1 package goja
2
3 import (
4 "fmt"
5 "math"
6 "math/bits"
7 "reflect"
8 "strconv"
9
10 "github.com/dop251/goja/unistring"
11 )
12
13 type arrayIterObject struct {
14 baseObject
15 obj *Object
16 nextIdx int64
17 kind iterationKind
18 }
19
20 func (ai *arrayIterObject) next() Value {
21 if ai.obj == nil {
22 return ai.val.runtime.createIterResultObject(_undefined, true)
23 }
24 if ta, ok := ai.obj.self.(*typedArrayObject); ok {
25 ta.viewedArrayBuf.ensureNotDetached(true)
26 }
27 l := toLength(ai.obj.self.getStr("length", nil))
28 index := ai.nextIdx
29 if index >= l {
30 ai.obj = nil
31 return ai.val.runtime.createIterResultObject(_undefined, true)
32 }
33 ai.nextIdx++
34 idxVal := valueInt(index)
35 if ai.kind == iterationKindKey {
36 return ai.val.runtime.createIterResultObject(idxVal, false)
37 }
38 elementValue := nilSafe(ai.obj.self.getIdx(idxVal, nil))
39 var result Value
40 if ai.kind == iterationKindValue {
41 result = elementValue
42 } else {
43 result = ai.val.runtime.newArrayValues([]Value{idxVal, elementValue})
44 }
45 return ai.val.runtime.createIterResultObject(result, false)
46 }
47
48 func (r *Runtime) createArrayIterator(iterObj *Object, kind iterationKind) Value {
49 o := &Object{runtime: r}
50
51 ai := &arrayIterObject{
52 obj: iterObj,
53 kind: kind,
54 }
55 ai.class = classObject
56 ai.val = o
57 ai.extensible = true
58 o.self = ai
59 ai.prototype = r.getArrayIteratorPrototype()
60 ai.init()
61
62 return o
63 }
64
65 type arrayObject struct {
66 baseObject
67 values []Value
68 length uint32
69 objCount int
70 propValueCount int
71 lengthProp valueProperty
72 }
73
74 func (a *arrayObject) init() {
75 a.baseObject.init()
76 a.lengthProp.writable = true
77
78 a._put("length", &a.lengthProp)
79 }
80
81 func (a *arrayObject) _setLengthInt(l uint32, throw bool) bool {
82 ret := true
83 if l <= a.length {
84 if a.propValueCount > 0 {
85
86 for i := len(a.values) - 1; i >= int(l); i-- {
87 if prop, ok := a.values[i].(*valueProperty); ok {
88 if !prop.configurable {
89 l = uint32(i) + 1
90 ret = false
91 break
92 }
93 a.propValueCount--
94 }
95 }
96 }
97 }
98 if l <= uint32(len(a.values)) {
99 if l >= 16 && l < uint32(cap(a.values))>>2 {
100 ar := make([]Value, l)
101 copy(ar, a.values)
102 a.values = ar
103 } else {
104 ar := a.values[l:len(a.values)]
105 for i := range ar {
106 ar[i] = nil
107 }
108 a.values = a.values[:l]
109 }
110 }
111 a.length = l
112 if !ret {
113 a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
114 }
115 return ret
116 }
117
118 func (a *arrayObject) setLengthInt(l uint32, throw bool) bool {
119 if l == a.length {
120 return true
121 }
122 if !a.lengthProp.writable {
123 a.val.runtime.typeErrorResult(throw, "length is not writable")
124 return false
125 }
126 return a._setLengthInt(l, throw)
127 }
128
129 func (a *arrayObject) setLength(v uint32, throw bool) bool {
130 if !a.lengthProp.writable {
131 a.val.runtime.typeErrorResult(throw, "length is not writable")
132 return false
133 }
134 return a._setLengthInt(v, throw)
135 }
136
137 func (a *arrayObject) getIdx(idx valueInt, receiver Value) Value {
138 prop := a.getOwnPropIdx(idx)
139 if prop == nil {
140 if a.prototype != nil {
141 if receiver == nil {
142 return a.prototype.self.getIdx(idx, a.val)
143 }
144 return a.prototype.self.getIdx(idx, receiver)
145 }
146 }
147 if prop, ok := prop.(*valueProperty); ok {
148 if receiver == nil {
149 return prop.get(a.val)
150 }
151 return prop.get(receiver)
152 }
153 return prop
154 }
155
156 func (a *arrayObject) getOwnPropStr(name unistring.String) Value {
157 if len(a.values) > 0 {
158 if i := strToArrayIdx(name); i != math.MaxUint32 {
159 if i < uint32(len(a.values)) {
160 return a.values[i]
161 }
162 }
163 }
164 if name == "length" {
165 return a.getLengthProp()
166 }
167 return a.baseObject.getOwnPropStr(name)
168 }
169
170 func (a *arrayObject) getOwnPropIdx(idx valueInt) Value {
171 if i := toIdx(idx); i != math.MaxUint32 {
172 if i < uint32(len(a.values)) {
173 return a.values[i]
174 }
175 return nil
176 }
177
178 return a.baseObject.getOwnPropStr(idx.string())
179 }
180
181 func (a *arrayObject) sortLen() int {
182 return len(a.values)
183 }
184
185 func (a *arrayObject) sortGet(i int) Value {
186 v := a.values[i]
187 if p, ok := v.(*valueProperty); ok {
188 v = p.get(a.val)
189 }
190 return v
191 }
192
193 func (a *arrayObject) swap(i int, j int) {
194 a.values[i], a.values[j] = a.values[j], a.values[i]
195 }
196
197 func (a *arrayObject) getStr(name unistring.String, receiver Value) Value {
198 return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
199 }
200
201 func (a *arrayObject) getLengthProp() *valueProperty {
202 a.lengthProp.value = intToValue(int64(a.length))
203 return &a.lengthProp
204 }
205
206 func (a *arrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
207 if i := toIdx(idx); i != math.MaxUint32 {
208 return a._setOwnIdx(i, val, throw)
209 } else {
210 return a.baseObject.setOwnStr(idx.string(), val, throw)
211 }
212 }
213
214 func (a *arrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
215 var prop Value
216 if idx < uint32(len(a.values)) {
217 prop = a.values[idx]
218 }
219
220 if prop == nil {
221 if proto := a.prototype; proto != nil {
222
223 if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
224 return res
225 }
226 }
227
228 if !a.extensible {
229 a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
230 return false
231 } else {
232 if idx >= a.length {
233 if !a.setLengthInt(idx+1, throw) {
234 return false
235 }
236 }
237 if idx >= uint32(len(a.values)) {
238 if !a.expand(idx) {
239 a.val.self.(*sparseArrayObject).add(idx, val)
240 return true
241 }
242 }
243 a.objCount++
244 }
245 } else {
246 if prop, ok := prop.(*valueProperty); ok {
247 if !prop.isWritable() {
248 a.val.runtime.typeErrorResult(throw)
249 return false
250 }
251 prop.set(a.val, val)
252 return true
253 }
254 }
255 a.values[idx] = val
256 return true
257 }
258
259 func (a *arrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
260 if idx := strToArrayIdx(name); idx != math.MaxUint32 {
261 return a._setOwnIdx(idx, val, throw)
262 } else {
263 if name == "length" {
264 return a.setLength(a.val.runtime.toLengthUint32(val), throw)
265 } else {
266 return a.baseObject.setOwnStr(name, val, throw)
267 }
268 }
269 }
270
271 func (a *arrayObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
272 return a._setForeignIdx(idx, a.getOwnPropIdx(idx), val, receiver, throw)
273 }
274
275 func (a *arrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
276 return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
277 }
278
279 type arrayPropIter struct {
280 a *arrayObject
281 limit int
282 idx int
283 }
284
285 func (i *arrayPropIter) next() (propIterItem, iterNextFunc) {
286 for i.idx < len(i.a.values) && i.idx < i.limit {
287 name := asciiString(strconv.Itoa(i.idx))
288 prop := i.a.values[i.idx]
289 i.idx++
290 if prop != nil {
291 return propIterItem{name: name, value: prop}, i.next
292 }
293 }
294
295 return i.a.baseObject.iterateStringKeys()()
296 }
297
298 func (a *arrayObject) iterateStringKeys() iterNextFunc {
299 return (&arrayPropIter{
300 a: a,
301 limit: len(a.values),
302 }).next
303 }
304
305 func (a *arrayObject) stringKeys(all bool, accum []Value) []Value {
306 for i, prop := range a.values {
307 name := strconv.Itoa(i)
308 if prop != nil {
309 if !all {
310 if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
311 continue
312 }
313 }
314 accum = append(accum, asciiString(name))
315 }
316 }
317 return a.baseObject.stringKeys(all, accum)
318 }
319
320 func (a *arrayObject) hasOwnPropertyStr(name unistring.String) bool {
321 if idx := strToArrayIdx(name); idx != math.MaxUint32 {
322 return idx < uint32(len(a.values)) && a.values[idx] != nil
323 } else {
324 return a.baseObject.hasOwnPropertyStr(name)
325 }
326 }
327
328 func (a *arrayObject) hasOwnPropertyIdx(idx valueInt) bool {
329 if idx := toIdx(idx); idx != math.MaxUint32 {
330 return idx < uint32(len(a.values)) && a.values[idx] != nil
331 }
332 return a.baseObject.hasOwnPropertyStr(idx.string())
333 }
334
335 func (a *arrayObject) hasPropertyIdx(idx valueInt) bool {
336 if a.hasOwnPropertyIdx(idx) {
337 return true
338 }
339
340 if a.prototype != nil {
341 return a.prototype.self.hasPropertyIdx(idx)
342 }
343
344 return false
345 }
346
347 func (a *arrayObject) expand(idx uint32) bool {
348 targetLen := idx + 1
349 if targetLen > uint32(len(a.values)) {
350 if targetLen < uint32(cap(a.values)) {
351 a.values = a.values[:targetLen]
352 } else {
353 if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) {
354
355 sa := &sparseArrayObject{
356 baseObject: a.baseObject,
357 length: a.length,
358 propValueCount: a.propValueCount,
359 }
360 sa.setValues(a.values, a.objCount+1)
361 sa.val.self = sa
362 sa.lengthProp.writable = a.lengthProp.writable
363 sa._put("length", &sa.lengthProp)
364 return false
365 } else {
366 if bits.UintSize == 32 {
367 if targetLen >= math.MaxInt32 {
368 panic(a.val.runtime.NewTypeError("Array index overflows int"))
369 }
370 }
371 tl := int(targetLen)
372 newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values)))
373 copy(newValues, a.values)
374 a.values = newValues
375 }
376 }
377 }
378 return true
379 }
380
381 func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(uint32, bool) bool, throw bool) bool {
382 var newLen uint32
383 ret := true
384 if descr.Value != nil {
385 newLen = r.toLengthUint32(descr.Value)
386 }
387
388 if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil {
389 ret = false
390 goto Reject
391 }
392
393 if descr.Value != nil {
394 oldLen := uint32(prop.value.ToInteger())
395 if oldLen != newLen {
396 ret = setter(newLen, false)
397 }
398 } else {
399 ret = true
400 }
401
402 if descr.Writable != FLAG_NOT_SET {
403 w := descr.Writable.Bool()
404 if prop.writable {
405 prop.writable = w
406 } else {
407 if w {
408 ret = false
409 goto Reject
410 }
411 }
412 }
413
414 Reject:
415 if !ret {
416 r.typeErrorResult(throw, "Cannot redefine property: length")
417 }
418
419 return ret
420 }
421
422 func (a *arrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
423 var existing Value
424 if idx < uint32(len(a.values)) {
425 existing = a.values[idx]
426 }
427 prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
428 if ok {
429 if idx >= a.length {
430 if !a.setLengthInt(idx+1, throw) {
431 return false
432 }
433 }
434 if a.expand(idx) {
435 a.values[idx] = prop
436 a.objCount++
437 if _, ok := prop.(*valueProperty); ok {
438 a.propValueCount++
439 }
440 } else {
441 a.val.self.(*sparseArrayObject).add(idx, prop)
442 }
443 }
444 return ok
445 }
446
447 func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
448 if idx := strToArrayIdx(name); idx != math.MaxUint32 {
449 return a._defineIdxProperty(idx, descr, throw)
450 }
451 if name == "length" {
452 return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
453 }
454 return a.baseObject.defineOwnPropertyStr(name, descr, throw)
455 }
456
457 func (a *arrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
458 if idx := toIdx(idx); idx != math.MaxUint32 {
459 return a._defineIdxProperty(idx, descr, throw)
460 }
461 return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
462 }
463
464 func (a *arrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
465 if idx < uint32(len(a.values)) {
466 if v := a.values[idx]; v != nil {
467 if p, ok := v.(*valueProperty); ok {
468 if !p.configurable {
469 a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
470 return false
471 }
472 a.propValueCount--
473 }
474 a.values[idx] = nil
475 a.objCount--
476 }
477 }
478 return true
479 }
480
481 func (a *arrayObject) deleteStr(name unistring.String, throw bool) bool {
482 if idx := strToArrayIdx(name); idx != math.MaxUint32 {
483 return a._deleteIdxProp(idx, throw)
484 }
485 return a.baseObject.deleteStr(name, throw)
486 }
487
488 func (a *arrayObject) deleteIdx(idx valueInt, throw bool) bool {
489 if idx := toIdx(idx); idx != math.MaxUint32 {
490 return a._deleteIdxProp(idx, throw)
491 }
492 return a.baseObject.deleteStr(idx.string(), throw)
493 }
494
495 func (a *arrayObject) export(ctx *objectExportCtx) interface{} {
496 if v, exists := ctx.get(a.val); exists {
497 return v
498 }
499 arr := make([]interface{}, a.length)
500 ctx.put(a.val, arr)
501 if a.propValueCount == 0 && a.length == uint32(len(a.values)) && uint32(a.objCount) == a.length {
502 for i, v := range a.values {
503 if v != nil {
504 arr[i] = exportValue(v, ctx)
505 }
506 }
507 } else {
508 for i := uint32(0); i < a.length; i++ {
509 v := a.getIdx(valueInt(i), nil)
510 if v != nil {
511 arr[i] = exportValue(v, ctx)
512 }
513 }
514 }
515 return arr
516 }
517
518 func (a *arrayObject) exportType() reflect.Type {
519 return reflectTypeArray
520 }
521
522 func (a *arrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
523 r := a.val.runtime
524 if iter := a.getSym(SymIterator, nil); iter == r.getArrayValues() || iter == nil {
525 l := toIntStrict(int64(a.length))
526 if typ.Kind() == reflect.Array {
527 if dst.Len() != l {
528 return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
529 }
530 } else {
531 dst.Set(reflect.MakeSlice(typ, l, l))
532 }
533 ctx.putTyped(a.val, typ, dst.Interface())
534 for i := 0; i < l; i++ {
535 if i >= len(a.values) {
536 break
537 }
538 val := a.values[i]
539 if p, ok := val.(*valueProperty); ok {
540 val = p.get(a.val)
541 }
542 err := r.toReflectValue(val, dst.Index(i), ctx)
543 if err != nil {
544 return fmt.Errorf("could not convert array element %v to %v at %d: %w", val, typ, i, err)
545 }
546 }
547 return nil
548 }
549 return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
550 }
551
552 func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) {
553 a.values = make([]Value, newMaxIdx+1)
554 for _, item := range items {
555 a.values[item.idx] = item.value
556 }
557 a.objCount = len(items)
558 }
559
560 func toIdx(v valueInt) uint32 {
561 if v >= 0 && v < math.MaxUint32 {
562 return uint32(v)
563 }
564 return math.MaxUint32
565 }
566
View as plain text