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_ci// Unfortunately, MutableSlice<> is currently not a subtype of ConstSlice.
61cb0ef41Sopenharmony_ci// This would require struct subtyping, which is not yet supported.
71cb0ef41Sopenharmony_citype MutableSlice<T: type> extends torque_internal::Slice<T, &T>;
81cb0ef41Sopenharmony_citype ConstSlice<T: type> extends torque_internal::Slice<T, const &T>;
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cimacro Subslice<T: type>(slice: ConstSlice<T>, start: intptr, length: intptr):
111cb0ef41Sopenharmony_ci    ConstSlice<T>labels OutOfBounds {
121cb0ef41Sopenharmony_ci  if (Unsigned(length) > Unsigned(slice.length)) goto OutOfBounds;
131cb0ef41Sopenharmony_ci  if (Unsigned(start) > Unsigned(slice.length - length)) goto OutOfBounds;
141cb0ef41Sopenharmony_ci  const offset = slice.offset + torque_internal::TimesSizeOf<T>(start);
151cb0ef41Sopenharmony_ci  return torque_internal::unsafe::NewConstSlice<T>(
161cb0ef41Sopenharmony_ci      slice.object, offset, length);
171cb0ef41Sopenharmony_ci}
181cb0ef41Sopenharmony_cimacro Subslice<T: type>(slice: MutableSlice<T>, start: intptr, length: intptr):
191cb0ef41Sopenharmony_ci    MutableSlice<T>labels OutOfBounds {
201cb0ef41Sopenharmony_ci  if (Unsigned(length) > Unsigned(slice.length)) goto OutOfBounds;
211cb0ef41Sopenharmony_ci  if (Unsigned(start) > Unsigned(slice.length - length)) goto OutOfBounds;
221cb0ef41Sopenharmony_ci  const offset = slice.offset + torque_internal::TimesSizeOf<T>(start);
231cb0ef41Sopenharmony_ci  return torque_internal::unsafe::NewMutableSlice<T>(
241cb0ef41Sopenharmony_ci      slice.object, offset, length);
251cb0ef41Sopenharmony_ci}
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_cinamespace unsafe {
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cimacro AddOffset<T: type>(ref: &T, offset: intptr): &T {
301cb0ef41Sopenharmony_ci  return torque_internal::unsafe::NewReference<T>(
311cb0ef41Sopenharmony_ci      ref.object, ref.offset + torque_internal::TimesSizeOf<T>(offset));
321cb0ef41Sopenharmony_ci}
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_cimacro AddOffset<T: type>(ref: const &T, offset: intptr): const &T {
351cb0ef41Sopenharmony_ci  return torque_internal::unsafe::NewReference<T>(
361cb0ef41Sopenharmony_ci      ref.object, ref.offset + torque_internal::TimesSizeOf<T>(offset));
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci}  // namespace unsafe
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cinamespace torque_internal {
421cb0ef41Sopenharmony_ci// Unsafe is a marker that we require to be passed when calling internal APIs
431cb0ef41Sopenharmony_ci// that might lead to unsoundness when used incorrectly. Unsafe markers should
441cb0ef41Sopenharmony_ci// therefore not be instantiated anywhere outside of this namespace.
451cb0ef41Sopenharmony_cistruct Unsafe {}
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci// Size of a type in memory (on the heap). For class types, this is the size
481cb0ef41Sopenharmony_ci// of the pointer, not of the instance.
491cb0ef41Sopenharmony_ciintrinsic %SizeOf<T: type>(): constexpr int31;
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_cimacro TimesSizeOf<T: type>(i: intptr): intptr {
521cb0ef41Sopenharmony_ci  return i * %SizeOf<T>();
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cistruct Reference<T: type> {
561cb0ef41Sopenharmony_ci  const object: HeapObject|TaggedZeroPattern;
571cb0ef41Sopenharmony_ci  const offset: intptr;
581cb0ef41Sopenharmony_ci  unsafeMarker: Unsafe;
591cb0ef41Sopenharmony_ci}
601cb0ef41Sopenharmony_citype ConstReference<T: type> extends Reference<T>;
611cb0ef41Sopenharmony_citype MutableReference<T: type> extends ConstReference<T>;
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_cinamespace unsafe {
641cb0ef41Sopenharmony_cimacro NewReference<T: type>(
651cb0ef41Sopenharmony_ci    object: HeapObject|TaggedZeroPattern, offset: intptr):&T {
661cb0ef41Sopenharmony_ci  return %RawDownCast<&T>(
671cb0ef41Sopenharmony_ci      Reference<T>{object: object, offset: offset, unsafeMarker: Unsafe {}});
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_cimacro NewOffHeapReference<T: type>(ptr: RawPtr<T>):&T {
701cb0ef41Sopenharmony_ci  return %RawDownCast<&T>(Reference<T>{
711cb0ef41Sopenharmony_ci    object: kZeroBitPattern,
721cb0ef41Sopenharmony_ci    offset: Convert<intptr>(Convert<RawPtr>(ptr)) + kHeapObjectTag,
731cb0ef41Sopenharmony_ci    unsafeMarker: Unsafe {}
741cb0ef41Sopenharmony_ci  });
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_cimacro ReferenceCast<T: type, U: type>(ref:&U):&T {
771cb0ef41Sopenharmony_ci  const ref = NewReference<T>(ref.object, ref.offset);
781cb0ef41Sopenharmony_ci  UnsafeCast<T>(*ref);
791cb0ef41Sopenharmony_ci  return ref;
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ciextern macro GCUnsafeReferenceToRawPtr(
831cb0ef41Sopenharmony_ci    HeapObject | TaggedZeroPattern, intptr): RawPtr;
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci}  // namespace unsafe
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_cistruct Slice<T: type, Reference: type> {
881cb0ef41Sopenharmony_ci  macro TryAtIndex(index: intptr): Reference labels OutOfBounds {
891cb0ef41Sopenharmony_ci    if (Convert<uintptr>(index) < Convert<uintptr>(this.length)) {
901cb0ef41Sopenharmony_ci      return this.UncheckedAtIndex(index);
911cb0ef41Sopenharmony_ci    } else {
921cb0ef41Sopenharmony_ci      goto OutOfBounds;
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci  macro UncheckedAtIndex(index: intptr): Reference {
961cb0ef41Sopenharmony_ci    return unsafe::NewReference<T>(
971cb0ef41Sopenharmony_ci        this.object, this.offset + TimesSizeOf<T>(index));
981cb0ef41Sopenharmony_ci  }
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  macro AtIndex(index: intptr): Reference {
1011cb0ef41Sopenharmony_ci    return this.TryAtIndex(index) otherwise unreachable;
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  macro AtIndex(index: uintptr): Reference {
1051cb0ef41Sopenharmony_ci    return this.TryAtIndex(Convert<intptr>(index)) otherwise unreachable;
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  macro AtIndex(index: constexpr IntegerLiteral): Reference {
1091cb0ef41Sopenharmony_ci    return this.AtIndex(FromConstexpr<uintptr>(index));
1101cb0ef41Sopenharmony_ci  }
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  macro AtIndex(index: constexpr int31): Reference {
1131cb0ef41Sopenharmony_ci    const i: intptr = Convert<intptr>(index);
1141cb0ef41Sopenharmony_ci    return this.TryAtIndex(i) otherwise unreachable;
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  macro AtIndex(index: Smi): Reference {
1181cb0ef41Sopenharmony_ci    const i: intptr = Convert<intptr>(index);
1191cb0ef41Sopenharmony_ci    return this.TryAtIndex(i) otherwise unreachable;
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  macro Iterator(): SliceIterator<T, Reference> {
1231cb0ef41Sopenharmony_ci    const end = this.offset + TimesSizeOf<T>(this.length);
1241cb0ef41Sopenharmony_ci    return SliceIterator<T, Reference>{
1251cb0ef41Sopenharmony_ci      object: this.object,
1261cb0ef41Sopenharmony_ci      start: this.offset,
1271cb0ef41Sopenharmony_ci      end: end,
1281cb0ef41Sopenharmony_ci      unsafeMarker: Unsafe {}
1291cb0ef41Sopenharmony_ci    };
1301cb0ef41Sopenharmony_ci  }
1311cb0ef41Sopenharmony_ci  macro Iterator(
1321cb0ef41Sopenharmony_ci      startIndex: intptr, endIndex: intptr): SliceIterator<T, Reference> {
1331cb0ef41Sopenharmony_ci    check(
1341cb0ef41Sopenharmony_ci        Convert<uintptr>(endIndex) <= Convert<uintptr>(this.length) &&
1351cb0ef41Sopenharmony_ci        Convert<uintptr>(startIndex) <= Convert<uintptr>(endIndex));
1361cb0ef41Sopenharmony_ci    const start = this.offset + TimesSizeOf<T>(startIndex);
1371cb0ef41Sopenharmony_ci    const end = this.offset + TimesSizeOf<T>(endIndex);
1381cb0ef41Sopenharmony_ci    return SliceIterator<T, Reference>{
1391cb0ef41Sopenharmony_ci      object: this.object,
1401cb0ef41Sopenharmony_ci      start,
1411cb0ef41Sopenharmony_ci      end,
1421cb0ef41Sopenharmony_ci      unsafeMarker: Unsafe {}
1431cb0ef41Sopenharmony_ci    };
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  // WARNING: This can return a raw pointer into the heap, which is not GC-safe.
1471cb0ef41Sopenharmony_ci  macro GCUnsafeStartPointer(): RawPtr<T> {
1481cb0ef41Sopenharmony_ci    return %RawDownCast<RawPtr<T>>(
1491cb0ef41Sopenharmony_ci        unsafe::GCUnsafeReferenceToRawPtr(this.object, this.offset));
1501cb0ef41Sopenharmony_ci  }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  const object: HeapObject|TaggedZeroPattern;
1531cb0ef41Sopenharmony_ci  const offset: intptr;
1541cb0ef41Sopenharmony_ci  const length: intptr;
1551cb0ef41Sopenharmony_ci  unsafeMarker: Unsafe;
1561cb0ef41Sopenharmony_ci}
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_cinamespace unsafe {
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_cimacro NewMutableSlice<T: type>(
1611cb0ef41Sopenharmony_ci    object: HeapObject|TaggedZeroPattern, offset: intptr,
1621cb0ef41Sopenharmony_ci    length: intptr): MutableSlice<T> {
1631cb0ef41Sopenharmony_ci  return %RawDownCast<MutableSlice<T>>(Slice<T, &T>{
1641cb0ef41Sopenharmony_ci    object: object,
1651cb0ef41Sopenharmony_ci    offset: offset,
1661cb0ef41Sopenharmony_ci    length: length,
1671cb0ef41Sopenharmony_ci    unsafeMarker: Unsafe {}
1681cb0ef41Sopenharmony_ci  });
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cimacro NewConstSlice<T: type>(
1721cb0ef41Sopenharmony_ci    object: HeapObject|TaggedZeroPattern, offset: intptr,
1731cb0ef41Sopenharmony_ci    length: intptr): ConstSlice<T> {
1741cb0ef41Sopenharmony_ci  return %RawDownCast<ConstSlice<T>>(Slice<T, const &T>{
1751cb0ef41Sopenharmony_ci    object: object,
1761cb0ef41Sopenharmony_ci    offset: offset,
1771cb0ef41Sopenharmony_ci    length: length,
1781cb0ef41Sopenharmony_ci    unsafeMarker: Unsafe {}
1791cb0ef41Sopenharmony_ci  });
1801cb0ef41Sopenharmony_ci}
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_cimacro NewOffHeapConstSlice<T: type>(
1831cb0ef41Sopenharmony_ci    startPointer: RawPtr<T>, length: intptr): ConstSlice<T> {
1841cb0ef41Sopenharmony_ci  return %RawDownCast<ConstSlice<T>>(Slice<T, const &T>{
1851cb0ef41Sopenharmony_ci    object: kZeroBitPattern,
1861cb0ef41Sopenharmony_ci    offset: Convert<intptr>(Convert<RawPtr>(startPointer)) + kHeapObjectTag,
1871cb0ef41Sopenharmony_ci    length: length,
1881cb0ef41Sopenharmony_ci    unsafeMarker: Unsafe {}
1891cb0ef41Sopenharmony_ci  });
1901cb0ef41Sopenharmony_ci}
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci}  // namespace unsafe
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_cistruct SliceIterator<T: type, Reference: type> {
1951cb0ef41Sopenharmony_ci  macro Empty(): bool {
1961cb0ef41Sopenharmony_ci    return this.start == this.end;
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  macro Next(): T labels NoMore {
2001cb0ef41Sopenharmony_ci    return *this.NextReference() otherwise NoMore;
2011cb0ef41Sopenharmony_ci  }
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  macro NextReference(): Reference labels NoMore {
2041cb0ef41Sopenharmony_ci    if (this.Empty()) {
2051cb0ef41Sopenharmony_ci      goto NoMore;
2061cb0ef41Sopenharmony_ci    } else {
2071cb0ef41Sopenharmony_ci      const result = unsafe::NewReference<T>(this.object, this.start);
2081cb0ef41Sopenharmony_ci      this.start += %SizeOf<T>();
2091cb0ef41Sopenharmony_ci      return result;
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  object: HeapObject|TaggedZeroPattern;
2141cb0ef41Sopenharmony_ci  start: intptr;
2151cb0ef41Sopenharmony_ci  end: intptr;
2161cb0ef41Sopenharmony_ci  unsafeMarker: Unsafe;
2171cb0ef41Sopenharmony_ci}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_cimacro AddIndexedFieldSizeToObjectSize(
2201cb0ef41Sopenharmony_ci    baseSize: intptr, arrayLength: intptr, fieldSize: constexpr int32): intptr {
2211cb0ef41Sopenharmony_ci  const arrayLength = Convert<int32>(arrayLength);
2221cb0ef41Sopenharmony_ci  const byteLength = TryInt32Mul(arrayLength, fieldSize)
2231cb0ef41Sopenharmony_ci      otherwise unreachable;
2241cb0ef41Sopenharmony_ci  return TryIntPtrAdd(baseSize, Convert<intptr>(byteLength))
2251cb0ef41Sopenharmony_ci      otherwise unreachable;
2261cb0ef41Sopenharmony_ci}
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_cimacro AlignTagged(x: intptr): intptr {
2291cb0ef41Sopenharmony_ci  // Round up to a multiple of kTaggedSize.
2301cb0ef41Sopenharmony_ci  return (x + kObjectAlignmentMask) & ~kObjectAlignmentMask;
2311cb0ef41Sopenharmony_ci}
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_cimacro IsTaggedAligned(x: intptr): bool {
2341cb0ef41Sopenharmony_ci  return (x & kObjectAlignmentMask) == 0;
2351cb0ef41Sopenharmony_ci}
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_cimacro ValidAllocationSize(sizeInBytes: intptr, map: Map): bool {
2381cb0ef41Sopenharmony_ci  if (sizeInBytes <= 0) return false;
2391cb0ef41Sopenharmony_ci  if (!IsTaggedAligned(sizeInBytes)) return false;
2401cb0ef41Sopenharmony_ci  const instanceSizeInWords = Convert<intptr>(map.instance_size_in_words);
2411cb0ef41Sopenharmony_ci  return instanceSizeInWords == kVariableSizeSentinel ||
2421cb0ef41Sopenharmony_ci      instanceSizeInWords * kTaggedSize == sizeInBytes;
2431cb0ef41Sopenharmony_ci}
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_citype UninitializedHeapObject extends HeapObject;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ciextern macro GetInstanceTypeMap(constexpr InstanceType): Map;
2481cb0ef41Sopenharmony_ciextern macro Allocate(
2491cb0ef41Sopenharmony_ci    intptr, constexpr AllocationFlag): UninitializedHeapObject;
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ciconst kAllocateBaseFlags: constexpr AllocationFlag =
2521cb0ef41Sopenharmony_ci    AllocationFlag::kAllowLargeObjectAllocation;
2531cb0ef41Sopenharmony_cimacro AllocateFromNew(
2541cb0ef41Sopenharmony_ci    sizeInBytes: intptr, map: Map, pretenured: bool): UninitializedHeapObject {
2551cb0ef41Sopenharmony_ci  dcheck(ValidAllocationSize(sizeInBytes, map));
2561cb0ef41Sopenharmony_ci  if (pretenured) {
2571cb0ef41Sopenharmony_ci    return Allocate(
2581cb0ef41Sopenharmony_ci        sizeInBytes,
2591cb0ef41Sopenharmony_ci        %RawConstexprCast<constexpr AllocationFlag>(
2601cb0ef41Sopenharmony_ci            %RawConstexprCast<constexpr int32>(kAllocateBaseFlags) |
2611cb0ef41Sopenharmony_ci            %RawConstexprCast<constexpr int32>(AllocationFlag::kPretenured)));
2621cb0ef41Sopenharmony_ci  } else {
2631cb0ef41Sopenharmony_ci    return Allocate(sizeInBytes, kAllocateBaseFlags);
2641cb0ef41Sopenharmony_ci  }
2651cb0ef41Sopenharmony_ci}
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_cimacro InitializeFieldsFromIterator<T: type, Iterator: type>(
2681cb0ef41Sopenharmony_ci    target: MutableSlice<T>, originIterator: Iterator): void {
2691cb0ef41Sopenharmony_ci  let targetIterator = target.Iterator();
2701cb0ef41Sopenharmony_ci  let originIterator = originIterator;
2711cb0ef41Sopenharmony_ci  while (true) {
2721cb0ef41Sopenharmony_ci    const ref:&T = targetIterator.NextReference() otherwise break;
2731cb0ef41Sopenharmony_ci    *ref = originIterator.Next() otherwise unreachable;
2741cb0ef41Sopenharmony_ci  }
2751cb0ef41Sopenharmony_ci}
2761cb0ef41Sopenharmony_ci// Dummy implementations: do not initialize for UninitializedIterator.
2771cb0ef41Sopenharmony_ciInitializeFieldsFromIterator<char8, UninitializedIterator>(
2781cb0ef41Sopenharmony_ci    _target: MutableSlice<char8>,
2791cb0ef41Sopenharmony_ci    _originIterator: UninitializedIterator): void {}
2801cb0ef41Sopenharmony_ciInitializeFieldsFromIterator<char16, UninitializedIterator>(
2811cb0ef41Sopenharmony_ci    _target: MutableSlice<char16>,
2821cb0ef41Sopenharmony_ci    _originIterator: UninitializedIterator): void {}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ciextern macro IsDoubleHole(HeapObject, intptr): bool;
2851cb0ef41Sopenharmony_ciextern macro StoreDoubleHole(HeapObject, intptr): void;
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_cimacro LoadFloat64OrHole(r:&float64_or_hole): float64_or_hole {
2881cb0ef41Sopenharmony_ci  return float64_or_hole{
2891cb0ef41Sopenharmony_ci    is_hole: IsDoubleHole(
2901cb0ef41Sopenharmony_ci        %RawDownCast<HeapObject>(r.object), r.offset - kHeapObjectTag),
2911cb0ef41Sopenharmony_ci    value: *unsafe::NewReference<float64>(r.object, r.offset)
2921cb0ef41Sopenharmony_ci  };
2931cb0ef41Sopenharmony_ci}
2941cb0ef41Sopenharmony_cimacro StoreFloat64OrHole(r:&float64_or_hole, value: float64_or_hole): void {
2951cb0ef41Sopenharmony_ci  if (value.is_hole) {
2961cb0ef41Sopenharmony_ci    StoreDoubleHole(
2971cb0ef41Sopenharmony_ci        %RawDownCast<HeapObject>(r.object), r.offset - kHeapObjectTag);
2981cb0ef41Sopenharmony_ci  } else {
2991cb0ef41Sopenharmony_ci    *unsafe::NewReference<float64>(r.object, r.offset) = value.value;
3001cb0ef41Sopenharmony_ci  }
3011cb0ef41Sopenharmony_ci}
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_cimacro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject):
3041cb0ef41Sopenharmony_ci    T labels CastError {
3051cb0ef41Sopenharmony_ci  const map = o.map;
3061cb0ef41Sopenharmony_ci  const minInstanceType = %MinInstanceType<T>();
3071cb0ef41Sopenharmony_ci  const maxInstanceType = %MaxInstanceType<T>();
3081cb0ef41Sopenharmony_ci  if constexpr (minInstanceType == maxInstanceType) {
3091cb0ef41Sopenharmony_ci    if constexpr (%ClassHasMapConstant<T>()) {
3101cb0ef41Sopenharmony_ci      if (map != %GetClassMapConstant<T>()) goto CastError;
3111cb0ef41Sopenharmony_ci    } else {
3121cb0ef41Sopenharmony_ci      if (map.instance_type != minInstanceType) goto CastError;
3131cb0ef41Sopenharmony_ci    }
3141cb0ef41Sopenharmony_ci  } else {
3151cb0ef41Sopenharmony_ci    const diff: int32 = maxInstanceType - minInstanceType;
3161cb0ef41Sopenharmony_ci    const offset = Convert<int32>(Convert<uint16>(map.instance_type)) -
3171cb0ef41Sopenharmony_ci        Convert<int32>(Convert<uint16>(
3181cb0ef41Sopenharmony_ci            FromConstexpr<InstanceType>(minInstanceType)));
3191cb0ef41Sopenharmony_ci    if (Unsigned(offset) > Unsigned(diff)) goto CastError;
3201cb0ef41Sopenharmony_ci  }
3211cb0ef41Sopenharmony_ci  return %RawDownCast<T>(o);
3221cb0ef41Sopenharmony_ci}
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ciextern macro StaticAssert(bool, constexpr string): void;
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci// This is for the implementation of the dot operator. In any context where the
3271cb0ef41Sopenharmony_ci// dot operator is available, the correct way to get the length of an indexed
3281cb0ef41Sopenharmony_ci// field x from object o is `(&o.x).length`.
3291cb0ef41Sopenharmony_ciintrinsic %IndexedFieldLength<T: type>(o: T, f: constexpr string): intptr;
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci// If field x is defined as optional, then &o.x returns a reference to the field
3321cb0ef41Sopenharmony_ci// or crashes the program (unreachable) if the field is not present. Usually
3331cb0ef41Sopenharmony_ci// that's the most convenient behavior, but in rare cases such as the
3341cb0ef41Sopenharmony_ci// implementation of the dot operator, we may instead need to get a Slice to the
3351cb0ef41Sopenharmony_ci// optional field, which is either length zero or one depending on whether the
3361cb0ef41Sopenharmony_ci// field is present. This intrinsic provides Slices for both indexed fields
3371cb0ef41Sopenharmony_ci// (equivalent to &o.x) and optional fields.
3381cb0ef41Sopenharmony_ciintrinsic %FieldSlice<T: type, TSlice: type>(
3391cb0ef41Sopenharmony_ci    o: T, f: constexpr string): TSlice;
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ciextern macro GetPendingMessage(): TheHole|JSMessageObject;
3421cb0ef41Sopenharmony_ciextern macro SetPendingMessage(TheHole | JSMessageObject): void;
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci// This is implicitly performed at the beginning of Torque catch-blocks.
3451cb0ef41Sopenharmony_cimacro GetAndResetPendingMessage(): TheHole|JSMessageObject {
3461cb0ef41Sopenharmony_ci  const message = GetPendingMessage();
3471cb0ef41Sopenharmony_ci  SetPendingMessage(TheHole);
3481cb0ef41Sopenharmony_ci  return message;
3491cb0ef41Sopenharmony_ci}
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci}  // namespace torque_internal
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci// Indicates that an array-field should not be initialized.
3541cb0ef41Sopenharmony_ci// For safety reasons, this is only allowed for untagged types.
3551cb0ef41Sopenharmony_cistruct UninitializedIterator {}
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci// %RawDownCast should *never* be used anywhere in Torque code except for
3581cb0ef41Sopenharmony_ci// in Torque-based UnsafeCast operators preceeded by an appropriate
3591cb0ef41Sopenharmony_ci// type dcheck()
3601cb0ef41Sopenharmony_ciintrinsic %RawDownCast<To: type, From: type>(x: From): To;
3611cb0ef41Sopenharmony_ciintrinsic %RawConstexprCast<To: type, From: type>(f: From): To;
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ciintrinsic %MinInstanceType<T: type>(): constexpr InstanceType;
3641cb0ef41Sopenharmony_ciintrinsic %MaxInstanceType<T: type>(): constexpr InstanceType;
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ciintrinsic %ClassHasMapConstant<T: type>(): constexpr bool;
3671cb0ef41Sopenharmony_ciintrinsic %GetClassMapConstant<T: type>(): Map;
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_cistruct IteratorSequence<T: type, FirstIterator: type, SecondIterator: type> {
3701cb0ef41Sopenharmony_ci  macro Empty(): bool {
3711cb0ef41Sopenharmony_ci    return this.first.Empty() && this.second.Empty();
3721cb0ef41Sopenharmony_ci  }
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  macro Next(): T labels NoMore {
3751cb0ef41Sopenharmony_ci    return this.first.Next()
3761cb0ef41Sopenharmony_ci        otherwise return (this.second.Next() otherwise NoMore);
3771cb0ef41Sopenharmony_ci  }
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci  first: FirstIterator;
3801cb0ef41Sopenharmony_ci  second: SecondIterator;
3811cb0ef41Sopenharmony_ci}
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_cimacro IteratorSequence<T: type, FirstIterator: type, SecondIterator: type>(
3841cb0ef41Sopenharmony_ci    first: FirstIterator, second: SecondIterator):
3851cb0ef41Sopenharmony_ci    IteratorSequence<T, FirstIterator, SecondIterator> {
3861cb0ef41Sopenharmony_ci  return IteratorSequence<T>{first, second};
3871cb0ef41Sopenharmony_ci}
388