wasm.tq 15 KB
Newer Older
1 2 3 4
// 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.

5 6 7
#include 'src/builtins/builtins-wasm-gen.h'

namespace runtime {
8 9
extern runtime WasmMemoryGrow(Context, WasmInstanceObject, Smi): Smi;
extern runtime WasmRefFunc(Context, WasmInstanceObject, Smi): JSAny;
10 11 12 13
extern runtime WasmTableInit(
    Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny;
extern runtime WasmTableCopy(
    Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny;
14 15 16 17 18 19 20
extern runtime WasmFunctionTableGet(
    Context, WasmInstanceObject, Smi, Smi): JSAny;
extern runtime WasmFunctionTableSet(
    Context, WasmInstanceObject, Smi, Smi, Object): JSAny;
extern runtime ThrowWasmError(Context, Smi): JSAny;
extern runtime Throw(Context, Object): JSAny;
extern runtime ReThrow(Context, Object): JSAny;
21
extern runtime WasmTriggerTierUp(Context, WasmInstanceObject): JSAny;
22 23 24
extern runtime WasmStackGuard(Context): JSAny;
extern runtime ThrowWasmStackOverflow(Context): JSAny;
extern runtime WasmTraceMemory(Context, Smi): JSAny;
25
extern runtime WasmTraceEnter(Context): JSAny;
26
extern runtime WasmTraceExit(Context, Smi): JSAny;
27 28 29 30 31 32
extern runtime WasmAtomicNotify(
    Context, WasmInstanceObject, Number, Number): Smi;
extern runtime WasmI32AtomicWait(
    Context, WasmInstanceObject, Number, Number, BigInt): Smi;
extern runtime WasmI64AtomicWait(
    Context, WasmInstanceObject, Number, BigInt, BigInt): Smi;
33
extern runtime WasmAllocateRtt(Context, Smi, Map): Map;
34 35 36 37 38
}

namespace unsafe {
extern macro TimesTaggedSize(intptr): intptr;
extern macro Allocate(intptr): HeapObject;
39 40
}

41
namespace wasm {
42
const kFuncTableType: constexpr int31 generates 'wasm::HeapType::kFunc';
43 44 45 46 47 48 49 50 51 52 53

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::LoadExternalFunctionsFromInstance(
    WasmInstanceObject): FixedArray;
54 55
extern macro WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance(
    WasmInstanceObject): FixedArray;
56 57 58 59

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

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

65 66 67 68
builtin WasmTaggedNonSmiToInt32(implicit context: Context)(val: JSAnyNotSmi):
    int32 {
  return ChangeTaggedNonSmiToInt32(val);
}
69

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

74 75 76 77 78 79 80 81 82
builtin WasmMemoryGrow(numPages: int32): int32 {
  if (!IsValidPositiveSmi(ChangeInt32ToIntPtr(numPages)))
    return Int32Constant(-1);
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const context: NativeContext = LoadContextFromInstance(instance);
  const result: Smi =
      runtime::WasmMemoryGrow(context, instance, SmiFromInt32(numPages));
  return SmiToInt32(result);
}
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
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();
  }
}

116 117 118 119 120 121
builtin WasmTableGet(tableIndex: intptr, index: int32): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    assert(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;
122

123 124 125 126 127 128 129 130
    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);
131 132

    try {
133 134 135 136 137 138
      const entryObject: HeapObject =
          TaggedToHeapObject<HeapObject>(entry) otherwise ReturnEntry;
      if (IsTuple2Map(entryObject.map)) goto CallRuntime;
      goto ReturnEntry;
    } label ReturnEntry {
      return entry;
139
    }
140 141 142 143 144 145
  } label CallRuntime deferred {
    tail runtime::WasmFunctionTableGet(
        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
        SmiFromIntPtr(entryIndex));
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
146
  }
147
}
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
builtin WasmTableSet(tableIndex: intptr, index: int32, value: Object): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
  try {
    assert(IsValidPositiveSmi(tableIndex));
    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;

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

    // Fall back to the runtime to set funcrefs, since we have to update
    // function dispatch tables.
    const tableType: Smi = table.raw_type;
    if (tableType == SmiConstant(kFuncTableType)) goto CallRuntime;

    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 CallRuntime deferred {
    tail runtime::WasmFunctionTableSet(
        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
        SmiFromIntPtr(entryIndex), value);
  } label IndexOutOfRange deferred {
    tail ThrowWasmTrapTableOutOfBounds();
177
  }
178
}
179

180 181 182 183 184 185 186 187 188 189 190 191
builtin WasmRefFunc(index: uint32): Object {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  try {
    const table: FixedArray = LoadExternalFunctionsFromInstance(instance);
    if (table == Undefined) goto CallRuntime;
    const functionIndex: intptr = Signed(ChangeUint32ToWord(index));
    const result: Object = LoadFixedArrayElement(table, functionIndex);
    if (result == Undefined) goto CallRuntime;
    return result;
  } label CallRuntime deferred {
    tail runtime::WasmRefFunc(
        LoadContextFromInstance(instance), instance, SmiFromUint32(index));
192
  }
193
}
194

195 196 197
builtin WasmThrow(exception: Object): JSAny {
  tail runtime::Throw(LoadContextFromFrame(), exception);
}
198

199
builtin WasmRethrow(exception: Object): JSAny {
200
  if (exception == Null) tail ThrowWasmTrapRethrowNull();
201 202
  tail runtime::ReThrow(LoadContextFromFrame(), exception);
}
203

204 205 206 207 208
builtin WasmTriggerTierUp(): JSAny {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  tail runtime::WasmTriggerTierUp(LoadContextFromFrame(), instance);
}

209 210 211
builtin WasmStackGuard(): JSAny {
  tail runtime::WasmStackGuard(LoadContextFromFrame());
}
212

213 214 215 216 217 218 219 220
builtin WasmStackOverflow(): JSAny {
  tail runtime::ThrowWasmStackOverflow(LoadContextFromFrame());
}

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

221 222 223 224
builtin WasmTraceEnter(): JSAny {
  tail runtime::WasmTraceEnter(LoadContextFromFrame());
}

225 226 227 228
builtin WasmTraceExit(info: Smi): JSAny {
  tail runtime::WasmTraceExit(LoadContextFromFrame(), info);
}

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

234 235 236 237 238
builtin WasmAllocateRtt(implicit context: Context)(
    typeIndex: Smi, parent: Map): Map {
  tail runtime::WasmAllocateRtt(context, typeIndex, parent);
}

239 240 241 242 243
builtin WasmAllocateStructWithRtt(implicit context: Context)(rtt: Map):
    HeapObject {
  const instanceSize: intptr =
      unsafe::TimesTaggedSize(Convert<intptr>(rtt.instance_size_in_words));
  const result: HeapObject = unsafe::Allocate(instanceSize);
244
  *UnsafeConstCast(&result.map) = rtt;
245 246 247
  return result;
}

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
builtin WasmIsRttSubtype(implicit context: Context)(sub: Map, super: Map): Smi {
  let map = sub;
  while (true) {
    if (map == super) return SmiConstant(1);  // "true"
    // This code relies on the fact that we use a non-WasmObject map as the
    // end of the chain, e.g. for "rtt any", which then doesn't have a
    // WasmTypeInfo.
    // TODO(7748): Use a more explicit sentinel mechanism?
    const maybeTypeInfo = map.constructor_or_back_pointer_or_native_context;
    if (!Is<WasmTypeInfo>(maybeTypeInfo)) return SmiConstant(0);  // "false"
    const typeInfo = %RawDownCast<WasmTypeInfo>(maybeTypeInfo);
    map = typeInfo.parent;
  }
  unreachable;
}

264 265 266 267 268 269 270 271 272 273 274 275 276
// Redeclaration with different typing (value is an Object, not JSAny).
extern transitioning runtime
CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, Object);

transitioning builtin WasmAllocateObjectWrapper(implicit context: Context)(
    obj: Object): JSObject {
  // Note: {obj} can be null, or i31ref. The code below is agnostic to that.
  const wrapper = NewJSObject();
  const symbol = WasmWrappedObjectSymbolConstant();
  CreateDataProperty(wrapper, symbol, obj);
  return wrapper;
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
builtin WasmInt32ToNumber(value: int32): Number {
  return ChangeInt32ToTagged(value);
}

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

extern builtin I64ToBigInt(intptr): BigInt;

builtin WasmAtomicNotify(address: uint32, count: uint32): uint32 {
  const instance: WasmInstanceObject = LoadInstanceFromFrame();
  const result: Smi = runtime::WasmAtomicNotify(
      LoadContextFromInstance(instance), instance, WasmUint32ToNumber(address),
      WasmUint32ToNumber(count));
  return Unsigned(SmiToInt32(result));
}

builtin WasmI32AtomicWait64(
    address: uint32, expectedValue: int32, timeout: intptr): uint32 {
  if constexpr (Is64()) {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const result: Smi = runtime::WasmI32AtomicWait(
        LoadContextFromInstance(instance), instance,
        WasmUint32ToNumber(address), WasmInt32ToNumber(expectedValue),
        I64ToBigInt(timeout));
    return Unsigned(SmiToInt32(result));
  } else {
    unreachable;
  }
}

builtin WasmI64AtomicWait64(
    address: uint32, expectedValue: intptr, timeout: intptr): uint32 {
  if constexpr (Is64()) {
    const instance: WasmInstanceObject = LoadInstanceFromFrame();
    const result: Smi = runtime::WasmI64AtomicWait(
        LoadContextFromInstance(instance), instance,
        WasmUint32ToNumber(address), I64ToBigInt(expectedValue),
        I64ToBigInt(timeout));
    return Unsigned(SmiToInt32(result));
  } else {
    unreachable;
  }
}

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
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;
339
    try {
340 341 342 343 344 345
      TryHasOwnProperty(
          receiver, receiver.map, receiver.instanceType, uniqueName)
          otherwise Found, NotFound, Bailout;
    } label Found {
      tail GetPropertyWithReceiver(
          receiver, uniqueName, receiver, SmiConstant(kReturnUndefined));
346
    }
347 348 349 350
  } label NotFound deferred {
    return Undefined;
  } label Bailout deferred {
    unreachable;
351
  }
352
}
353

354
// Trap builtins.
355

356 357 358
builtin WasmTrap(error: Smi): JSAny {
  tail runtime::ThrowWasmError(LoadContextFromFrame(), error);
}
359

360 361 362
builtin ThrowWasmTrapUnreachable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable));
}
363

364 365 366
builtin ThrowWasmTrapMemOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapMemOutOfBounds));
}
367

368 369 370
builtin ThrowWasmTrapUnalignedAccess(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnalignedAccess));
}
371

372 373 374
builtin ThrowWasmTrapDivByZero(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivByZero));
}
375

376 377 378
builtin ThrowWasmTrapDivUnrepresentable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivUnrepresentable));
}
379

380 381 382
builtin ThrowWasmTrapRemByZero(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRemByZero));
}
383

384 385 386
builtin ThrowWasmTrapFloatUnrepresentable(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFloatUnrepresentable));
}
387

388 389 390
builtin ThrowWasmTrapFuncSigMismatch(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncSigMismatch));
}
391

392 393 394
builtin ThrowWasmTrapDataSegmentDropped(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDataSegmentDropped));
}
395

396 397 398
builtin ThrowWasmTrapElemSegmentDropped(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapElemSegmentDropped));
}
399

400 401 402
builtin ThrowWasmTrapTableOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds));
}
403

404 405
builtin ThrowWasmTrapBrOnExnNull(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapBrOnExnNull));
406
}
407

408 409
builtin ThrowWasmTrapRethrowNull(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNull));
410
}
411

412 413 414
builtin ThrowWasmTrapNullDereference(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference));
}
415

416 417 418
builtin ThrowWasmTrapIllegalCast(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast));
}
419

420 421 422
builtin ThrowWasmTrapArrayOutOfBounds(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds));
}
423 424 425 426

builtin ThrowWasmTrapWasmJSFunction(): JSAny {
  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapWasmJSFunction));
}
427
}