array_sparse.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. package goja
  2. import (
  3. "math"
  4. "math/bits"
  5. "reflect"
  6. "sort"
  7. "strconv"
  8. "github.com/dop251/goja/unistring"
  9. )
  10. type sparseArrayItem struct {
  11. idx uint32
  12. value Value
  13. }
  14. type sparseArrayObject struct {
  15. baseObject
  16. items []sparseArrayItem
  17. length uint32
  18. propValueCount int
  19. lengthProp valueProperty
  20. }
  21. func (a *sparseArrayObject) findIdx(idx uint32) int {
  22. return sort.Search(len(a.items), func(i int) bool {
  23. return a.items[i].idx >= idx
  24. })
  25. }
  26. func (a *sparseArrayObject) _setLengthInt(l uint32, throw bool) bool {
  27. ret := true
  28. if l <= a.length {
  29. if a.propValueCount > 0 {
  30. // Slow path
  31. for i := len(a.items) - 1; i >= 0; i-- {
  32. item := a.items[i]
  33. if item.idx <= l {
  34. break
  35. }
  36. if prop, ok := item.value.(*valueProperty); ok {
  37. if !prop.configurable {
  38. l = item.idx + 1
  39. ret = false
  40. break
  41. }
  42. a.propValueCount--
  43. }
  44. }
  45. }
  46. }
  47. idx := a.findIdx(l)
  48. aa := a.items[idx:]
  49. for i := range aa {
  50. aa[i].value = nil
  51. }
  52. a.items = a.items[:idx]
  53. a.length = l
  54. if !ret {
  55. a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
  56. }
  57. return ret
  58. }
  59. func (a *sparseArrayObject) setLengthInt(l uint32, throw bool) bool {
  60. if l == a.length {
  61. return true
  62. }
  63. if !a.lengthProp.writable {
  64. a.val.runtime.typeErrorResult(throw, "length is not writable")
  65. return false
  66. }
  67. return a._setLengthInt(l, throw)
  68. }
  69. func (a *sparseArrayObject) setLength(v uint32, throw bool) bool {
  70. if v == a.length {
  71. return true
  72. }
  73. if !a.lengthProp.writable {
  74. a.val.runtime.typeErrorResult(throw, "length is not writable")
  75. return false
  76. }
  77. return a._setLengthInt(v, throw)
  78. }
  79. func (a *sparseArrayObject) _getIdx(idx uint32) Value {
  80. i := a.findIdx(idx)
  81. if i < len(a.items) && a.items[i].idx == idx {
  82. return a.items[i].value
  83. }
  84. return nil
  85. }
  86. func (a *sparseArrayObject) getStr(name unistring.String, receiver Value) Value {
  87. return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
  88. }
  89. func (a *sparseArrayObject) getIdx(idx valueInt, receiver Value) Value {
  90. prop := a.getOwnPropIdx(idx)
  91. if prop == nil {
  92. if a.prototype != nil {
  93. if receiver == nil {
  94. return a.prototype.self.getIdx(idx, a.val)
  95. }
  96. return a.prototype.self.getIdx(idx, receiver)
  97. }
  98. }
  99. if prop, ok := prop.(*valueProperty); ok {
  100. if receiver == nil {
  101. return prop.get(a.val)
  102. }
  103. return prop.get(receiver)
  104. }
  105. return prop
  106. }
  107. func (a *sparseArrayObject) getLengthProp() Value {
  108. a.lengthProp.value = intToValue(int64(a.length))
  109. return &a.lengthProp
  110. }
  111. func (a *sparseArrayObject) getOwnPropStr(name unistring.String) Value {
  112. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  113. return a._getIdx(idx)
  114. }
  115. if name == "length" {
  116. return a.getLengthProp()
  117. }
  118. return a.baseObject.getOwnPropStr(name)
  119. }
  120. func (a *sparseArrayObject) getOwnPropIdx(idx valueInt) Value {
  121. if idx := toIdx(idx); idx != math.MaxUint32 {
  122. return a._getIdx(idx)
  123. }
  124. return a.baseObject.getOwnPropStr(idx.string())
  125. }
  126. func (a *sparseArrayObject) add(idx uint32, val Value) {
  127. i := a.findIdx(idx)
  128. a.items = append(a.items, sparseArrayItem{})
  129. copy(a.items[i+1:], a.items[i:])
  130. a.items[i] = sparseArrayItem{
  131. idx: idx,
  132. value: val,
  133. }
  134. }
  135. func (a *sparseArrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
  136. var prop Value
  137. i := a.findIdx(idx)
  138. if i < len(a.items) && a.items[i].idx == idx {
  139. prop = a.items[i].value
  140. }
  141. if prop == nil {
  142. if proto := a.prototype; proto != nil {
  143. // we know it's foreign because prototype loops are not allowed
  144. if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
  145. return res
  146. }
  147. }
  148. // new property
  149. if !a.extensible {
  150. a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
  151. return false
  152. }
  153. if idx >= a.length {
  154. if !a.setLengthInt(idx+1, throw) {
  155. return false
  156. }
  157. }
  158. if a.expand(idx) {
  159. a.items = append(a.items, sparseArrayItem{})
  160. copy(a.items[i+1:], a.items[i:])
  161. a.items[i] = sparseArrayItem{
  162. idx: idx,
  163. value: val,
  164. }
  165. } else {
  166. ar := a.val.self.(*arrayObject)
  167. ar.values[idx] = val
  168. ar.objCount++
  169. return true
  170. }
  171. } else {
  172. if prop, ok := prop.(*valueProperty); ok {
  173. if !prop.isWritable() {
  174. a.val.runtime.typeErrorResult(throw)
  175. return false
  176. }
  177. prop.set(a.val, val)
  178. } else {
  179. a.items[i].value = val
  180. }
  181. }
  182. return true
  183. }
  184. func (a *sparseArrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
  185. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  186. return a._setOwnIdx(idx, val, throw)
  187. } else {
  188. if name == "length" {
  189. return a.setLength(a.val.runtime.toLengthUint32(val), throw)
  190. } else {
  191. return a.baseObject.setOwnStr(name, val, throw)
  192. }
  193. }
  194. }
  195. func (a *sparseArrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
  196. if idx := toIdx(idx); idx != math.MaxUint32 {
  197. return a._setOwnIdx(idx, val, throw)
  198. }
  199. return a.baseObject.setOwnStr(idx.string(), val, throw)
  200. }
  201. func (a *sparseArrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  202. return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
  203. }
  204. func (a *sparseArrayObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) {
  205. return a._setForeignIdx(name, a.getOwnPropIdx(name), val, receiver, throw)
  206. }
  207. type sparseArrayPropIter struct {
  208. a *sparseArrayObject
  209. idx int
  210. }
  211. func (i *sparseArrayPropIter) next() (propIterItem, iterNextFunc) {
  212. for i.idx < len(i.a.items) {
  213. name := asciiString(strconv.Itoa(int(i.a.items[i.idx].idx)))
  214. prop := i.a.items[i.idx].value
  215. i.idx++
  216. if prop != nil {
  217. return propIterItem{name: name, value: prop}, i.next
  218. }
  219. }
  220. return i.a.baseObject.iterateStringKeys()()
  221. }
  222. func (a *sparseArrayObject) iterateStringKeys() iterNextFunc {
  223. return (&sparseArrayPropIter{
  224. a: a,
  225. }).next
  226. }
  227. func (a *sparseArrayObject) stringKeys(all bool, accum []Value) []Value {
  228. if all {
  229. for _, item := range a.items {
  230. accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
  231. }
  232. } else {
  233. for _, item := range a.items {
  234. if prop, ok := item.value.(*valueProperty); ok && !prop.enumerable {
  235. continue
  236. }
  237. accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
  238. }
  239. }
  240. return a.baseObject.stringKeys(all, accum)
  241. }
  242. func (a *sparseArrayObject) setValues(values []Value, objCount int) {
  243. a.items = make([]sparseArrayItem, 0, objCount)
  244. for i, val := range values {
  245. if val != nil {
  246. a.items = append(a.items, sparseArrayItem{
  247. idx: uint32(i),
  248. value: val,
  249. })
  250. }
  251. }
  252. }
  253. func (a *sparseArrayObject) hasOwnPropertyStr(name unistring.String) bool {
  254. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  255. i := a.findIdx(idx)
  256. return i < len(a.items) && a.items[i].idx == idx
  257. } else {
  258. return a.baseObject.hasOwnPropertyStr(name)
  259. }
  260. }
  261. func (a *sparseArrayObject) hasOwnPropertyIdx(idx valueInt) bool {
  262. if idx := toIdx(idx); idx != math.MaxUint32 {
  263. i := a.findIdx(idx)
  264. return i < len(a.items) && a.items[i].idx == idx
  265. }
  266. return a.baseObject.hasOwnPropertyStr(idx.string())
  267. }
  268. func (a *sparseArrayObject) expand(idx uint32) bool {
  269. if l := len(a.items); l >= 1024 {
  270. if ii := a.items[l-1].idx; ii > idx {
  271. idx = ii
  272. }
  273. if (bits.UintSize == 64 || idx < math.MaxInt32) && int(idx)>>3 < l {
  274. //log.Println("Switching sparse->standard")
  275. ar := &arrayObject{
  276. baseObject: a.baseObject,
  277. length: a.length,
  278. propValueCount: a.propValueCount,
  279. }
  280. ar.setValuesFromSparse(a.items, int(idx))
  281. ar.val.self = ar
  282. ar.lengthProp.writable = a.lengthProp.writable
  283. a._put("length", &ar.lengthProp)
  284. return false
  285. }
  286. }
  287. return true
  288. }
  289. func (a *sparseArrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
  290. var existing Value
  291. i := a.findIdx(idx)
  292. if i < len(a.items) && a.items[i].idx == idx {
  293. existing = a.items[i].value
  294. }
  295. prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
  296. if ok {
  297. if idx >= a.length {
  298. if !a.setLengthInt(idx+1, throw) {
  299. return false
  300. }
  301. }
  302. if i >= len(a.items) || a.items[i].idx != idx {
  303. if a.expand(idx) {
  304. a.items = append(a.items, sparseArrayItem{})
  305. copy(a.items[i+1:], a.items[i:])
  306. a.items[i] = sparseArrayItem{
  307. idx: idx,
  308. value: prop,
  309. }
  310. if idx >= a.length {
  311. a.length = idx + 1
  312. }
  313. } else {
  314. a.val.self.(*arrayObject).values[idx] = prop
  315. }
  316. } else {
  317. a.items[i].value = prop
  318. }
  319. if _, ok := prop.(*valueProperty); ok {
  320. a.propValueCount++
  321. }
  322. }
  323. return ok
  324. }
  325. func (a *sparseArrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  326. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  327. return a._defineIdxProperty(idx, descr, throw)
  328. }
  329. if name == "length" {
  330. return a.val.runtime.defineArrayLength(&a.lengthProp, descr, a.setLength, throw)
  331. }
  332. return a.baseObject.defineOwnPropertyStr(name, descr, throw)
  333. }
  334. func (a *sparseArrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
  335. if idx := toIdx(idx); idx != math.MaxUint32 {
  336. return a._defineIdxProperty(idx, descr, throw)
  337. }
  338. return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
  339. }
  340. func (a *sparseArrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
  341. i := a.findIdx(idx)
  342. if i < len(a.items) && a.items[i].idx == idx {
  343. if p, ok := a.items[i].value.(*valueProperty); ok {
  344. if !p.configurable {
  345. a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
  346. return false
  347. }
  348. a.propValueCount--
  349. }
  350. copy(a.items[i:], a.items[i+1:])
  351. a.items[len(a.items)-1].value = nil
  352. a.items = a.items[:len(a.items)-1]
  353. }
  354. return true
  355. }
  356. func (a *sparseArrayObject) deleteStr(name unistring.String, throw bool) bool {
  357. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  358. return a._deleteIdxProp(idx, throw)
  359. }
  360. return a.baseObject.deleteStr(name, throw)
  361. }
  362. func (a *sparseArrayObject) deleteIdx(idx valueInt, throw bool) bool {
  363. if idx := toIdx(idx); idx != math.MaxUint32 {
  364. return a._deleteIdxProp(idx, throw)
  365. }
  366. return a.baseObject.deleteStr(idx.string(), throw)
  367. }
  368. func (a *sparseArrayObject) sortLen() int64 {
  369. if len(a.items) > 0 {
  370. return int64(a.items[len(a.items)-1].idx) + 1
  371. }
  372. return 0
  373. }
  374. func (a *sparseArrayObject) export(ctx *objectExportCtx) interface{} {
  375. if v, exists := ctx.get(a); exists {
  376. return v
  377. }
  378. arr := make([]interface{}, a.length)
  379. ctx.put(a, arr)
  380. var prevIdx uint32
  381. for _, item := range a.items {
  382. idx := item.idx
  383. for i := prevIdx; i < idx; i++ {
  384. if a.prototype != nil {
  385. if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
  386. arr[i] = exportValue(v, ctx)
  387. }
  388. }
  389. }
  390. v := item.value
  391. if v != nil {
  392. if prop, ok := v.(*valueProperty); ok {
  393. v = prop.get(a.val)
  394. }
  395. arr[idx] = exportValue(v, ctx)
  396. }
  397. prevIdx = idx + 1
  398. }
  399. for i := prevIdx; i < a.length; i++ {
  400. if a.prototype != nil {
  401. if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
  402. arr[i] = exportValue(v, ctx)
  403. }
  404. }
  405. }
  406. return arr
  407. }
  408. func (a *sparseArrayObject) exportType() reflect.Type {
  409. return reflectTypeArray
  410. }