1package goja 2 3import ( 4 "math" 5 "math/bits" 6 "reflect" 7 "strconv" 8 9 "github.com/dop251/goja/unistring" 10) 11 12type arrayIterObject struct { 13 baseObject 14 obj *Object 15 nextIdx int64 16 kind iterationKind 17} 18 19func (ai *arrayIterObject) next() Value { 20 if ai.obj == nil { 21 return ai.val.runtime.createIterResultObject(_undefined, true) 22 } 23 l := toLength(ai.obj.self.getStr("length", nil)) 24 index := ai.nextIdx 25 if index >= l { 26 ai.obj = nil 27 return ai.val.runtime.createIterResultObject(_undefined, true) 28 } 29 ai.nextIdx++ 30 idxVal := valueInt(index) 31 if ai.kind == iterationKindKey { 32 return ai.val.runtime.createIterResultObject(idxVal, false) 33 } 34 elementValue := nilSafe(ai.obj.self.getIdx(idxVal, nil)) 35 var result Value 36 if ai.kind == iterationKindValue { 37 result = elementValue 38 } else { 39 result = ai.val.runtime.newArrayValues([]Value{idxVal, elementValue}) 40 } 41 return ai.val.runtime.createIterResultObject(result, false) 42} 43 44func (r *Runtime) createArrayIterator(iterObj *Object, kind iterationKind) Value { 45 o := &Object{runtime: r} 46 47 ai := &arrayIterObject{ 48 obj: iterObj, 49 kind: kind, 50 } 51 ai.class = classArrayIterator 52 ai.val = o 53 ai.extensible = true 54 o.self = ai 55 ai.prototype = r.global.ArrayIteratorPrototype 56 ai.init() 57 58 return o 59} 60 61type arrayObject struct { 62 baseObject 63 values []Value 64 length uint32 65 objCount int 66 propValueCount int 67 lengthProp valueProperty 68} 69 70func (a *arrayObject) init() { 71 a.baseObject.init() 72 a.lengthProp.writable = true 73 74 a._put("length", &a.lengthProp) 75} 76 77func (a *arrayObject) _setLengthInt(l int64, throw bool) bool { 78 if l >= 0 && l <= math.MaxUint32 { 79 l := uint32(l) 80 ret := true 81 if l <= a.length { 82 if a.propValueCount > 0 { 83 // Slow path 84 for i := len(a.values) - 1; i >= int(l); i-- { 85 if prop, ok := a.values[i].(*valueProperty); ok { 86 if !prop.configurable { 87 l = uint32(i) + 1 88 ret = false 89 break 90 } 91 a.propValueCount-- 92 } 93 } 94 } 95 } 96 if l <= uint32(len(a.values)) { 97 if l >= 16 && l < uint32(cap(a.values))>>2 { 98 ar := make([]Value, l) 99 copy(ar, a.values) 100 a.values = ar 101 } else { 102 ar := a.values[l:len(a.values)] 103 for i := range ar { 104 ar[i] = nil 105 } 106 a.values = a.values[:l] 107 } 108 } 109 a.length = l 110 if !ret { 111 a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length") 112 } 113 return ret 114 } 115 panic(a.val.runtime.newError(a.val.runtime.global.RangeError, "Invalid array length")) 116} 117 118func (a *arrayObject) setLengthInt(l int64, throw bool) bool { 119 if l == int64(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 129func (a *arrayObject) setLength(v Value, throw bool) bool { 130 l, ok := toIntIgnoreNegZero(v) 131 if ok && l == int64(a.length) { 132 return true 133 } 134 if !a.lengthProp.writable { 135 a.val.runtime.typeErrorResult(throw, "length is not writable") 136 return false 137 } 138 if ok { 139 return a._setLengthInt(l, throw) 140 } 141 panic(a.val.runtime.newError(a.val.runtime.global.RangeError, "Invalid array length")) 142} 143 144func (a *arrayObject) getIdx(idx valueInt, receiver Value) Value { 145 prop := a.getOwnPropIdx(idx) 146 if prop == nil { 147 if a.prototype != nil { 148 if receiver == nil { 149 return a.prototype.self.getIdx(idx, a.val) 150 } 151 return a.prototype.self.getIdx(idx, receiver) 152 } 153 } 154 if prop, ok := prop.(*valueProperty); ok { 155 if receiver == nil { 156 return prop.get(a.val) 157 } 158 return prop.get(receiver) 159 } 160 return prop 161} 162 163func (a *arrayObject) getOwnPropStr(name unistring.String) Value { 164 if len(a.values) > 0 { 165 if i := strToArrayIdx(name); i != math.MaxUint32 { 166 if i < uint32(len(a.values)) { 167 return a.values[i] 168 } 169 } 170 } 171 if name == "length" { 172 return a.getLengthProp() 173 } 174 return a.baseObject.getOwnPropStr(name) 175} 176 177func (a *arrayObject) getOwnPropIdx(idx valueInt) Value { 178 if i := toIdx(idx); i != math.MaxUint32 { 179 if i < uint32(len(a.values)) { 180 return a.values[i] 181 } 182 return nil 183 } 184 185 return a.baseObject.getOwnPropStr(idx.string()) 186} 187 188func (a *arrayObject) sortLen() int64 { 189 return int64(len(a.values)) 190} 191 192func (a *arrayObject) sortGet(i int64) Value { 193 v := a.values[i] 194 if p, ok := v.(*valueProperty); ok { 195 v = p.get(a.val) 196 } 197 return v 198} 199 200func (a *arrayObject) swap(i, j int64) { 201 a.values[i], a.values[j] = a.values[j], a.values[i] 202} 203 204func (a *arrayObject) getStr(name unistring.String, receiver Value) Value { 205 return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver) 206} 207 208func (a *arrayObject) getLengthProp() Value { 209 a.lengthProp.value = intToValue(int64(a.length)) 210 return &a.lengthProp 211} 212 213func (a *arrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool { 214 if i := toIdx(idx); i != math.MaxUint32 { 215 return a._setOwnIdx(i, val, throw) 216 } else { 217 return a.baseObject.setOwnStr(idx.string(), val, throw) 218 } 219} 220 221func (a *arrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool { 222 var prop Value 223 if idx < uint32(len(a.values)) { 224 prop = a.values[idx] 225 } 226 227 if prop == nil { 228 if proto := a.prototype; proto != nil { 229 // we know it's foreign because prototype loops are not allowed 230 if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok { 231 return res 232 } 233 } 234 // new property 235 if !a.extensible { 236 a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx) 237 return false 238 } else { 239 if idx >= a.length { 240 if !a.setLengthInt(int64(idx)+1, throw) { 241 return false 242 } 243 } 244 if idx >= uint32(len(a.values)) { 245 if !a.expand(idx) { 246 a.val.self.(*sparseArrayObject).add(idx, val) 247 return true 248 } 249 } 250 a.objCount++ 251 } 252 } else { 253 if prop, ok := prop.(*valueProperty); ok { 254 if !prop.isWritable() { 255 a.val.runtime.typeErrorResult(throw) 256 return false 257 } 258 prop.set(a.val, val) 259 return true 260 } 261 } 262 a.values[idx] = val 263 return true 264} 265 266func (a *arrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool { 267 if idx := strToArrayIdx(name); idx != math.MaxUint32 { 268 return a._setOwnIdx(idx, val, throw) 269 } else { 270 if name == "length" { 271 return a.setLength(val, throw) 272 } else { 273 return a.baseObject.setOwnStr(name, val, throw) 274 } 275 } 276} 277 278func (a *arrayObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) { 279 return a._setForeignIdx(idx, a.getOwnPropIdx(idx), val, receiver, throw) 280} 281 282func (a *arrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 283 return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw) 284} 285 286type arrayPropIter struct { 287 a *arrayObject 288 limit int 289 idx int 290} 291 292func (i *arrayPropIter) next() (propIterItem, iterNextFunc) { 293 for i.idx < len(i.a.values) && i.idx < i.limit { 294 name := unistring.String(strconv.Itoa(i.idx)) 295 prop := i.a.values[i.idx] 296 i.idx++ 297 if prop != nil { 298 return propIterItem{name: name, value: prop}, i.next 299 } 300 } 301 302 return i.a.baseObject.enumerateOwnKeys()() 303} 304 305func (a *arrayObject) enumerateOwnKeys() iterNextFunc { 306 return (&arrayPropIter{ 307 a: a, 308 limit: len(a.values), 309 }).next 310} 311 312func (a *arrayObject) ownKeys(all bool, accum []Value) []Value { 313 for i, prop := range a.values { 314 name := strconv.Itoa(i) 315 if prop != nil { 316 if !all { 317 if prop, ok := prop.(*valueProperty); ok && !prop.enumerable { 318 continue 319 } 320 } 321 accum = append(accum, asciiString(name)) 322 } 323 } 324 return a.baseObject.ownKeys(all, accum) 325} 326 327func (a *arrayObject) hasOwnPropertyStr(name unistring.String) bool { 328 if idx := strToArrayIdx(name); idx != math.MaxUint32 { 329 return idx < uint32(len(a.values)) && a.values[idx] != nil 330 } else { 331 return a.baseObject.hasOwnPropertyStr(name) 332 } 333} 334 335func (a *arrayObject) hasOwnPropertyIdx(idx valueInt) bool { 336 if idx := toIdx(idx); idx != math.MaxUint32 { 337 return idx < uint32(len(a.values)) && a.values[idx] != nil 338 } 339 return a.baseObject.hasOwnPropertyStr(idx.string()) 340} 341 342func (a *arrayObject) expand(idx uint32) bool { 343 targetLen := idx + 1 344 if targetLen > uint32(len(a.values)) { 345 if targetLen < uint32(cap(a.values)) { 346 a.values = a.values[:targetLen] 347 } else { 348 if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) { 349 //log.Println("Switching standard->sparse") 350 sa := &sparseArrayObject{ 351 baseObject: a.baseObject, 352 length: a.length, 353 propValueCount: a.propValueCount, 354 } 355 sa.setValues(a.values, a.objCount+1) 356 sa.val.self = sa 357 sa.lengthProp.writable = a.lengthProp.writable 358 sa._put("length", &sa.lengthProp) 359 return false 360 } else { 361 if bits.UintSize == 32 { 362 if targetLen >= math.MaxInt32 { 363 panic(a.val.runtime.NewTypeError("Array index overflows int")) 364 } 365 } 366 tl := int(targetLen) 367 newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values))) 368 copy(newValues, a.values) 369 a.values = newValues 370 } 371 } 372 } 373 return true 374} 375 376func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(Value, bool) bool, throw bool) bool { 377 ret := true 378 379 if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil { 380 ret = false 381 goto Reject 382 } 383 384 if newLen := descr.Value; newLen != nil { 385 ret = setter(newLen, false) 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 402Reject: 403 if !ret { 404 r.typeErrorResult(throw, "Cannot redefine property: length") 405 } 406 407 return ret 408} 409 410func (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(int64(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 435func (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.lengthProp, descr, a.setLength, throw) 441 } 442 return a.baseObject.defineOwnPropertyStr(name, descr, throw) 443} 444 445func (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 452func (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 469func (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 476func (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 483func (a *arrayObject) export(ctx *objectExportCtx) interface{} { 484 if v, exists := ctx.get(a); exists { 485 return v 486 } 487 arr := make([]interface{}, a.length) 488 ctx.put(a, 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 506func (a *arrayObject) exportType() reflect.Type { 507 return reflectTypeArray 508} 509 510func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) { 511 a.values = make([]Value, newMaxIdx+1) 512 for _, item := range items { 513 a.values[item.idx] = item.value 514 } 515 a.objCount = len(items) 516} 517 518func toIdx(v valueInt) uint32 { 519 if v >= 0 && v < math.MaxUint32 { 520 return uint32(v) 521 } 522 return math.MaxUint32 523} 524