11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciextern enum IterationKind extends uint31 { kKeys, kValues, kEntries }
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciextern class JSArrayIterator extends JSObject {
81cb0ef41Sopenharmony_ci  iterated_object: JSReceiver;
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci  // [next_index]: The [[ArrayIteratorNextIndex]] inobject property.
111cb0ef41Sopenharmony_ci  // The next_index is always a positive integer, and it points to
121cb0ef41Sopenharmony_ci  // the next index that is to be returned by this iterator. It's
131cb0ef41Sopenharmony_ci  // possible range is fixed depending on the [[iterated_object]]:
141cb0ef41Sopenharmony_ci  //
151cb0ef41Sopenharmony_ci  //   1. For JSArray's the next_index is always in Unsigned32
161cb0ef41Sopenharmony_ci  //      range, and when the iterator reaches the end it's set
171cb0ef41Sopenharmony_ci  //      to kMaxUInt32 to indicate that this iterator should
181cb0ef41Sopenharmony_ci  //      never produce values anymore even if the "length"
191cb0ef41Sopenharmony_ci  //      property of the JSArray changes at some later point.
201cb0ef41Sopenharmony_ci  //   2. For JSTypedArray's the next_index is always in
211cb0ef41Sopenharmony_ci  //      UnsignedSmall range, and when the iterator terminates
221cb0ef41Sopenharmony_ci  //      it's set to Smi::kMaxValue.
231cb0ef41Sopenharmony_ci  //   3. For all other JSReceiver's it's always between 0 and
241cb0ef41Sopenharmony_ci  //      kMaxSafeInteger, and the latter value is used to mark
251cb0ef41Sopenharmony_ci  //      termination.
261cb0ef41Sopenharmony_ci  //
271cb0ef41Sopenharmony_ci  // It's important that for 1. and 2. the value fits into the
281cb0ef41Sopenharmony_ci  // Unsigned32 range (UnsignedSmall is a subset of Unsigned32),
291cb0ef41Sopenharmony_ci  // since we use this knowledge in the fast-path for the array
301cb0ef41Sopenharmony_ci  // iterator next calls in TurboFan (in the JSCallReducer) to
311cb0ef41Sopenharmony_ci  // keep the index in Word32 representation. This invariant is
321cb0ef41Sopenharmony_ci  // checked in JSArrayIterator::JSArrayIteratorVerify().
331cb0ef41Sopenharmony_ci  next_index: Number;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  kind: SmiTagged<IterationKind>;
361cb0ef41Sopenharmony_ci}
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci// Perform CreateArrayIterator (ES #sec-createarrayiterator).
391cb0ef41Sopenharmony_ci@export
401cb0ef41Sopenharmony_cimacro CreateArrayIterator(implicit context: NativeContext)(
411cb0ef41Sopenharmony_ci    array: JSReceiver, kind: constexpr IterationKind): JSArrayIterator {
421cb0ef41Sopenharmony_ci  return new JSArrayIterator{
431cb0ef41Sopenharmony_ci    map: *NativeContextSlot(ContextSlot::INITIAL_ARRAY_ITERATOR_MAP_INDEX),
441cb0ef41Sopenharmony_ci    properties_or_hash: kEmptyFixedArray,
451cb0ef41Sopenharmony_ci    elements: kEmptyFixedArray,
461cb0ef41Sopenharmony_ci    iterated_object: array,
471cb0ef41Sopenharmony_ci    next_index: 0,
481cb0ef41Sopenharmony_ci    kind: SmiTag<IterationKind>(kind)
491cb0ef41Sopenharmony_ci  };
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciextern class JSArray extends JSObject {
531cb0ef41Sopenharmony_ci  macro IsEmpty(): bool {
541cb0ef41Sopenharmony_ci    return this.length == 0;
551cb0ef41Sopenharmony_ci  }
561cb0ef41Sopenharmony_ci  length: Number;
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci@doNotGenerateCast
601cb0ef41Sopenharmony_ciextern class JSArrayConstructor extends JSFunction
611cb0ef41Sopenharmony_ci    generates 'TNode<JSFunction>';
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_cimacro NewJSArray(implicit context: Context)(
641cb0ef41Sopenharmony_ci    map: Map, elements: FixedArrayBase): JSArray {
651cb0ef41Sopenharmony_ci  return new JSArray{
661cb0ef41Sopenharmony_ci    map,
671cb0ef41Sopenharmony_ci    properties_or_hash: kEmptyFixedArray,
681cb0ef41Sopenharmony_ci    elements,
691cb0ef41Sopenharmony_ci    length: elements.length
701cb0ef41Sopenharmony_ci  };
711cb0ef41Sopenharmony_ci}
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cimacro NewJSArray(implicit context: Context)(): JSArray {
741cb0ef41Sopenharmony_ci  return new JSArray{
751cb0ef41Sopenharmony_ci    map: GetFastPackedSmiElementsJSArrayMap(),
761cb0ef41Sopenharmony_ci    properties_or_hash: kEmptyFixedArray,
771cb0ef41Sopenharmony_ci    elements: kEmptyFixedArray,
781cb0ef41Sopenharmony_ci    length: 0
791cb0ef41Sopenharmony_ci  };
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci// A HeapObject with a JSArray map, and either fast packed elements, or fast
831cb0ef41Sopenharmony_ci// holey elements when the global NoElementsProtector is not invalidated.
841cb0ef41Sopenharmony_citransient type FastJSArray extends JSArray;
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci// A HeapObject with a JSArray map, and either fast packed elements, or fast
871cb0ef41Sopenharmony_ci// holey elements or frozen, sealed elements when the global NoElementsProtector
881cb0ef41Sopenharmony_ci// is not invalidated.
891cb0ef41Sopenharmony_citransient type FastJSArrayForRead extends JSArray;
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci// A FastJSArray when the global ArraySpeciesProtector is not invalidated.
921cb0ef41Sopenharmony_citransient type FastJSArrayForCopy extends FastJSArray;
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci// A FastJSArrayForCopy when the global IsConcatSpreadableProtector is not
951cb0ef41Sopenharmony_ci// invalidated.
961cb0ef41Sopenharmony_citransient type FastJSArrayForConcat extends FastJSArrayForCopy;
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci// A FastJSArray when the global ArrayIteratorProtector is not invalidated.
991cb0ef41Sopenharmony_citransient type FastJSArrayWithNoCustomIteration extends FastJSArray;
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci// A FastJSArrayForRead when the global ArrayIteratorProtector is not
1021cb0ef41Sopenharmony_ci// invalidated.
1031cb0ef41Sopenharmony_citransient type FastJSArrayForReadWithNoCustomIteration extends
1041cb0ef41Sopenharmony_ci    FastJSArrayForRead;
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ciextern macro AllocateJSArray(
1071cb0ef41Sopenharmony_ci    constexpr ElementsKind, Map, intptr, Smi,
1081cb0ef41Sopenharmony_ci    constexpr AllocationFlag): JSArray;
1091cb0ef41Sopenharmony_ciextern macro AllocateJSArray(constexpr ElementsKind, Map, intptr, Smi): JSArray;
1101cb0ef41Sopenharmony_ciextern macro AllocateJSArray(constexpr ElementsKind, Map, Smi, Smi): JSArray;
1111cb0ef41Sopenharmony_ciextern macro AllocateJSArray(Map, FixedArrayBase, Smi): JSArray;
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_cimacro LoadElementNoHole<T : type extends FixedArrayBase>(
1141cb0ef41Sopenharmony_ci    a: JSArray, index: Smi): JSAny
1151cb0ef41Sopenharmony_ci    labels IfHole;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ciLoadElementNoHole<FixedArray>(implicit context: Context)(
1181cb0ef41Sopenharmony_ci    a: JSArray, index: Smi): JSAny
1191cb0ef41Sopenharmony_ci    labels IfHole {
1201cb0ef41Sopenharmony_ci  const elements: FixedArray =
1211cb0ef41Sopenharmony_ci      Cast<FixedArray>(a.elements) otherwise unreachable;
1221cb0ef41Sopenharmony_ci  const e = UnsafeCast<(JSAny | TheHole)>(elements.objects[index]);
1231cb0ef41Sopenharmony_ci  typeswitch (e) {
1241cb0ef41Sopenharmony_ci    case (TheHole): {
1251cb0ef41Sopenharmony_ci      goto IfHole;
1261cb0ef41Sopenharmony_ci    }
1271cb0ef41Sopenharmony_ci    case (e: JSAny): {
1281cb0ef41Sopenharmony_ci      return e;
1291cb0ef41Sopenharmony_ci    }
1301cb0ef41Sopenharmony_ci  }
1311cb0ef41Sopenharmony_ci}
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ciLoadElementNoHole<FixedDoubleArray>(implicit context: Context)(
1341cb0ef41Sopenharmony_ci    a: JSArray, index: Smi): JSAny
1351cb0ef41Sopenharmony_ci    labels IfHole {
1361cb0ef41Sopenharmony_ci  const elements: FixedDoubleArray =
1371cb0ef41Sopenharmony_ci      Cast<FixedDoubleArray>(a.elements) otherwise unreachable;
1381cb0ef41Sopenharmony_ci  const e: float64 = elements.floats[index].Value() otherwise IfHole;
1391cb0ef41Sopenharmony_ci  return AllocateHeapNumberWithValue(e);
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ciextern builtin ExtractFastJSArray(Context, JSArray, Smi, Smi): JSArray;
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ciextern macro MoveElements(
1451cb0ef41Sopenharmony_ci    constexpr ElementsKind, FixedArrayBase, intptr, intptr, intptr): void;
1461cb0ef41Sopenharmony_cimacro TorqueMoveElementsSmi(
1471cb0ef41Sopenharmony_ci    elements: FixedArray, dstIndex: intptr, srcIndex: intptr,
1481cb0ef41Sopenharmony_ci    count: intptr): void {
1491cb0ef41Sopenharmony_ci  MoveElements(
1501cb0ef41Sopenharmony_ci      ElementsKind::HOLEY_SMI_ELEMENTS, elements, dstIndex, srcIndex, count);
1511cb0ef41Sopenharmony_ci}
1521cb0ef41Sopenharmony_cimacro TorqueMoveElements(
1531cb0ef41Sopenharmony_ci    elements: FixedArray, dstIndex: intptr, srcIndex: intptr,
1541cb0ef41Sopenharmony_ci    count: intptr): void {
1551cb0ef41Sopenharmony_ci  MoveElements(
1561cb0ef41Sopenharmony_ci      ElementsKind::HOLEY_ELEMENTS, elements, dstIndex, srcIndex, count);
1571cb0ef41Sopenharmony_ci}
1581cb0ef41Sopenharmony_cimacro TorqueMoveElements(
1591cb0ef41Sopenharmony_ci    elements: FixedDoubleArray, dstIndex: intptr, srcIndex: intptr,
1601cb0ef41Sopenharmony_ci    count: intptr): void {
1611cb0ef41Sopenharmony_ci  MoveElements(
1621cb0ef41Sopenharmony_ci      ElementsKind::HOLEY_DOUBLE_ELEMENTS, elements, dstIndex, srcIndex, count);
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ciextern macro CopyElements(
1661cb0ef41Sopenharmony_ci    constexpr ElementsKind, FixedArrayBase, intptr, FixedArrayBase, intptr,
1671cb0ef41Sopenharmony_ci    intptr): void;
1681cb0ef41Sopenharmony_cimacro TorqueCopyElements(
1691cb0ef41Sopenharmony_ci    dstElements: FixedArray, dstIndex: intptr, srcElements: FixedArray,
1701cb0ef41Sopenharmony_ci    srcIndex: intptr, count: intptr): void {
1711cb0ef41Sopenharmony_ci  CopyElements(
1721cb0ef41Sopenharmony_ci      ElementsKind::HOLEY_ELEMENTS, dstElements, dstIndex, srcElements,
1731cb0ef41Sopenharmony_ci      srcIndex, count);
1741cb0ef41Sopenharmony_ci}
1751cb0ef41Sopenharmony_cimacro TorqueCopyElements(
1761cb0ef41Sopenharmony_ci    dstElements: FixedDoubleArray, dstIndex: intptr,
1771cb0ef41Sopenharmony_ci    srcElements: FixedDoubleArray, srcIndex: intptr, count: intptr): void {
1781cb0ef41Sopenharmony_ci  CopyElements(
1791cb0ef41Sopenharmony_ci      ElementsKind::HOLEY_DOUBLE_ELEMENTS, dstElements, dstIndex, srcElements,
1801cb0ef41Sopenharmony_ci      srcIndex, count);
1811cb0ef41Sopenharmony_ci}
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ciextern builtin CloneFastJSArray(Context, FastJSArrayForCopy): JSArray;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_cistruct FastJSArrayWitness {
1861cb0ef41Sopenharmony_ci  macro Get(): FastJSArray {
1871cb0ef41Sopenharmony_ci    return this.unstable;
1881cb0ef41Sopenharmony_ci  }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  macro Recheck(): void labels CastError {
1911cb0ef41Sopenharmony_ci    if (this.stable.map != this.map) goto CastError;
1921cb0ef41Sopenharmony_ci    // We don't need to check elements kind or whether the prototype
1931cb0ef41Sopenharmony_ci    // has changed away from the default JSArray prototype, because
1941cb0ef41Sopenharmony_ci    // if the map remains the same then those properties hold.
1951cb0ef41Sopenharmony_ci    //
1961cb0ef41Sopenharmony_ci    // However, we have to make sure there are no elements in the
1971cb0ef41Sopenharmony_ci    // prototype chain.
1981cb0ef41Sopenharmony_ci    if (IsNoElementsProtectorCellInvalid()) goto CastError;
1991cb0ef41Sopenharmony_ci    this.unstable = %RawDownCast<FastJSArray>(this.stable);
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  macro LoadElementNoHole(implicit context: Context)(k: Smi): JSAny
2031cb0ef41Sopenharmony_ci      labels FoundHole {
2041cb0ef41Sopenharmony_ci    if (this.hasDoubles) {
2051cb0ef41Sopenharmony_ci      return LoadElementNoHole<FixedDoubleArray>(this.unstable, k)
2061cb0ef41Sopenharmony_ci          otherwise FoundHole;
2071cb0ef41Sopenharmony_ci    } else {
2081cb0ef41Sopenharmony_ci      return LoadElementNoHole<FixedArray>(this.unstable, k)
2091cb0ef41Sopenharmony_ci          otherwise FoundHole;
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  macro StoreHole(k: Smi): void {
2141cb0ef41Sopenharmony_ci    if (this.hasDoubles) {
2151cb0ef41Sopenharmony_ci      const elements = Cast<FixedDoubleArray>(this.unstable.elements)
2161cb0ef41Sopenharmony_ci          otherwise unreachable;
2171cb0ef41Sopenharmony_ci      elements.floats[k] = kDoubleHole;
2181cb0ef41Sopenharmony_ci    } else {
2191cb0ef41Sopenharmony_ci      const elements = Cast<FixedArray>(this.unstable.elements)
2201cb0ef41Sopenharmony_ci          otherwise unreachable;
2211cb0ef41Sopenharmony_ci      elements.objects[k] = TheHole;
2221cb0ef41Sopenharmony_ci    }
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  macro LoadElementOrUndefined(implicit context: Context)(k: Smi): JSAny {
2261cb0ef41Sopenharmony_ci    try {
2271cb0ef41Sopenharmony_ci      return this.LoadElementNoHole(k) otherwise FoundHole;
2281cb0ef41Sopenharmony_ci    } label FoundHole {
2291cb0ef41Sopenharmony_ci      return Undefined;
2301cb0ef41Sopenharmony_ci    }
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  macro EnsureArrayPushable(implicit context: Context)(): void labels Failed {
2341cb0ef41Sopenharmony_ci    EnsureArrayPushable(this.map) otherwise Failed;
2351cb0ef41Sopenharmony_ci    array::EnsureWriteableFastElements(this.unstable);
2361cb0ef41Sopenharmony_ci    this.arrayIsPushable = true;
2371cb0ef41Sopenharmony_ci  }
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  macro ChangeLength(newLength: Smi): void {
2401cb0ef41Sopenharmony_ci    dcheck(this.arrayIsPushable);
2411cb0ef41Sopenharmony_ci    this.unstable.length = newLength;
2421cb0ef41Sopenharmony_ci  }
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci  macro Push(value: JSAny): void labels Failed {
2451cb0ef41Sopenharmony_ci    dcheck(this.arrayIsPushable);
2461cb0ef41Sopenharmony_ci    if (this.hasDoubles) {
2471cb0ef41Sopenharmony_ci      BuildAppendJSArray(
2481cb0ef41Sopenharmony_ci          ElementsKind::HOLEY_DOUBLE_ELEMENTS, this.unstable, value)
2491cb0ef41Sopenharmony_ci          otherwise Failed;
2501cb0ef41Sopenharmony_ci    } else if (this.hasSmis) {
2511cb0ef41Sopenharmony_ci      BuildAppendJSArray(ElementsKind::HOLEY_SMI_ELEMENTS, this.unstable, value)
2521cb0ef41Sopenharmony_ci          otherwise Failed;
2531cb0ef41Sopenharmony_ci    } else {
2541cb0ef41Sopenharmony_ci      dcheck(
2551cb0ef41Sopenharmony_ci          this.map.elements_kind == ElementsKind::HOLEY_ELEMENTS ||
2561cb0ef41Sopenharmony_ci          this.map.elements_kind == ElementsKind::PACKED_ELEMENTS);
2571cb0ef41Sopenharmony_ci      BuildAppendJSArray(ElementsKind::HOLEY_ELEMENTS, this.unstable, value)
2581cb0ef41Sopenharmony_ci          otherwise Failed;
2591cb0ef41Sopenharmony_ci    }
2601cb0ef41Sopenharmony_ci  }
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci  macro MoveElements(dst: intptr, src: intptr, length: intptr): void {
2631cb0ef41Sopenharmony_ci    dcheck(this.arrayIsPushable);
2641cb0ef41Sopenharmony_ci    if (this.hasDoubles) {
2651cb0ef41Sopenharmony_ci      const elements: FixedDoubleArray =
2661cb0ef41Sopenharmony_ci          Cast<FixedDoubleArray>(this.unstable.elements)
2671cb0ef41Sopenharmony_ci          otherwise unreachable;
2681cb0ef41Sopenharmony_ci      TorqueMoveElements(elements, dst, src, length);
2691cb0ef41Sopenharmony_ci    } else {
2701cb0ef41Sopenharmony_ci      const elements: FixedArray = Cast<FixedArray>(this.unstable.elements)
2711cb0ef41Sopenharmony_ci          otherwise unreachable;
2721cb0ef41Sopenharmony_ci      if (this.hasSmis) {
2731cb0ef41Sopenharmony_ci        TorqueMoveElementsSmi(elements, dst, src, length);
2741cb0ef41Sopenharmony_ci      } else {
2751cb0ef41Sopenharmony_ci        TorqueMoveElements(elements, dst, src, length);
2761cb0ef41Sopenharmony_ci      }
2771cb0ef41Sopenharmony_ci    }
2781cb0ef41Sopenharmony_ci  }
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci  const stable: JSArray;
2811cb0ef41Sopenharmony_ci  unstable: FastJSArray;
2821cb0ef41Sopenharmony_ci  const map: Map;
2831cb0ef41Sopenharmony_ci  const hasDoubles: bool;
2841cb0ef41Sopenharmony_ci  const hasSmis: bool;
2851cb0ef41Sopenharmony_ci  arrayIsPushable: bool;
2861cb0ef41Sopenharmony_ci}
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_cimacro NewFastJSArrayWitness(array: FastJSArray): FastJSArrayWitness {
2891cb0ef41Sopenharmony_ci  const kind = array.map.elements_kind;
2901cb0ef41Sopenharmony_ci  return FastJSArrayWitness{
2911cb0ef41Sopenharmony_ci    stable: array,
2921cb0ef41Sopenharmony_ci    unstable: array,
2931cb0ef41Sopenharmony_ci    map: array.map,
2941cb0ef41Sopenharmony_ci    hasDoubles: IsDoubleElementsKind(kind),
2951cb0ef41Sopenharmony_ci    hasSmis:
2961cb0ef41Sopenharmony_ci        IsElementsKindLessThanOrEqual(kind, ElementsKind::HOLEY_SMI_ELEMENTS),
2971cb0ef41Sopenharmony_ci    arrayIsPushable: false
2981cb0ef41Sopenharmony_ci  };
2991cb0ef41Sopenharmony_ci}
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_cistruct FastJSArrayForReadWitness {
3021cb0ef41Sopenharmony_ci  macro Get(): FastJSArrayForRead {
3031cb0ef41Sopenharmony_ci    return this.unstable;
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci  macro Recheck(): void labels CastError {
3071cb0ef41Sopenharmony_ci    if (this.stable.map != this.map) goto CastError;
3081cb0ef41Sopenharmony_ci    // We don't need to check elements kind or whether the prototype
3091cb0ef41Sopenharmony_ci    // has changed away from the default JSArray prototype, because
3101cb0ef41Sopenharmony_ci    // if the map remains the same then those properties hold.
3111cb0ef41Sopenharmony_ci    //
3121cb0ef41Sopenharmony_ci    // However, we have to make sure there are no elements in the
3131cb0ef41Sopenharmony_ci    // prototype chain.
3141cb0ef41Sopenharmony_ci    if (IsNoElementsProtectorCellInvalid()) goto CastError;
3151cb0ef41Sopenharmony_ci    this.unstable = %RawDownCast<FastJSArrayForRead>(this.stable);
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  macro LoadElementNoHole(implicit context: Context)(k: Smi): JSAny
3191cb0ef41Sopenharmony_ci      labels FoundHole {
3201cb0ef41Sopenharmony_ci    if (this.hasDoubles) {
3211cb0ef41Sopenharmony_ci      return LoadElementNoHole<FixedDoubleArray>(this.unstable, k)
3221cb0ef41Sopenharmony_ci          otherwise FoundHole;
3231cb0ef41Sopenharmony_ci    } else {
3241cb0ef41Sopenharmony_ci      return LoadElementNoHole<FixedArray>(this.unstable, k)
3251cb0ef41Sopenharmony_ci          otherwise FoundHole;
3261cb0ef41Sopenharmony_ci    }
3271cb0ef41Sopenharmony_ci  }
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  const stable: JSArray;
3301cb0ef41Sopenharmony_ci  unstable: FastJSArrayForRead;
3311cb0ef41Sopenharmony_ci  const map: Map;
3321cb0ef41Sopenharmony_ci  const hasDoubles: bool;
3331cb0ef41Sopenharmony_ci}
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_cimacro NewFastJSArrayForReadWitness(array: FastJSArrayForRead):
3361cb0ef41Sopenharmony_ci    FastJSArrayForReadWitness {
3371cb0ef41Sopenharmony_ci  const kind = array.map.elements_kind;
3381cb0ef41Sopenharmony_ci  return FastJSArrayForReadWitness{
3391cb0ef41Sopenharmony_ci    stable: array,
3401cb0ef41Sopenharmony_ci    unstable: array,
3411cb0ef41Sopenharmony_ci    map: array.map,
3421cb0ef41Sopenharmony_ci    hasDoubles: IsDoubleElementsKind(kind)
3431cb0ef41Sopenharmony_ci  };
3441cb0ef41Sopenharmony_ci}
345