%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/wasm.tq

// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include 'src/builtins/builtins-wasm-gen.h'

namespace runtime {
extern runtime WasmMemoryGrow(Context, WasmInstanceObject, Smi, Smi): Smi;
extern runtime WasmRefFunc(Context, WasmInstanceObject, Smi): JSAny;
extern runtime WasmInternalFunctionCreateExternal(
    Context, WasmInternalFunction): JSFunction;
extern runtime WasmTableInit(
    Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny;
extern runtime WasmTableCopy(
    Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny;
extern runtime WasmTableFill(
    Context, WasmInstanceObject, Smi, Smi, Object, Smi): JSAny;
extern runtime WasmTableGrow(Context, WasmInstanceObject, Smi, Object, Smi):
    Smi;
extern runtime WasmFunctionTableGet(Context, WasmInstanceObject, Smi, Smi):
    JSAny;
extern runtime WasmFunctionTableSet(
    Context, WasmInstanceObject, Smi, Smi, Object): JSAny;
extern runtime ThrowRangeError(Context, Smi): never;
extern runtime ThrowWasmError(Context, Smi): never;
extern runtime WasmThrowRangeError(Context, Smi): never;
extern runtime WasmThrowTypeError(Context, Smi, JSAny): never;
extern runtime WasmThrowTypeErrorTwoArgs(Context, Smi, JSAny, JSAny): never;
extern runtime WasmThrow(Context, Object, FixedArray): JSAny;
extern runtime WasmReThrow(Context, Object): JSAny;
extern runtime WasmTriggerTierUp(Context, WasmInstanceObject): JSAny;
extern runtime WasmStackGuard(Context): JSAny;
extern runtime ThrowWasmStackOverflow(Context): JSAny;
extern runtime WasmTraceMemory(Context, Smi): JSAny;
extern runtime WasmTraceEnter(Context): JSAny;
extern runtime WasmTraceExit(Context, Smi): JSAny;
extern runtime WasmAtomicNotify(
    Context, WasmInstanceObject, Smi, Number, Number): Smi;
extern runtime WasmI32AtomicWait(
    Context, WasmInstanceObject, Smi, Number, Number, BigInt): Smi;
extern runtime WasmI64AtomicWait(
    Context, WasmInstanceObject, Smi, Number, BigInt, BigInt): Smi;
extern runtime WasmArrayCopy(Context, WasmArray, Smi, WasmArray, Smi, Smi):
    JSAny;
extern runtime WasmArrayNewSegment(
    Context, WasmInstanceObject, Smi, Smi, Smi, Map): Object;
extern runtime WasmStringNewSegmentWtf8(
    Context, WasmInstanceObject, Smi, Smi, Smi): String;
extern runtime WasmArrayInitSegment(
    Context, WasmInstanceObject, Smi, WasmArray, Smi, Smi, Smi): JSAny;
extern runtime WasmStringNewWtf8(
    Context, WasmInstanceObject, Smi, Smi, Number, Number): String|Null;
extern runtime WasmStringNewWtf8Array(Context, Smi, WasmArray, Smi, Smi): String
    |Null;
extern runtime WasmStringNewWtf16(
    Context, WasmInstanceObject, Smi, Number, Number): String;
extern runtime WasmStringNewWtf16Array(Context, WasmArray, Smi, Smi): String;
extern runtime WasmStringConst(Context, WasmInstanceObject, Smi): String;
extern runtime WasmStringMeasureUtf8(Context, String): Number;
extern runtime WasmStringMeasureWtf8(Context, String): Number;
extern runtime WasmStringEncodeWtf8(
    Context, WasmInstanceObject, Smi, Smi, String, Number): Number;
extern runtime WasmStringEncodeWtf8Array(
    Context, Smi, String, WasmArray, Number): Number;
extern runtime WasmStringEncodeWtf16(
    Context, WasmInstanceObject, Smi, String, Number, Smi, Smi): JSAny;
extern runtime WasmStringAsWtf8(Context, String): ByteArray;
extern runtime WasmStringViewWtf8Encode(
    Context, WasmInstanceObject, Smi, ByteArray, Number, Number, Number): JSAny;
extern runtime WasmStringViewWtf8Slice(Context, ByteArray, Number, Number):
    String;
extern runtime WasmStringFromCodePoint(Context, Number): String;
extern runtime WasmStringHash(NoContext, String): Smi;
extern runtime WasmSubstring(Context, String, Smi, Smi): String;
extern runtime WasmJSToWasmObject(Context, JSAny, Smi): JSAny;
}

namespace unsafe {
extern macro Allocate(intptr): HeapObject;
extern macro Allocate(intptr, constexpr AllocationFlag): HeapObject;
}

namespace wasm {
const kAnyType: constexpr int31
    generates 'wasm::kWasmAnyRef.raw_bit_field()';
const kMaxPolymorphism:
    constexpr int31 generates 'wasm::kMaxPolymorphism';

extern macro WasmBuiltinsAssembler::LoadInstanceFromFrame():
    WasmInstanceObject;

// WasmInstanceObject has a field layout that Torque can't handle yet.
// TODO(bbudge) Eliminate these functions when Torque is ready.
extern macro WasmBuiltinsAssembler::LoadContextFromInstance(
    WasmInstanceObject): NativeContext;
extern macro WasmBuiltinsAssembler::LoadTablesFromInstance(WasmInstanceObject):
    FixedArray;
extern macro WasmBuiltinsAssembler::LoadInternalFunctionsFromInstance(
    WasmInstanceObject): FixedArray;
extern macro WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance(
    WasmInstanceObject): FixedArray;
extern macro WasmBuiltinsAssembler::LoadContextFromWasmOrJsFrame():
    NativeContext;

extern macro WasmBuiltinsAssembler::StringToFloat64(String): float64;

macro LoadContextFromFrame(): NativeContext {
  return LoadContextFromInstance(LoadInstanceFromFrame());
}

builtin WasmInt32ToHeapNumber(val: int32): HeapNumber {
  return AllocateHeapNumberWithValue(Convert<float64>(val));
}

builtin WasmFuncRefToJS(
    implicit context: Context)(val: WasmInternalFunction|WasmNull): JSFunction
    |Null {
  typeswitch (val) {
    case (WasmNull): {
      return Null;
    }
    case (func: WasmInternalFunction): {
      const maybeExternal: Object = func.external;
      if (maybeExternal != Undefined) {
        return %RawDownCast<JSFunction>(maybeExternal);
      }
      tail runtime::WasmInternalFunctionCreateExternal(context, func);
    }
  }
}

builtin WasmTaggedNonSmiToInt32(implicit context: Context)(val: HeapObject):
    int32 {
  return ChangeTaggedNonSmiToInt32(val);
}

builtin WasmTaggedToFloat64(implicit context: Context)(val: JSAny): float64 {
  return ChangeTaggedToFloat64(val);
}

builtin WasmTaggedToFloat32(implicit context: Context)(val: JSAny): float32 {
  return TruncateFloat64ToFloat32(ChangeTaggedToFloat64(val));
}

builtin WasmMemoryGrow(memIndex: int32, numPages: int32): int32 {
  dcheck(IsValidPositiveSmi(ChangeInt32ToIntPtr(memIndex)));
  if (!IsValidPositiveSmi(ChangeInt32ToIntPtr(numPages)))
    return Int32Constant(-1);
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const context: NativeContext = LoadContextFromInstance(instance);
  const result: Smi = runtime::WasmMemoryGrow(
      context, instance, SmiFromInt32(memIndex), SmiFromInt32(numPages));
  return SmiToInt32(result);
}

builtin WasmTableInit(
    dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, tableIndex: Smi,
    segmentIndex: Smi): JSAny {
  try {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds;
    const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds;
    const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds;
    tail runtime::WasmTableInit(
        LoadContextFromInstance(instance), instance, tableIndex, segmentIndex,
        dst, src, size);
  } label TableOutOfBounds deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableCopy(
    dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, dstTable: Smi,
    srcTable: Smi): JSAny {
  try {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds;
    const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds;
    const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds;
    tail runtime::WasmTableCopy(
        LoadContextFromInstance(instance), instance, dstTable, srcTable, dst,
        src, size);
  } label TableOutOfBounds deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableFill(
    table: Smi, startRaw: uint32, countRaw: uint32, value: Object): JSAny {
  try {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const start: Smi =
        Convert<PositiveSmi>(startRaw) otherwise TableOutOfBounds;
    const count: Smi =
        Convert<PositiveSmi>(countRaw) otherwise TableOutOfBounds;
    tail runtime::WasmTableFill(
        LoadContextFromInstance(instance), instance, table, start, value,
        count);
  } label TableOutOfBounds deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableGrow(table: Smi, deltaRaw: uint32, value: Object): Smi {
  try {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const delta: Smi =
        Convert<PositiveSmi>(deltaRaw) otherwise TableOutOfBounds;
    tail runtime::WasmTableGrow(
        LoadContextFromInstance(instance), instance, table, value, delta);
  } label TableOutOfBounds deferred {
    return -1;
  }
}

builtin WasmTableGet(tableIndex: intptr, index: int32): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    dcheck(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;

    const tables: FixedArray = LoadTablesFromInstance(instance);
    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
        LoadFixedArrayElement(tables, tableIndex));
    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
    if (entryIndex >= entriesCount) goto IndexOutOfRange;

    const entries: FixedArray = table.entries;
    const entry: Object = LoadFixedArrayElement(entries, entryIndex);
    return entry;
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableSet(tableIndex: intptr, index: int32, value: Object): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    dcheck(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;

    const tables: FixedArray = LoadTablesFromInstance(instance);
    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
        LoadFixedArrayElement(tables, tableIndex));

    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
    if (entryIndex >= entriesCount) goto IndexOutOfRange;

    const entries: FixedArray = table.entries;
    StoreFixedArrayElement(entries, entryIndex, value);
    return Undefined;
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableGetFuncRef(tableIndex: intptr, index: int32): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    dcheck(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;

    const tables: FixedArray = LoadTablesFromInstance(instance);
    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
        LoadFixedArrayElement(tables, tableIndex));
    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
    if (entryIndex >= entriesCount) goto IndexOutOfRange;

    const entries: FixedArray = table.entries;
    const entry: Object = LoadFixedArrayElement(entries, entryIndex);

    try {
      const entryObject: HeapObject =
          TaggedToHeapObject<HeapObject>(entry) otherwise ReturnEntry;
      if (IsTuple2Map(entryObject.map)) goto CallRuntime;
      goto ReturnEntry;
    } label ReturnEntry {
      return entry;
    }
  } label CallRuntime deferred {
    tail runtime::WasmFunctionTableGet(
        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
        SmiFromIntPtr(entryIndex));
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmTableSetFuncRef(tableIndex: intptr, index: int32, value: Object):
    Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    dcheck(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;

    const tables: FixedArray = LoadTablesFromInstance(instance);
    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
        LoadFixedArrayElement(tables, tableIndex));

    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
    if (entryIndex >= entriesCount) goto IndexOutOfRange;

    tail runtime::WasmFunctionTableSet(
        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
        SmiFromIntPtr(entryIndex), value);
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
  }
}

builtin WasmRefFunc(index: uint32): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  try {
    const table: FixedArray = LoadInternalFunctionsFromInstance(instance);
    const functionIndex: intptr = Signed(ChangeUint32ToWord(index));
    const result: Object = LoadFixedArrayElement(table, functionIndex);
    // {result} is either a funcref or nullptr. A Smi check is the fastest
    // way to distinguish these two cases.
    if (TaggedIsSmi(result)) goto CallRuntime;
    return result;
  } label CallRuntime deferred {
    tail runtime::WasmRefFunc(
        LoadContextFromInstance(instance), instance, SmiFromUint32(index));
  }
}

builtin WasmInternalFunctionCreateExternal(
    context: Context, func: WasmInternalFunction): JSFunction {
  return runtime::WasmInternalFunctionCreateExternal(context, func);
}

builtin WasmAllocateZeroedFixedArray(size: intptr): FixedArray {
  if (size == 0) return kEmptyFixedArray;
  const result = UnsafeCast<FixedArray>(AllocateFixedArray(
      ElementsKind::PACKED_ELEMENTS, size, AllocationFlag::kNone));
  FillEntireFixedArrayWithSmiZero(ElementsKind::PACKED_ELEMENTS, result, size);
  return result;
}

builtin WasmAllocateFixedArray(size: intptr): FixedArray {
  if (size == 0) return kEmptyFixedArray;
  return UnsafeCast<FixedArray>(AllocateFixedArray(
      ElementsKind::PACKED_ELEMENTS, size, AllocationFlag::kNone));
}

builtin WasmThrow(tag: Object, values: FixedArray): JSAny {
  tail runtime::WasmThrow(LoadContextFromFrame(), tag, values);
}

builtin WasmRethrow(exception: Object): JSAny {
  if (exception == Null) tail ThrowWasmTrapRethrowNull();
  tail runtime::WasmReThrow(LoadContextFromFrame(), exception);
}

// We need this for frames that do not have the instance in the parameters.
// Currently, this is CapiCallWrapper frames.
builtin WasmRethrowExplicitContext(
    exception: Object, explicitContext: Context): JSAny {
  if (exception == Null) tail ThrowWasmTrapRethrowNull();
  tail runtime::WasmReThrow(explicitContext, exception);
}

builtin WasmTriggerTierUp(): JSAny {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  tail runtime::WasmTriggerTierUp(LoadContextFromFrame(), instance);
}

builtin WasmStackGuard(): JSAny {
  tail runtime::WasmStackGuard(LoadContextFromFrame());
}

builtin WasmStackOverflow(): JSAny {
  tail runtime::ThrowWasmStackOverflow(LoadContextFromFrame());
}

builtin WasmTraceMemory(info: Smi): JSAny {
  tail runtime::WasmTraceMemory(LoadContextFromFrame(), info);
}

builtin WasmTraceEnter(): JSAny {
  tail runtime::WasmTraceEnter(LoadContextFromFrame());
}

builtin WasmTraceExit(info: Smi): JSAny {
  tail runtime::WasmTraceExit(LoadContextFromFrame(), info);
}

builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray {
  const map: Map = GetFastPackedElementsJSArrayMap();
  return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size);
}

builtin WasmAllocateStructWithRtt(rtt: Map, instanceSize: int32): HeapObject {
  const result: HeapObject = unsafe::Allocate(Convert<intptr>(instanceSize));
  *UnsafeConstCast(&result.map) = rtt;
  // TODO(ishell): consider removing properties_or_hash field from WasmObjects.
  %RawDownCast<WasmStruct>(result).properties_or_hash = kEmptyFixedArray;
  return result;
}

builtin WasmAllocateArray_Uninitialized(
    rtt: Map, length: uint32, elementSize: uint32): WasmArray {
  // instanceSize = RoundUp(elementSize * length, kObjectAlignment)
  //              + WasmArray::kHeaderSize
  const instanceSize: intptr =
      torque_internal::AlignTagged(
          Convert<intptr>(length) * Convert<intptr>(elementSize)) +
      Convert<intptr>(kWasmArrayHeaderSize);
  const result: HeapObject = unsafe::Allocate(instanceSize);
  *UnsafeConstCast(&result.map) = rtt;
  // TODO(ishell): consider removing properties_or_hash field from WasmObjects.
  %RawDownCast<WasmArray>(result).properties_or_hash = kEmptyFixedArray;
  %RawDownCast<WasmArray>(result).length = length;
  return %RawDownCast<WasmArray>(result);
}

builtin WasmArrayNewSegment(
    segmentIndex: uint32, offset: uint32, length: uint32, isElement: Smi,
    rtt: Map): Object {
  const instance = LoadInstanceFromFrame();
  try {
    const smiOffset = Convert<PositiveSmi>(offset) otherwise SegmentOutOfBounds;
    const smiLength = Convert<PositiveSmi>(length) otherwise ArrayTooLarge;
    tail runtime::WasmArrayNewSegment(
        LoadContextFromInstance(instance), instance,
        SmiFromUint32(segmentIndex), smiOffset, smiLength, rtt);
  } label SegmentOutOfBounds {
    if (isElement == SmiConstant(0)) {
      tail ThrowWasmTrapDataSegmentOutOfBounds();
    } else {
      tail ThrowWasmTrapElementSegmentOutOfBounds();
    }
  } label ArrayTooLarge {
    tail ThrowWasmTrapArrayTooLarge();
  }
}

// {segmentIndex} has to be tagged as a possible stack parameter.
builtin WasmArrayInitSegment(
    arrayIndex: uint32, segmentOffset: uint32, length: uint32,
    segmentIndex: Smi, isElement: Smi, arrayRaw: HeapObject): JSAny {
  const instance = LoadInstanceFromFrame();
  if (arrayRaw == kWasmNull) {
    tail ThrowWasmTrapNullDereference();
  }
  const array = %RawDownCast<WasmArray>(arrayRaw);
  try {
    const smiArrayIndex =
        Convert<PositiveSmi>(arrayIndex) otherwise ArrayOutOfBounds;
    const smiOffset =
        Convert<PositiveSmi>(segmentOffset) otherwise SegmentOutOfBounds;
    const smiLength = Convert<PositiveSmi>(length) otherwise ArrayOutOfBounds;

    tail runtime::WasmArrayInitSegment(
        LoadContextFromInstance(instance), instance, segmentIndex, array,
        smiArrayIndex, smiOffset, smiLength);
  } label SegmentOutOfBounds {
    if (isElement == SmiConstant(0)) {
      tail ThrowWasmTrapDataSegmentOutOfBounds();
    } else {
      tail ThrowWasmTrapElementSegmentOutOfBounds();
    }
  } label ArrayOutOfBounds {
    tail ThrowWasmTrapArrayOutOfBounds();
  }
}

// We put all uint32 parameters at the beginning so that they are assigned to
// registers.
builtin WasmArrayCopyWithChecks(
    dstIndex: uint32, srcIndex: uint32, length: uint32, dstObject: Object,
    srcObject: Object): JSAny {
  if (dstObject == kWasmNull) tail ThrowWasmTrapNullDereference();
  if (srcObject == kWasmNull) tail ThrowWasmTrapNullDereference();
  const dstArray = UnsafeCast<WasmArray>(dstObject);
  const srcArray = UnsafeCast<WasmArray>(srcObject);
  // Check that the end of the copying range is in-bounds and that the range
  // does not overflow.
  if (dstIndex + length > dstArray.length || dstIndex + length < dstIndex ||
      srcIndex + length > srcArray.length || srcIndex + length < srcIndex) {
    tail ThrowWasmTrapArrayOutOfBounds();
  }
  if (length == 0) return Undefined;
  tail runtime::WasmArrayCopy(
      LoadContextFromFrame(), dstArray, SmiFromUint32(dstIndex), srcArray,
      SmiFromUint32(srcIndex), SmiFromUint32(length));
}

builtin WasmArrayCopy(
    dstIndex: uint32, srcIndex: uint32, length: uint32, dstObject: Object,
    srcObject: Object): JSAny {
  if (dstObject == kWasmNull) tail ThrowWasmTrapNullDereference();
  if (srcObject == kWasmNull) tail ThrowWasmTrapNullDereference();
  if (length == 0) return Undefined;
  tail runtime::WasmArrayCopy(
      LoadContextFromFrame(), UnsafeCast<WasmArray>(dstObject),
      SmiFromUint32(dstIndex), UnsafeCast<WasmArray>(srcObject),
      SmiFromUint32(srcIndex), SmiFromUint32(length));
}

builtin WasmUint32ToNumber(value: uint32): Number {
  return ChangeUint32ToTagged(value);
}

builtin UintPtr53ToNumber(value: uintptr): Number {
  if (value <= kSmiMaxValue) return Convert<Smi>(Convert<intptr>(value));
  const valueFloat = ChangeUintPtrToFloat64(value);
  // Values need to be within [0..2^53], such that they can be represented as
  // float64.
  dcheck(ChangeFloat64ToUintPtr(valueFloat) == value);
  return AllocateHeapNumberWithValue(valueFloat);
}

extern builtin I64ToBigInt(intptr): BigInt;
extern builtin I32PairToBigInt(/*low*/ intptr, /*high*/ intptr): BigInt;

builtin WasmAtomicNotify(memoryIndex: int32, offset: uintptr, count: uint32):
    uint32 {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const result: Smi = runtime::WasmAtomicNotify(
      LoadContextFromInstance(instance), instance, SmiFromInt32(memoryIndex),
      UintPtr53ToNumber(offset), WasmUint32ToNumber(count));
  return Unsigned(SmiToInt32(result));
}

builtin WasmI32AtomicWait(
    memIndex: int32, offset: uintptr, expectedValue: int32,
    timeout: BigInt): uint32 {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const result: Smi = runtime::WasmI32AtomicWait(
      LoadContextFromInstance(instance), instance, SmiFromInt32(memIndex),
      UintPtr53ToNumber(offset), ChangeInt32ToTagged(expectedValue), timeout);
  return Unsigned(SmiToInt32(result));
}

builtin WasmI64AtomicWait(
    memIndex: int32, offset: uintptr, expectedValue: BigInt,
    timeout: BigInt): uint32 {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const result: Smi = runtime::WasmI64AtomicWait(
      LoadContextFromInstance(instance), instance, SmiFromInt32(memIndex),
      UintPtr53ToNumber(offset), expectedValue, timeout);
  return Unsigned(SmiToInt32(result));
}

// Type feedback collection support for `call_ref`.

extern macro LoadCodeInstructionStart(Code): RawPtr;

struct TargetAndInstance {
  target: RawPtr;
  instance: HeapObject;  // WasmInstanceObject or WasmApiFunctionRef
}

macro GetTargetAndInstance(funcref: WasmInternalFunction):
    TargetAndInstance {
  const ref = funcref.ref;
  let target = funcref.call_target_ptr;
  if (Signed(target) == IntPtrConstant(0)) {
    target = LoadCodeInstructionStart(funcref.code);
  }
  return TargetAndInstance{target: target, instance: ref};
}

// Vector format:
// Two slots per call_ref instruction. These slots' values can be:
// - uninitialized: (0, <unused>). Note: we use {0} as the sentinel because
//   it also works as default for vector slots used as counts.
// - monomorphic: (funcref, count (smi)). The second slot is a counter for how
//   often the funcref in the first slot has been seen.
// - polymorphic: (fixed_array, <unused>). In this case, the array
//   contains 2..kMaxPolymorphism pairs (funcref, count (smi))
// - megamorphic: ("megamorphic" sentinel, <unused>)
//
// TODO(rstz): The counter might overflow if it exceeds the range of a Smi.
// This can lead to incorrect inlining decisions.
builtin CallRefIC(
    vector: FixedArray, index: intptr,
    funcref: WasmInternalFunction): TargetAndInstance {
  const value = vector.objects[index];
  if (value == funcref) {
    // Monomorphic hit. Check for this case first to maximize its performance.
    const count = UnsafeCast<Smi>(vector.objects[index + 1]) + SmiConstant(1);
    vector.objects[index + 1] = count;
    return GetTargetAndInstance(funcref);
  }
  // Check for polymorphic hit; its performance is second-most-important.
  if (Is<FixedArray>(value)) {
    const entries = UnsafeCast<FixedArray>(value);
    for (let i: intptr = 0; i < entries.length_intptr; i += 2) {
      if (entries.objects[i] == funcref) {
        // Polymorphic hit.
        const count = UnsafeCast<Smi>(entries.objects[i + 1]) + SmiConstant(1);
        entries.objects[i + 1] = count;
        return GetTargetAndInstance(funcref);
      }
    }
  }
  // All other cases are some sort of miss and must compute the target/
  // instance. They all fall through to returning the computed data.
  const result = GetTargetAndInstance(funcref);
  if (TaggedEqual(value, SmiConstant(0))) {
    // Was uninitialized.
    vector.objects[index] = funcref;
    vector.objects[index + 1] = SmiConstant(1);
  } else if (Is<FixedArray>(value)) {
    // Polymorphic miss.
    const entries = UnsafeCast<FixedArray>(value);
    const kMaxSlots = kMaxPolymorphism * 2;  // 2 slots per entry.
    if (entries.length == SmiConstant(kMaxSlots)) {
      vector.objects[index] = ic::kMegamorphicSymbol;
      vector.objects[index + 1] = ic::kMegamorphicSymbol;
    } else {
      const newEntries = UnsafeCast<FixedArray>(AllocateFixedArray(
          ElementsKind::PACKED_ELEMENTS, entries.length_intptr + 2,
          AllocationFlag::kNone));
      for (let i: intptr = 0; i < entries.length_intptr; i++) {
        newEntries.objects[i] = entries.objects[i];
      }
      const newIndex = entries.length_intptr;
      newEntries.objects[newIndex] = funcref;
      newEntries.objects[newIndex + 1] = SmiConstant(1);
      vector.objects[index] = newEntries;
    }
  } else if (Is<WasmInternalFunction>(value)) {
    // Monomorphic miss.
    const newEntries = UnsafeCast<FixedArray>(AllocateFixedArray(
        ElementsKind::PACKED_ELEMENTS, 4, AllocationFlag::kNone));
    newEntries.objects[0] = value;
    newEntries.objects[1] = vector.objects[index + 1];
    newEntries.objects[2] = funcref;
    newEntries.objects[3] = SmiConstant(1);
    vector.objects[index] = newEntries;
    // Clear the first entry's counter; the specific value we write doesn't
    // matter.
    vector.objects[index + 1] = Undefined;
  }
  // The "ic::IsMegamorphic(value)" case doesn't need to do anything.
  return result;
}

extern macro TryHasOwnProperty(HeapObject, Map, InstanceType, Name): never
    labels Found, NotFound, Bailout;
type OnNonExistent constexpr 'OnNonExistent';
const kReturnUndefined: constexpr OnNonExistent
    generates 'OnNonExistent::kReturnUndefined';
extern macro SmiConstant(constexpr OnNonExistent): Smi;
extern transitioning builtin GetPropertyWithReceiver(
    implicit context: Context)(JSAny, Name, JSAny, Smi): JSAny;

transitioning builtin WasmGetOwnProperty(
    implicit context: Context)(object: Object, uniqueName: Name): JSAny {
  try {
    const heapObject: HeapObject =
        TaggedToHeapObject(object) otherwise NotFound;
    const receiver: JSReceiver =
        Cast<JSReceiver>(heapObject) otherwise NotFound;
    try {
      TryHasOwnProperty(
          receiver, receiver.map, receiver.instanceType, uniqueName)
          otherwise Found, NotFound, NotFound;
    } label Found {
      tail GetPropertyWithReceiver(
          receiver, uniqueName, receiver, SmiConstant(kReturnUndefined));
    }
  } label NotFound deferred {
    return Undefined;
  }
}

// Trap builtins.

builtin WasmTrap(error: Smi): JSAny {
  tail runtime::ThrowWasmError(LoadContextFromWasmOrJsFrame(), error);
}

builtin ThrowWasmTrapUnreachable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable));
}

builtin ThrowWasmTrapMemOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapMemOutOfBounds));
}

builtin ThrowWasmTrapUnalignedAccess(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnalignedAccess));
}

builtin ThrowWasmTrapDivByZero(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivByZero));
}

builtin ThrowWasmTrapDivUnrepresentable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivUnrepresentable));
}

builtin ThrowWasmTrapRemByZero(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRemByZero));
}

builtin ThrowWasmTrapFloatUnrepresentable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFloatUnrepresentable));
}

builtin ThrowWasmTrapFuncSigMismatch(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncSigMismatch));
}

builtin ThrowWasmTrapDataSegmentOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDataSegmentOutOfBounds));
}

builtin ThrowWasmTrapElementSegmentOutOfBounds(): JSAny {
  tail WasmTrap(
      SmiConstant(MessageTemplate::kWasmTrapElementSegmentOutOfBounds));
}

builtin ThrowWasmTrapTableOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds));
}

builtin ThrowWasmTrapRethrowNull(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNull));
}

builtin ThrowWasmTrapNullDereference(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference));
}

builtin ThrowWasmTrapIllegalCast(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast));
}

builtin ThrowWasmTrapArrayOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds));
}

builtin ThrowWasmTrapArrayTooLarge(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayTooLarge));
}

builtin ThrowWasmTrapStringOffsetOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapStringOffsetOutOfBounds));
}

macro WasmTypeInfo(map: Map): WasmTypeInfo {
  return UnsafeCast<WasmTypeInfo>(
      map.constructor_or_back_pointer_or_native_context);
}

const kWasmI16ValueType: constexpr int32
    generates 'wasm::ValueType::Primitive(wasm::kI16).raw_bit_field()';
const kWasmI8ValueType: constexpr int32
    generates 'wasm::ValueType::Primitive(wasm::kI8).raw_bit_field()';

const kWasmArrayTypeRepOffset:
    constexpr intptr generates 'wasm::ArrayType::kRepOffset';
const kWasmValueTypeBitFieldOffset:
    constexpr intptr generates 'wasm::ValueType::kBitFieldOffset';

macro IsWord16WasmArrayMap(map: Map): bool {
  const arrayTypePtr: RawPtr<int32> = %RawDownCast<RawPtr<int32>>(
      WasmTypeInfo(map).native_type_ptr + kWasmArrayTypeRepOffset +
      kWasmValueTypeBitFieldOffset);
  const arrayTypeRef: &int32 =
      torque_internal::unsafe::NewOffHeapReference(arrayTypePtr);
  return *arrayTypeRef == kWasmI16ValueType;
}

macro IsWord8WasmArrayMap(map: Map): bool {
  const arrayTypePtr: RawPtr<int32> = %RawDownCast<RawPtr<int32>>(
      WasmTypeInfo(map).native_type_ptr + kWasmArrayTypeRepOffset +
      kWasmValueTypeBitFieldOffset);
  const arrayTypeRef: &int32 =
      torque_internal::unsafe::NewOffHeapReference(arrayTypePtr);
  return *arrayTypeRef == kWasmI8ValueType;
}

macro GetRefAt<T: type, From: type>(base: From, offset: intptr): &T {
  return torque_internal::unsafe::NewOffHeapReference<T>(
      %RawDownCast<RawPtr<T>>(base + offset));
}

extern macro LoadPointerFromRootRegister(intptr): RawPtr;

const kThreadInWasmFlagAddressOffset: constexpr intptr
    generates 'Isolate::thread_in_wasm_flag_address_offset()';

const kActiveSuspenderOffset: constexpr intptr
    generates 'IsolateData::root_slot_offset(RootIndex::kActiveSuspender)';

macro ModifyThreadInWasmFlag(newValue: int32): void {
  const threadInWasmFlagAddress =
      LoadPointerFromRootRegister(kThreadInWasmFlagAddressOffset);
  const threadInWasmFlagRef = GetRefAt<int32>(threadInWasmFlagAddress, 0);
  *threadInWasmFlagRef = newValue;
}

macro ModifyWasmToJSCounter(increment: int32): void {
  const rootSlot = LoadPointerFromRootRegister(kActiveSuspenderOffset);

  const rawSuspender = BitcastWordToTagged(rootSlot);
  typeswitch (rawSuspender) {
    case (activeSuspender: WasmSuspenderObject): {
      const current = Signed(activeSuspender.wasm_to_js_counter);
      activeSuspender.wasm_to_js_counter = Unsigned(current + increment);
    }
    case (Object): {
      // Nothing to do, but the case is needed by the Torque compiler.
    }
  }
}

builtin WasmStringNewWtf8(
    offset: uint32, size: uint32, memory: Smi, utf8Variant: Smi): String|Null {
  const instance = LoadInstanceFromFrame();
  tail runtime::WasmStringNewWtf8(
      LoadContextFromInstance(instance), instance, memory, utf8Variant,
      WasmUint32ToNumber(offset), WasmUint32ToNumber(size));
}
builtin WasmStringNewWtf8Array(
    start: uint32, end: uint32, array: WasmArray, utf8Variant: Smi): String
    |Null {
  // This can be called from Wasm and from WebAssembly.String.* JS builtins.
  const context = LoadContextFromWasmOrJsFrame();
  try {
    if (array.length < end) goto OffsetOutOfRange;
    if (end < start) goto OffsetOutOfRange;
    tail runtime::WasmStringNewWtf8Array(
        context, utf8Variant, array, SmiFromUint32(start), SmiFromUint32(end));
  } label OffsetOutOfRange deferred {
    const error = MessageTemplate::kWasmTrapArrayOutOfBounds;
    runtime::ThrowWasmError(context, SmiConstant(error));
  }
}
builtin WasmStringNewWtf16(memory: uint32, offset: uint32, size: uint32):
    String {
  const instance = LoadInstanceFromFrame();
  tail runtime::WasmStringNewWtf16(
      LoadContextFromInstance(instance), instance, SmiFromUint32(memory),
      WasmUint32ToNumber(offset), WasmUint32ToNumber(size));
}

struct TwoByteToOneByteIterator {
  macro Next(): char8 labels NoMore {
    if (this.start == this.end) goto NoMore;
    const raw: char16 = *torque_internal::unsafe::NewReference<char16>(
        this.object, this.start);
    const result: char8 = %RawDownCast<char8>(raw & 0xFF);
    this.start += 2;
    return result;
  }

  object: HeapObject|TaggedZeroPattern;
  start: intptr;
  end: intptr;
}

macro StringFromTwoByteSlice(length: uint32, slice: ConstSlice<char16>):
    String {
  // Ideas for additional future improvements:
  // (1) We could add a fast path for very short strings, e.g. <= 8 chars,
  //     and just allocate two-byte strings for them. That would save time
  //     here, and would only waste a couple of bytes at most. A concern is
  //     that such strings couldn't take one-byte fast paths later on, e.g.
  //     in toLower/toUpper case conversions.
  // (2) We could load more than one array element at a time, e.g. using
  //     intptr-wide loads, or possibly even wider SIMD instructions. We'd
  //     have to make sure that non-aligned start offsets are handled,
  //     and the implementation would become more platform-specific.
  // (3) We could shift the problem around by allocating two-byte strings
  //     here and checking whether they're one-byte-compatible later, e.g.
  //     when promoting them from new to old space. Drawback: rewriting
  //     strings to different maps isn't great for optimized code that's
  //     based on collected type feedback, or that wants to elide duplicate
  //     map checks within the function.
  // (4) We could allocate space for a two-byte string, then optimistically
  //     start writing one-byte characters into it, and then either restart
  //     in two-byte mode if needed, or return the over-allocated bytes to
  //     the allocator in the end.
  // (5) We could standardize a `string.new_ascii_array` instruction, which
  //     could safely produce one-byte strings without checking characters.
  //     See https://github.com/WebAssembly/stringref/issues/53.

  try {
    // To reduce the amount of branching, check 8 code units at a time. The
    // tradeoff for choosing 8 is that we want to check for early termination
    // of the loop often (to avoid unnecessary work) but not too often
    // (because each check has a cost).
    let i: intptr = 0;
    const intptrLength = slice.length;
    const eightElementLoopEnd = intptrLength - 8;
    while (i <= eightElementLoopEnd) {
      const bits = Convert<uint32>(*slice.UncheckedAtIndex(i)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 1)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 2)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 3)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 4)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 5)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 6)) |
          Convert<uint32>(*slice.UncheckedAtIndex(i + 7));
      if (bits > 0xFF) goto TwoByte;
      i += 8;
    }
    let bits: uint32 = 0;
    while (i < intptrLength) {
      bits |= Convert<uint32>(*slice.UncheckedAtIndex(i));
      i += 1;
    }
    if (bits > 0xFF) goto TwoByte;
  } label TwoByte {
    return AllocateSeqTwoByteString(length, slice.Iterator());
  }

  const end = slice.offset + torque_internal::TimesSizeOf<char16>(slice.length);
  return AllocateNonEmptySeqOneByteString(length, TwoByteToOneByteIterator{
    object: slice.object,
    start: slice.offset,
    end: end
  });
}

builtin WasmStringNewWtf16Array(array: WasmArray, start: uint32, end: uint32):
    String {
  try {
    if (array.length < end) goto OffsetOutOfRange;
    if (end < start) goto OffsetOutOfRange;
    const length: uint32 = end - start;
    if (length == 0) return kEmptyString;
    if (length == 1) {
      const offset = kWasmArrayHeaderSize +
          torque_internal::TimesSizeOf<char16>(Convert<intptr>(start));
      const code: char16 = *torque_internal::unsafe::NewReference<char16>(
          array, offset);
      // This makes sure we check the SingleCharacterStringTable.
      return StringFromSingleCharCode(code);
    }
    // Calling into the runtime has overhead, but once we're there it's faster,
    // so it pays off for long strings. The threshold has been determined
    // experimentally.
    if (length >= 32) goto Runtime;
    const intptrLength = Convert<intptr>(length);
    const arrayContent = torque_internal::unsafe::NewConstSlice<char16>(
        array, kWasmArrayHeaderSize, Convert<intptr>(array.length));
    const substring =
        Subslice(arrayContent, Convert<intptr>(start), intptrLength)
        otherwise goto OffsetOutOfRange;

    return StringFromTwoByteSlice(length, substring);
  } label OffsetOutOfRange deferred {
    // This can be called from Wasm and from WebAssembly.String.* JS builtins.
    const context = LoadContextFromWasmOrJsFrame();
    const error = MessageTemplate::kWasmTrapArrayOutOfBounds;
    runtime::ThrowWasmError(context, SmiConstant(error));
  } label Runtime deferred {
    const context = LoadContextFromWasmOrJsFrame();
    tail runtime::WasmStringNewWtf16Array(
        context, array, SmiFromUint32(start), SmiFromUint32(end));
  }
}

// For imports based string constants.
// Always returns a String if it didn't trap; typed "JSAny" to satisfy
// Torque's type checker for tail calls.
builtin WasmStringFromDataSegment(
    segmentLength: uint32, arrayStart: uint32, arrayEnd: uint32,
    segmentIndex: Smi, segmentOffset: Smi): JSAny {
  const instance = LoadInstanceFromFrame();
  try {
    const segmentOffsetU: uint32 = Unsigned(SmiToInt32(segmentOffset));
    if (segmentLength > Convert<uint32>(kSmiMax) - segmentOffsetU) {
      goto SegmentOOB;
    }
    if (arrayStart > segmentLength) goto ArrayOutOfBounds;
    if (arrayEnd < arrayStart) goto ArrayOutOfBounds;
    const arrayLength = arrayEnd - arrayStart;
    if (arrayLength > segmentLength - arrayStart) goto ArrayOutOfBounds;
    const smiOffset = Convert<PositiveSmi>(segmentOffsetU + arrayStart)
        otherwise SegmentOOB;
    const smiLength = Convert<PositiveSmi>(arrayLength) otherwise SegmentOOB;
    tail runtime::WasmStringNewSegmentWtf8(
        LoadContextFromInstance(instance), instance, segmentIndex, smiOffset,
        smiLength);
  } label SegmentOOB deferred {
    tail ThrowWasmTrapElementSegmentOutOfBounds();
  } label ArrayOutOfBounds deferred {
    tail ThrowWasmTrapArrayOutOfBounds();
  }
}

// Contract: input is any string, output is a string that the TF operator
// "StringPrepareForGetCodeunit" can handle.
builtin WasmStringAsWtf16(str: String): String {
  const cons = Cast<ConsString>(str) otherwise return str;
  return Flatten(cons);
}

builtin WasmStringConst(index: uint32): String {
  const instance = LoadInstanceFromFrame();
  tail runtime::WasmStringConst(
      LoadContextFromInstance(instance), instance, SmiFromUint32(index));
}
builtin WasmStringMeasureUtf8(string: String): int32 {
  const result = runtime::WasmStringMeasureUtf8(LoadContextFromFrame(), string);
  return Signed(ChangeNumberToUint32(result));
}
builtin WasmStringMeasureWtf8(string: String): int32 {
  const result = runtime::WasmStringMeasureWtf8(LoadContextFromFrame(), string);
  return Signed(ChangeNumberToUint32(result));
}
builtin WasmStringEncodeWtf8(
    string: String, offset: uint32, memory: Smi, utf8Variant: Smi): uint32 {
  const instance = LoadInstanceFromFrame();
  const result = runtime::WasmStringEncodeWtf8(
      LoadContextFromInstance(instance), instance, memory, utf8Variant, string,
      WasmUint32ToNumber(offset));
  return ChangeNumberToUint32(result);
}
builtin WasmStringEncodeWtf8Array(
    string: String, array: WasmArray, start: uint32, utf8Variant: Smi): uint32 {
  const instance = LoadInstanceFromFrame();
  const result = runtime::WasmStringEncodeWtf8Array(
      LoadContextFromInstance(instance), utf8Variant, string, array,
      WasmUint32ToNumber(start));
  return ChangeNumberToUint32(result);
}
builtin WasmStringEncodeWtf16(string: String, offset: uint32, memory: Smi):
    uint32 {
  const instance = LoadInstanceFromFrame();
  runtime::WasmStringEncodeWtf16(
      LoadContextFromInstance(instance), instance, memory, string,
      WasmUint32ToNumber(offset), SmiConstant(0), SmiFromInt32(string.length));
  return Unsigned(string.length);
}
builtin WasmStringEncodeWtf16Array(
    string: String, array: WasmArray, start: uint32): uint32 {
  try {
    if (start > array.length) goto OffsetOutOfRange;
    if (array.length - start < Unsigned(string.length)) goto OffsetOutOfRange;

    const byteOffset: intptr = kWasmArrayHeaderSize +
        torque_internal::TimesSizeOf<char16>(Convert<intptr>(start));
    const arrayContent = torque_internal::unsafe::NewMutableSlice<char16>(
        array, byteOffset, string.length_intptr);
    try {
      StringToSlice(string) otherwise OneByte, TwoByte;
    } label OneByte(slice: ConstSlice<char8>) {
      let fromIt = slice.Iterator();
      let toIt = arrayContent.Iterator();
      while (true) {
        let toRef = toIt.NextReference() otherwise break;
        *toRef = %RawDownCast<char16>(Convert<uint16>(fromIt.NextNotEmpty()));
      }
    } label TwoByte(slice: ConstSlice<char16>) {
      let fromIt = slice.Iterator();
      let toIt = arrayContent.Iterator();
      while (true) {
        let toRef = toIt.NextReference() otherwise break;
        *toRef = fromIt.NextNotEmpty();
      }
    }
    return Unsigned(string.length);
  } label OffsetOutOfRange deferred {
    const error = MessageTemplate::kWasmTrapArrayOutOfBounds;
    runtime::ThrowWasmError(LoadContextFromWasmOrJsFrame(), SmiConstant(error));
  }
}

builtin ThrowToLowerCaseCalledOnNull(): JSAny {
  const context = LoadContextFromFrame();
  const error = MessageTemplate::kCalledOnNullOrUndefined;
  const name = StringConstant('String.prototype.toLowerCase');
  runtime::WasmThrowTypeError(context, SmiConstant(error), name);
}

builtin ThrowIndexOfCalledOnNull(): JSAny {
  const context = LoadContextFromFrame();
  const error = MessageTemplate::kCalledOnNullOrUndefined;
  const name = StringConstant('String.prototype.indexOf');
  runtime::WasmThrowTypeError(context, SmiConstant(error), name);
}

builtin ThrowDataViewGetInt32DetachedError(): JSAny {
  const context = LoadContextFromFrame();
  const error = MessageTemplate::kDetachedOperation;
  const name = StringConstant('DataView.prototype.getInt32');
  runtime::WasmThrowTypeError(context, SmiConstant(error), name);
}

builtin ThrowDataViewGetInt32OutOfBounds(): JSAny {
  const context = LoadContextFromFrame();
  const error = MessageTemplate::kInvalidDataViewAccessorOffset;
  runtime::WasmThrowRangeError(context, SmiConstant(error));
}

builtin ThrowDataViewGetInt32TypeError(value: JSAny): JSAny {
  const context = LoadContextFromFrame();
  const error = MessageTemplate::kIncompatibleMethodReceiver;
  const name = StringConstant('DataView.prototype.getInt32');
  runtime::WasmThrowTypeErrorTwoArgs(context, SmiConstant(error), name, value);
}

builtin WasmStringConcat(a: String, b: String): String {
  const context = LoadContextFromFrame();
  tail StringAdd_CheckNone(a, b);
}

extern builtin StringEqual(NoContext, String, String, intptr): Boolean;

builtin WasmStringEqual(a: String, b: String): int32 {
  if (TaggedEqual(a, b)) return 1;
  if (a.length != b.length) return 0;
  if (StringEqual(kNoContext, a, b, a.length_intptr) == True) {
    return 1;
  }
  return 0;
}

builtin WasmStringIsUSVSequence(str: String): int32 {
  if (IsOneByteStringInstanceType(str.instanceType)) return 1;
  const length = runtime::WasmStringMeasureUtf8(LoadContextFromFrame(), str);
  if (Signed(ChangeNumberToUint32(length)) < 0) return 0;
  return 1;
}

builtin WasmStringAsWtf8(str: String): ByteArray {
  tail runtime::WasmStringAsWtf8(LoadContextFromFrame(), str);
}

macro IsWtf8CodepointStart(view: ByteArray, pos: uint32): bool {
  // We're already at the start of a codepoint if the current byte
  // doesn't start with 0b10xxxxxx.
  return (view.bytes[Convert<uintptr>(pos)] & 0xc0) != 0x80;
}
macro AlignWtf8PositionForward(view: ByteArray, pos: uint32): uint32 {
  const length = Unsigned(SmiToInt32(view.length));
  if (pos >= length) return length;

  if (IsWtf8CodepointStart(view, pos)) return pos;

  // Otherwise `pos` is part of a multibyte codepoint, and is not the
  // leading byte.  The next codepoint will start at pos + 1, pos + 2,
  // or pos + 3.
  if (pos + 1 == length) return length;
  if (IsWtf8CodepointStart(view, pos + 1)) return pos + 1;

  if (pos + 2 == length) return length;
  if (IsWtf8CodepointStart(view, pos + 2)) return pos + 2;

  return pos + 3;
}
macro AlignWtf8PositionBackward(view: ByteArray, pos: uint32): uint32 {
  // Return the highest offset that starts a codepoint which is not
  // greater than pos.  Preconditions: pos in [0, view.length), view
  // contains well-formed WTF-8.
  if (IsWtf8CodepointStart(view, pos)) return pos;
  if (IsWtf8CodepointStart(view, pos - 1)) return pos - 1;
  if (IsWtf8CodepointStart(view, pos - 2)) return pos - 2;
  return pos - 3;
}
builtin WasmStringViewWtf8Advance(view: ByteArray, pos: uint32, bytes: uint32):
    uint32 {
  const clampedPos = AlignWtf8PositionForward(view, pos);
  if (bytes == 0) return clampedPos;
  const length = Unsigned(SmiToInt32(view.length));
  if (bytes >= length - clampedPos) return length;
  return AlignWtf8PositionBackward(view, clampedPos + bytes);
}
struct NewPositionAndBytesWritten {
  newPosition: uintptr;
  bytesWritten: uintptr;
}
builtin WasmStringViewWtf8Encode(
    addr: uint32, pos: uint32, bytes: uint32, view: ByteArray, memory: Smi,
    utf8Variant: Smi): NewPositionAndBytesWritten {
  const start = WasmStringViewWtf8Advance(view, pos, 0);
  const end = WasmStringViewWtf8Advance(view, start, bytes);
  const instance = LoadInstanceFromFrame();
  const context = LoadContextFromInstance(instance);

  // kMaxArgs in code-assembler.cc:CallRunTimeImpl is currently limited
  // to 6 arguments when calling a runtime function.  Throw away the
  // memory argument for now; when we need multi-memory we can bump
  // kMaxArgs.
  dcheck(memory == SmiFromInt32(0));

  // Always call out to run-time, to catch invalid addr.
  runtime::WasmStringViewWtf8Encode(
      context, instance, utf8Variant, view, WasmUint32ToNumber(addr),
      WasmUint32ToNumber(start), WasmUint32ToNumber(end));

  return NewPositionAndBytesWritten{
    newPosition: Convert<uintptr>(end),
    bytesWritten: Convert<uintptr>(end - start)
  };
}
builtin WasmStringViewWtf8Slice(view: ByteArray, start: uint32, end: uint32):
    String {
  const start = WasmStringViewWtf8Advance(view, start, 0);
  const end = WasmStringViewWtf8Advance(view, end, 0);

  if (end <= start) return kEmptyString;

  tail runtime::WasmStringViewWtf8Slice(
      LoadContextFromFrame(), view, WasmUint32ToNumber(start),
      WasmUint32ToNumber(end));
}
transitioning builtin WasmStringViewWtf16GetCodeUnit(
    string: String, offset: uint32): uint32 {
  try {
    if (Unsigned(string.length) <= offset) goto OffsetOutOfRange;
    const code: char16 = StringCharCodeAt(string, Convert<uintptr>(offset));
    return Convert<uint32>(code);
  } label OffsetOutOfRange deferred {
    const error = MessageTemplate::kWasmTrapStringOffsetOutOfBounds;
    runtime::ThrowWasmError(LoadContextFromFrame(), SmiConstant(error));
  }
}
builtin WasmStringViewWtf16Encode(
    offset: uint32, start: uint32, length: uint32, string: String,
    memory: Smi): uint32 {
  const instance = LoadInstanceFromFrame();
  const clampedStart =
      start < Unsigned(string.length) ? start : Unsigned(string.length);
  const maxLength = Unsigned(string.length) - clampedStart;
  const clampedLength = length < maxLength ? length : maxLength;
  runtime::WasmStringEncodeWtf16(
      LoadContextFromInstance(instance), instance, memory, string,
      WasmUint32ToNumber(offset), SmiFromUint32(clampedStart),
      SmiFromUint32(clampedLength));
  return clampedLength;
}
transitioning builtin WasmStringViewWtf16Slice(
    string: String, start: uint32, end: uint32): String {
  const length = Unsigned(string.length);
  if (start >= length) return kEmptyString;
  if (end <= start) return kEmptyString;

  // On a high level, the intended logic is:
  // (1) If start == 0 && end == string.length, return string.
  // (2) If clampedLength == 1, use a cached single-character string.
  // (3) If clampedLength < SlicedString::kMinLength, make a copy.
  // (4) If clampedLength < string.length / 2, make a copy.
  // (5) Else, create a slice.
  // The reason for having case (4) is that case (5) has the risk of keeping
  // huge parent strings alive unnecessarily, and Wasm currently doesn't have a
  // way to control that behavior, so we have to be careful.
  // The reason for having case (5) is that case (4) would lead to quadratic
  // overall behavior if code repeatedly chops off a few characters of a long
  // string, which we want to avoid.
  // The string::SubString implementation can handle cases (1), (2), (3),
  // and (5). The inline code here handles case (4), and doesn't mind if it
  // also catches some of case (3).
  const clampedEnd = end <= length ? end : length;
  const clampedLength = clampedEnd - start;
  if (clampedLength > 1 && clampedLength < length / 2) {
    try {
      // Calling into the runtime has overhead, but once we're there it's
      // faster, so it pays off for long strings.
      if (clampedLength > 32) goto Runtime;
      StringToSlice(string) otherwise OneByte, TwoByte;
    } label OneByte(slice: ConstSlice<char8>) {
      let subslice = Subslice(
          slice, Convert<intptr>(start), Convert<intptr>(clampedLength))
          otherwise unreachable;
      return AllocateNonEmptySeqOneByteString(
          clampedLength, subslice.Iterator());
    } label TwoByte(slice: ConstSlice<char16>) {
      let subslice = Subslice(
          slice, Convert<intptr>(start), Convert<intptr>(clampedLength))
          otherwise unreachable;
      return StringFromTwoByteSlice(clampedLength, subslice);
    } label Runtime deferred {
      const context = LoadContextFromWasmOrJsFrame();
      tail runtime::WasmSubstring(
          context, string, SmiFromUint32(start), SmiFromUint32(clampedLength));
    }
  }
  return string::SubString(
      string, Convert<uintptr>(start), Convert<uintptr>(clampedEnd));
}
builtin WasmStringAsIter(string: String): WasmStringViewIter {
  return new WasmStringViewIter{string: string, offset: 0, optional_padding: 0};
}
macro IsLeadSurrogate(code: char16): bool {
  return (code & 0xfc00) == 0xd800;
}
macro IsTrailSurrogate(code: char16): bool {
  return (code & 0xfc00) == 0xdc00;
}
macro CombineSurrogatePair(lead: char16, trail: char16): int32 {
  const lead32 = Convert<uint32>(lead);
  const trail32 = Convert<uint32>(trail);
  // Surrogate pairs encode codepoints in the range
  // [0x010000, 0x10FFFF].  Each surrogate has 10 bits of information in
  // the low bits.  We can combine them together with a shift-and-add,
  // then add a bias of 0x010000 - 0xD800<<10 - 0xDC00 = 0xFCA02400.
  const surrogateBias: uint32 = 0xFCA02400;
  return Signed((lead32 << 10) + trail32 + surrogateBias);
}

builtin WasmStringCodePointAt(string: String, offset: uint32): uint32 {
  try {
    if (Unsigned(string.length) <= offset) goto OffsetOutOfRange;
    const lead: char16 = StringCharCodeAt(string, Convert<uintptr>(offset));
    if (!IsLeadSurrogate(lead)) return Convert<uint32>(lead);
    const trailOffset = offset + 1;
    if (Unsigned(string.length) <= trailOffset) return Convert<uint32>(lead);
    const trail: char16 =
        StringCharCodeAt(string, Convert<uintptr>(trailOffset));
    if (!IsTrailSurrogate(trail)) return Convert<uint32>(lead);
    return Unsigned(CombineSurrogatePair(lead, trail));
  } label OffsetOutOfRange deferred {
    const error = MessageTemplate::kWasmTrapStringOffsetOutOfBounds;
    runtime::ThrowWasmError(LoadContextFromFrame(), SmiConstant(error));
  }
}

builtin WasmStringViewIterNext(view: WasmStringViewIter): int32 {
  const string = view.string;
  const offset = view.offset;
  if (offset >= Unsigned(string.length)) return -1;
  const code: char16 = StringCharCodeAt(string, Convert<uintptr>(offset));
  try {
    if (IsLeadSurrogate(code) && offset + 1 < Unsigned(string.length)) {
      goto CheckForSurrogatePair;
    }
  } label CheckForSurrogatePair deferred {
    const code2: char16 =
        StringCharCodeAt(string, Convert<uintptr>(offset + 1));
    if (IsTrailSurrogate(code2)) {
      view.offset = offset + 2;
      return CombineSurrogatePair(code, code2);
    }
  }
  view.offset = offset + 1;
  return Signed(Convert<uint32>(code));
}
builtin WasmStringViewIterAdvance(
    view: WasmStringViewIter, codepoints: uint32): uint32 {
  const string = view.string;
  let offset = view.offset;
  let advanced: uint32 = 0;
  while (advanced < codepoints) {
    if (offset == Unsigned(string.length)) break;
    advanced = advanced + 1;
    if (offset + 1 < Unsigned(string.length) &&
        IsLeadSurrogate(StringCharCodeAt(string, Convert<uintptr>(offset))) &&
        IsTrailSurrogate(
            StringCharCodeAt(string, Convert<uintptr>(offset + 1)))) {
      offset = offset + 2;
    } else {
      offset = offset + 1;
    }
  }
  view.offset = offset;
  return advanced;
}
builtin WasmStringViewIterRewind(view: WasmStringViewIter, codepoints: uint32):
    uint32 {
  const string = view.string;
  let offset = view.offset;
  let rewound: uint32 = 0;
  if (string.length == 0) return 0;
  while (rewound < codepoints) {
    if (offset == 0) break;
    rewound = rewound + 1;
    if (offset >= 2 &&
        IsTrailSurrogate(
            StringCharCodeAt(string, Convert<uintptr>(offset - 1))) &&
        IsLeadSurrogate(
            StringCharCodeAt(string, Convert<uintptr>(offset - 2)))) {
      offset = offset - 2;
    } else {
      offset = offset - 1;
    }
  }
  view.offset = offset;
  return rewound;
}
builtin WasmStringViewIterSlice(view: WasmStringViewIter, codepoints: uint32):
    String {
  const string = view.string;
  const start = view.offset;
  let end = view.offset;
  let advanced: uint32 = 0;
  while (advanced < codepoints) {
    if (end == Unsigned(string.length)) break;
    advanced = advanced + 1;
    if (end + 1 < Unsigned(string.length) &&
        IsLeadSurrogate(StringCharCodeAt(string, Convert<uintptr>(end))) &&
        IsTrailSurrogate(StringCharCodeAt(string, Convert<uintptr>(end + 1)))) {
      end = end + 2;
    } else {
      end = end + 1;
    }
  }
  return (start == end) ?
      kEmptyString :
      string::SubString(string, Convert<uintptr>(start), Convert<uintptr>(end));
}

builtin WasmIntToString(x: int32, radix: int32): String {
  if (radix == 10) {
    const smi = SmiFromInt32(x);
    const untagged = SmiToInt32(smi);
    if (x == untagged) {
      // Queries and populates the NumberToStringCache, but needs tagged
      // inputs, so only call this for Smis.
      return NumberToString(smi);
    }
    return number::IntToDecimalString(x);
  }

  // Pretend that Number.prototype.toString was called.
  if (radix < 2 || radix > 36) {
    runtime::ThrowRangeError(
        LoadContextFromInstance(LoadInstanceFromFrame()),
        SmiConstant(MessageTemplate::kToRadixFormatRange));
  }
  return number::IntToString(x, Unsigned(radix));
}

builtin WasmStringToDouble(s: String): float64 {
  const hash: NameHash = s.raw_hash_field;
  if (IsIntegerIndex(hash) &&
      hash.array_index_length < kMaxCachedArrayIndexLength) {
    const arrayIndex: int32 = Signed(hash.array_index_value);
    return Convert<float64>(arrayIndex);
  }
  return StringToFloat64(Flatten(s));
}

builtin WasmStringFromCodePoint(codePoint: uint32): String {
  tail runtime::WasmStringFromCodePoint(
      LoadContextFromFrame(), WasmUint32ToNumber(codePoint));
}

builtin WasmStringHash(string: String): int32 {
  const result = runtime::WasmStringHash(kNoContext, string);
  return SmiToInt32(result);
}

builtin WasmExternInternalize(externObject: JSAny): JSAny {
  const instance = LoadInstanceFromFrame();
  const context = LoadContextFromInstance(instance);

  tail runtime::WasmJSToWasmObject(
      context, externObject, SmiConstant(kAnyType));
}

}  // namespace wasm

Zerion Mini Shell 1.0