array_sparse.go 11 KB

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