github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/array.go (about) 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 // Slow path 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 // we know it's foreign because prototype loops are not allowed 223 if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok { 224 return res 225 } 226 } 227 // new property 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 //log.Println("Switching standard->sparse") 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 }