1// Copyright 2020 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include 'src/builtins/builtins-wasm-gen.h' 6 7namespace runtime { 8extern runtime WasmMemoryGrow(Context, WasmInstanceObject, Smi): Smi; 9extern runtime WasmRefFunc(Context, WasmInstanceObject, Smi): JSAny; 10extern runtime WasmTableInit( 11 Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny; 12extern runtime WasmTableCopy( 13 Context, WasmInstanceObject, Object, Object, Smi, Smi, Smi): JSAny; 14extern runtime WasmFunctionTableGet( 15 Context, WasmInstanceObject, Smi, Smi): JSAny; 16extern runtime WasmFunctionTableSet( 17 Context, WasmInstanceObject, Smi, Smi, Object): JSAny; 18extern runtime ThrowWasmError(Context, Smi): JSAny; 19extern runtime Throw(Context, Object): JSAny; 20extern runtime ReThrow(Context, Object): JSAny; 21extern runtime WasmTriggerTierUp(Context, WasmInstanceObject): JSAny; 22extern runtime WasmStackGuard(Context): JSAny; 23extern runtime ThrowWasmStackOverflow(Context): JSAny; 24extern runtime WasmTraceMemory(Context, Smi): JSAny; 25extern runtime WasmTraceEnter(Context): JSAny; 26extern runtime WasmTraceExit(Context, Smi): JSAny; 27extern runtime WasmAtomicNotify( 28 Context, WasmInstanceObject, Number, Number): Smi; 29extern runtime WasmI32AtomicWait( 30 Context, WasmInstanceObject, Number, Number, BigInt): Smi; 31extern runtime WasmI64AtomicWait( 32 Context, WasmInstanceObject, Number, BigInt, BigInt): Smi; 33extern runtime WasmAllocateRtt(Context, Smi, Map): Map; 34} 35 36namespace unsafe { 37extern macro TimesTaggedSize(intptr): intptr; 38extern macro Allocate(intptr): HeapObject; 39} 40 41namespace wasm { 42const kFuncTableType: constexpr int31 generates 'wasm::HeapType::kFunc'; 43 44extern macro WasmBuiltinsAssembler::LoadInstanceFromFrame(): WasmInstanceObject; 45 46// WasmInstanceObject has a field layout that Torque can't handle yet. 47// TODO(bbudge) Eliminate these functions when Torque is ready. 48extern macro WasmBuiltinsAssembler::LoadContextFromInstance(WasmInstanceObject): 49 NativeContext; 50extern macro WasmBuiltinsAssembler::LoadTablesFromInstance(WasmInstanceObject): 51 FixedArray; 52extern macro WasmBuiltinsAssembler::LoadExternalFunctionsFromInstance( 53 WasmInstanceObject): FixedArray; 54extern macro WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance( 55 WasmInstanceObject): FixedArray; 56 57macro LoadContextFromFrame(): NativeContext { 58 return LoadContextFromInstance(LoadInstanceFromFrame()); 59} 60 61builtin WasmInt32ToHeapNumber(val: int32): HeapNumber { 62 return AllocateHeapNumberWithValue(Convert<float64>(val)); 63} 64 65builtin WasmTaggedNonSmiToInt32(implicit context: Context)(val: JSAnyNotSmi): 66 int32 { 67 return ChangeTaggedNonSmiToInt32(val); 68} 69 70builtin WasmTaggedToFloat64(implicit context: Context)(val: JSAny): float64 { 71 return ChangeTaggedToFloat64(val); 72} 73 74builtin WasmMemoryGrow(numPages: int32): int32 { 75 if (!IsValidPositiveSmi(ChangeInt32ToIntPtr(numPages))) 76 return Int32Constant(-1); 77 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 78 const context: NativeContext = LoadContextFromInstance(instance); 79 const result: Smi = 80 runtime::WasmMemoryGrow(context, instance, SmiFromInt32(numPages)); 81 return SmiToInt32(result); 82} 83 84builtin WasmTableInit( 85 dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, tableIndex: Smi, 86 segmentIndex: Smi): JSAny { 87 try { 88 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 89 const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds; 90 const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds; 91 const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds; 92 tail runtime::WasmTableInit( 93 LoadContextFromInstance(instance), instance, tableIndex, segmentIndex, 94 dst, src, size); 95 } label TableOutOfBounds deferred { 96 tail ThrowWasmTrapTableOutOfBounds(); 97 } 98} 99 100builtin WasmTableCopy( 101 dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, dstTable: Smi, 102 srcTable: Smi): JSAny { 103 try { 104 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 105 const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds; 106 const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds; 107 const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds; 108 tail runtime::WasmTableCopy( 109 LoadContextFromInstance(instance), instance, dstTable, srcTable, dst, 110 src, size); 111 } label TableOutOfBounds deferred { 112 tail ThrowWasmTrapTableOutOfBounds(); 113 } 114} 115 116builtin WasmTableGet(tableIndex: intptr, index: int32): Object { 117 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 118 const entryIndex: intptr = ChangeInt32ToIntPtr(index); 119 try { 120 assert(IsValidPositiveSmi(tableIndex)); 121 if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange; 122 123 const tables: FixedArray = LoadTablesFromInstance(instance); 124 const table: WasmTableObject = %RawDownCast<WasmTableObject>( 125 LoadFixedArrayElement(tables, tableIndex)); 126 const entriesCount: intptr = Convert<intptr, Smi>(table.current_length); 127 if (entryIndex >= entriesCount) goto IndexOutOfRange; 128 129 const entries: FixedArray = table.entries; 130 const entry: Object = LoadFixedArrayElement(entries, entryIndex); 131 132 try { 133 const entryObject: HeapObject = 134 TaggedToHeapObject<HeapObject>(entry) otherwise ReturnEntry; 135 if (IsTuple2Map(entryObject.map)) goto CallRuntime; 136 goto ReturnEntry; 137 } label ReturnEntry { 138 return entry; 139 } 140 } label CallRuntime deferred { 141 tail runtime::WasmFunctionTableGet( 142 LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex), 143 SmiFromIntPtr(entryIndex)); 144 } label IndexOutOfRange deferred { 145 tail ThrowWasmTrapTableOutOfBounds(); 146 } 147} 148 149builtin WasmTableSet(tableIndex: intptr, index: int32, value: Object): Object { 150 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 151 const entryIndex: intptr = ChangeInt32ToIntPtr(index); 152 try { 153 assert(IsValidPositiveSmi(tableIndex)); 154 if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange; 155 156 const tables: FixedArray = LoadTablesFromInstance(instance); 157 const table: WasmTableObject = %RawDownCast<WasmTableObject>( 158 LoadFixedArrayElement(tables, tableIndex)); 159 160 // Fall back to the runtime to set funcrefs, since we have to update 161 // function dispatch tables. 162 const tableType: Smi = table.raw_type; 163 if (tableType == SmiConstant(kFuncTableType)) goto CallRuntime; 164 165 const entriesCount: intptr = Convert<intptr, Smi>(table.current_length); 166 if (entryIndex >= entriesCount) goto IndexOutOfRange; 167 168 const entries: FixedArray = table.entries; 169 StoreFixedArrayElement(entries, entryIndex, value); 170 return Undefined; 171 } label CallRuntime deferred { 172 tail runtime::WasmFunctionTableSet( 173 LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex), 174 SmiFromIntPtr(entryIndex), value); 175 } label IndexOutOfRange deferred { 176 tail ThrowWasmTrapTableOutOfBounds(); 177 } 178} 179 180builtin WasmRefFunc(index: uint32): Object { 181 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 182 try { 183 const table: FixedArray = LoadExternalFunctionsFromInstance(instance); 184 if (table == Undefined) goto CallRuntime; 185 const functionIndex: intptr = Signed(ChangeUint32ToWord(index)); 186 const result: Object = LoadFixedArrayElement(table, functionIndex); 187 if (result == Undefined) goto CallRuntime; 188 return result; 189 } label CallRuntime deferred { 190 tail runtime::WasmRefFunc( 191 LoadContextFromInstance(instance), instance, SmiFromUint32(index)); 192 } 193} 194 195builtin WasmThrow(exception: Object): JSAny { 196 tail runtime::Throw(LoadContextFromFrame(), exception); 197} 198 199builtin WasmRethrow(exception: Object): JSAny { 200 if (exception == Null) tail ThrowWasmTrapRethrowNull(); 201 tail runtime::ReThrow(LoadContextFromFrame(), exception); 202} 203 204builtin WasmTriggerTierUp(): JSAny { 205 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 206 tail runtime::WasmTriggerTierUp(LoadContextFromFrame(), instance); 207} 208 209builtin WasmStackGuard(): JSAny { 210 tail runtime::WasmStackGuard(LoadContextFromFrame()); 211} 212 213builtin WasmStackOverflow(): JSAny { 214 tail runtime::ThrowWasmStackOverflow(LoadContextFromFrame()); 215} 216 217builtin WasmTraceMemory(info: Smi): JSAny { 218 tail runtime::WasmTraceMemory(LoadContextFromFrame(), info); 219} 220 221builtin WasmTraceEnter(): JSAny { 222 tail runtime::WasmTraceEnter(LoadContextFromFrame()); 223} 224 225builtin WasmTraceExit(info: Smi): JSAny { 226 tail runtime::WasmTraceExit(LoadContextFromFrame(), info); 227} 228 229builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray { 230 const map: Map = GetFastPackedElementsJSArrayMap(); 231 return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size); 232} 233 234builtin WasmAllocateRtt(implicit context: Context)( 235 typeIndex: Smi, parent: Map): Map { 236 tail runtime::WasmAllocateRtt(context, typeIndex, parent); 237} 238 239builtin WasmAllocateStructWithRtt(implicit context: Context)(rtt: Map): 240 HeapObject { 241 const instanceSize: intptr = 242 unsafe::TimesTaggedSize(Convert<intptr>(rtt.instance_size_in_words)); 243 const result: HeapObject = unsafe::Allocate(instanceSize); 244 *UnsafeConstCast(&result.map) = rtt; 245 return result; 246} 247 248builtin WasmIsRttSubtype(implicit context: Context)(sub: Map, super: Map): Smi { 249 let map = sub; 250 while (true) { 251 if (map == super) return SmiConstant(1); // "true" 252 // This code relies on the fact that we use a non-WasmObject map as the 253 // end of the chain, e.g. for "rtt any", which then doesn't have a 254 // WasmTypeInfo. 255 // TODO(7748): Use a more explicit sentinel mechanism? 256 const maybeTypeInfo = map.constructor_or_back_pointer_or_native_context; 257 if (!Is<WasmTypeInfo>(maybeTypeInfo)) return SmiConstant(0); // "false" 258 const typeInfo = %RawDownCast<WasmTypeInfo>(maybeTypeInfo); 259 map = typeInfo.parent; 260 } 261 unreachable; 262} 263 264// Redeclaration with different typing (value is an Object, not JSAny). 265extern transitioning runtime 266CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, Object); 267 268transitioning builtin WasmAllocateObjectWrapper(implicit context: Context)( 269 obj: Object): JSObject { 270 // Note: {obj} can be null, or i31ref. The code below is agnostic to that. 271 const wrapper = NewJSObject(); 272 const symbol = WasmWrappedObjectSymbolConstant(); 273 CreateDataProperty(wrapper, symbol, obj); 274 return wrapper; 275} 276 277builtin WasmInt32ToNumber(value: int32): Number { 278 return ChangeInt32ToTagged(value); 279} 280 281builtin WasmUint32ToNumber(value: uint32): Number { 282 return ChangeUint32ToTagged(value); 283} 284 285builtin UintPtr53ToNumber(value: uintptr): Number { 286 if (value <= kSmiMaxValue) return Convert<Smi>(Convert<intptr>(value)); 287 const valueFloat = ChangeUintPtrToFloat64(value); 288 // Values need to be within [0..2^53], such that they can be represented as 289 // float64. 290 assert(ChangeFloat64ToUintPtr(valueFloat) == value); 291 return AllocateHeapNumberWithValue(valueFloat); 292} 293 294extern builtin I64ToBigInt(intptr): BigInt; 295 296builtin WasmAtomicNotify(offset: uintptr, count: uint32): uint32 { 297 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 298 const result: Smi = runtime::WasmAtomicNotify( 299 LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset), 300 WasmUint32ToNumber(count)); 301 return Unsigned(SmiToInt32(result)); 302} 303 304builtin WasmI32AtomicWait64( 305 offset: uintptr, expectedValue: int32, timeout: intptr): uint32 { 306 if constexpr (Is64()) { 307 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 308 const result: Smi = runtime::WasmI32AtomicWait( 309 LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset), 310 WasmInt32ToNumber(expectedValue), I64ToBigInt(timeout)); 311 return Unsigned(SmiToInt32(result)); 312 } else { 313 unreachable; 314 } 315} 316 317builtin WasmI64AtomicWait64( 318 offset: uintptr, expectedValue: intptr, timeout: intptr): uint32 { 319 if constexpr (Is64()) { 320 const instance: WasmInstanceObject = LoadInstanceFromFrame(); 321 const result: Smi = runtime::WasmI64AtomicWait( 322 LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset), 323 I64ToBigInt(expectedValue), I64ToBigInt(timeout)); 324 return Unsigned(SmiToInt32(result)); 325 } else { 326 unreachable; 327 } 328} 329 330extern macro TryHasOwnProperty(HeapObject, Map, InstanceType, Name): never 331 labels Found, NotFound, Bailout; 332type OnNonExistent constexpr 'OnNonExistent'; 333const kReturnUndefined: constexpr OnNonExistent 334 generates 'OnNonExistent::kReturnUndefined'; 335extern macro SmiConstant(constexpr OnNonExistent): Smi; 336extern transitioning builtin GetPropertyWithReceiver(implicit context: Context)( 337 JSAny, Name, JSAny, Smi): JSAny; 338 339transitioning builtin WasmGetOwnProperty(implicit context: Context)( 340 object: Object, uniqueName: Name): JSAny { 341 try { 342 const heapObject: HeapObject = 343 TaggedToHeapObject(object) otherwise NotFound; 344 const receiver: JSReceiver = 345 Cast<JSReceiver>(heapObject) otherwise NotFound; 346 try { 347 TryHasOwnProperty( 348 receiver, receiver.map, receiver.instanceType, uniqueName) 349 otherwise Found, NotFound, Bailout; 350 } label Found { 351 tail GetPropertyWithReceiver( 352 receiver, uniqueName, receiver, SmiConstant(kReturnUndefined)); 353 } 354 } label NotFound deferred { 355 return Undefined; 356 } label Bailout deferred { 357 unreachable; 358 } 359} 360 361// Trap builtins. 362 363builtin WasmTrap(error: Smi): JSAny { 364 tail runtime::ThrowWasmError(LoadContextFromFrame(), error); 365} 366 367builtin ThrowWasmTrapUnreachable(): JSAny { 368 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable)); 369} 370 371builtin ThrowWasmTrapMemOutOfBounds(): JSAny { 372 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapMemOutOfBounds)); 373} 374 375builtin ThrowWasmTrapUnalignedAccess(): JSAny { 376 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnalignedAccess)); 377} 378 379builtin ThrowWasmTrapDivByZero(): JSAny { 380 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivByZero)); 381} 382 383builtin ThrowWasmTrapDivUnrepresentable(): JSAny { 384 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivUnrepresentable)); 385} 386 387builtin ThrowWasmTrapRemByZero(): JSAny { 388 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRemByZero)); 389} 390 391builtin ThrowWasmTrapFloatUnrepresentable(): JSAny { 392 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFloatUnrepresentable)); 393} 394 395builtin ThrowWasmTrapFuncSigMismatch(): JSAny { 396 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncSigMismatch)); 397} 398 399builtin ThrowWasmTrapDataSegmentDropped(): JSAny { 400 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDataSegmentDropped)); 401} 402 403builtin ThrowWasmTrapElemSegmentDropped(): JSAny { 404 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapElemSegmentDropped)); 405} 406 407builtin ThrowWasmTrapTableOutOfBounds(): JSAny { 408 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds)); 409} 410 411builtin ThrowWasmTrapBrOnExnNull(): JSAny { 412 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapBrOnExnNull)); 413} 414 415builtin ThrowWasmTrapRethrowNull(): JSAny { 416 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNull)); 417} 418 419builtin ThrowWasmTrapNullDereference(): JSAny { 420 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference)); 421} 422 423builtin ThrowWasmTrapIllegalCast(): JSAny { 424 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast)); 425} 426 427builtin ThrowWasmTrapArrayOutOfBounds(): JSAny { 428 tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds)); 429} 430} 431