github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/array.go (about) 1 package goja 2 3 import ( 4 "fmt" 5 "math" 6 "math/bits" 7 "reflect" 8 "strconv" 9 10 "github.com/nuvolaris/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) expand(idx uint32) bool { 336 targetLen := idx + 1 337 if targetLen > uint32(len(a.values)) { 338 if targetLen < uint32(cap(a.values)) { 339 a.values = a.values[:targetLen] 340 } else { 341 if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) { 342 //log.Println("Switching standard->sparse") 343 sa := &sparseArrayObject{ 344 baseObject: a.baseObject, 345 length: a.length, 346 propValueCount: a.propValueCount, 347 } 348 sa.setValues(a.values, a.objCount+1) 349 sa.val.self = sa 350 sa.lengthProp.writable = a.lengthProp.writable 351 sa._put("length", &sa.lengthProp) 352 return false 353 } else { 354 if bits.UintSize == 32 { 355 if targetLen >= math.MaxInt32 { 356 panic(a.val.runtime.NewTypeError("Array index overflows int")) 357 } 358 } 359 tl := int(targetLen) 360 newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values))) 361 copy(newValues, a.values) 362 a.values = newValues 363 } 364 } 365 } 366 return true 367 } 368 369 func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(uint32, bool) bool, throw bool) bool { 370 var newLen uint32 371 ret := true 372 if descr.Value != nil { 373 newLen = r.toLengthUint32(descr.Value) 374 } 375 376 if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil { 377 ret = false 378 goto Reject 379 } 380 381 if descr.Value != nil { 382 oldLen := uint32(prop.value.ToInteger()) 383 if oldLen != newLen { 384 ret = setter(newLen, false) 385 } 386 } else { 387 ret = true 388 } 389 390 if descr.Writable != FLAG_NOT_SET { 391 w := descr.Writable.Bool() 392 if prop.writable { 393 prop.writable = w 394 } else { 395 if w { 396 ret = false 397 goto Reject 398 } 399 } 400 } 401 402 Reject: 403 if !ret { 404 r.typeErrorResult(throw, "Cannot redefine property: length") 405 } 406 407 return ret 408 } 409 410 func (a *arrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool { 411 var existing Value 412 if idx < uint32(len(a.values)) { 413 existing = a.values[idx] 414 } 415 prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw) 416 if ok { 417 if idx >= a.length { 418 if !a.setLengthInt(idx+1, throw) { 419 return false 420 } 421 } 422 if a.expand(idx) { 423 a.values[idx] = prop 424 a.objCount++ 425 if _, ok := prop.(*valueProperty); ok { 426 a.propValueCount++ 427 } 428 } else { 429 a.val.self.(*sparseArrayObject).add(idx, prop) 430 } 431 } 432 return ok 433 } 434 435 func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool { 436 if idx := strToArrayIdx(name); idx != math.MaxUint32 { 437 return a._defineIdxProperty(idx, descr, throw) 438 } 439 if name == "length" { 440 return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw) 441 } 442 return a.baseObject.defineOwnPropertyStr(name, descr, throw) 443 } 444 445 func (a *arrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool { 446 if idx := toIdx(idx); idx != math.MaxUint32 { 447 return a._defineIdxProperty(idx, descr, throw) 448 } 449 return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw) 450 } 451 452 func (a *arrayObject) _deleteIdxProp(idx uint32, throw bool) bool { 453 if idx < uint32(len(a.values)) { 454 if v := a.values[idx]; v != nil { 455 if p, ok := v.(*valueProperty); ok { 456 if !p.configurable { 457 a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString()) 458 return false 459 } 460 a.propValueCount-- 461 } 462 a.values[idx] = nil 463 a.objCount-- 464 } 465 } 466 return true 467 } 468 469 func (a *arrayObject) deleteStr(name unistring.String, throw bool) bool { 470 if idx := strToArrayIdx(name); idx != math.MaxUint32 { 471 return a._deleteIdxProp(idx, throw) 472 } 473 return a.baseObject.deleteStr(name, throw) 474 } 475 476 func (a *arrayObject) deleteIdx(idx valueInt, throw bool) bool { 477 if idx := toIdx(idx); idx != math.MaxUint32 { 478 return a._deleteIdxProp(idx, throw) 479 } 480 return a.baseObject.deleteStr(idx.string(), throw) 481 } 482 483 func (a *arrayObject) export(ctx *objectExportCtx) interface{} { 484 if v, exists := ctx.get(a.val); exists { 485 return v 486 } 487 arr := make([]interface{}, a.length) 488 ctx.put(a.val, arr) 489 if a.propValueCount == 0 && a.length == uint32(len(a.values)) && uint32(a.objCount) == a.length { 490 for i, v := range a.values { 491 if v != nil { 492 arr[i] = exportValue(v, ctx) 493 } 494 } 495 } else { 496 for i := uint32(0); i < a.length; i++ { 497 v := a.getIdx(valueInt(i), nil) 498 if v != nil { 499 arr[i] = exportValue(v, ctx) 500 } 501 } 502 } 503 return arr 504 } 505 506 func (a *arrayObject) exportType() reflect.Type { 507 return reflectTypeArray 508 } 509 510 func (a *arrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error { 511 r := a.val.runtime 512 if iter := a.getSym(SymIterator, nil); iter == r.global.arrayValues || iter == nil { 513 l := toIntStrict(int64(a.length)) 514 if typ.Kind() == reflect.Array { 515 if dst.Len() != l { 516 return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len()) 517 } 518 } else { 519 dst.Set(reflect.MakeSlice(typ, l, l)) 520 } 521 ctx.putTyped(a.val, typ, dst.Interface()) 522 for i := 0; i < l; i++ { 523 if i >= len(a.values) { 524 break 525 } 526 val := a.values[i] 527 if p, ok := val.(*valueProperty); ok { 528 val = p.get(a.val) 529 } 530 err := r.toReflectValue(val, dst.Index(i), ctx) 531 if err != nil { 532 return fmt.Errorf("could not convert array element %v to %v at %d: %w", val, typ, i, err) 533 } 534 } 535 return nil 536 } 537 return a.baseObject.exportToArrayOrSlice(dst, typ, ctx) 538 } 539 540 func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) { 541 a.values = make([]Value, newMaxIdx+1) 542 for _, item := range items { 543 a.values[item.idx] = item.value 544 } 545 a.objCount = len(items) 546 } 547 548 func toIdx(v valueInt) uint32 { 549 if v >= 0 && v < math.MaxUint32 { 550 return uint32(v) 551 } 552 return math.MaxUint32 553 }