• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 WasmTableFill(
15    Context, WasmInstanceObject, Smi, Smi, Object, Smi): JSAny;
16extern runtime WasmTableGrow(
17    Context, WasmInstanceObject, Smi, Object, Smi): Smi;
18extern runtime WasmFunctionTableGet(
19    Context, WasmInstanceObject, Smi, Smi): JSAny;
20extern runtime WasmFunctionTableSet(
21    Context, WasmInstanceObject, Smi, Smi, Object): JSAny;
22extern runtime ThrowWasmError(Context, Smi): JSAny;
23extern runtime WasmThrow(Context, Object, FixedArray): JSAny;
24extern runtime WasmReThrow(Context, Object): JSAny;
25extern runtime WasmTriggerTierUp(Context, WasmInstanceObject): JSAny;
26extern runtime WasmStackGuard(Context): JSAny;
27extern runtime ThrowWasmStackOverflow(Context): JSAny;
28extern runtime WasmTraceMemory(Context, Smi): JSAny;
29extern runtime WasmTraceEnter(Context): JSAny;
30extern runtime WasmTraceExit(Context, Smi): JSAny;
31extern runtime WasmAtomicNotify(
32    Context, WasmInstanceObject, Number, Number): Smi;
33extern runtime WasmI32AtomicWait(
34    Context, WasmInstanceObject, Number, Number, BigInt): Smi;
35extern runtime WasmI64AtomicWait(
36    Context, WasmInstanceObject, Number, BigInt, BigInt): Smi;
37extern runtime WasmArrayCopy(
38    Context, WasmArray, Smi, WasmArray, Smi, Smi): JSAny;
39extern runtime WasmArrayInitFromData(
40    Context, WasmInstanceObject, Smi, Smi, Smi, Map): Object;
41}
42
43namespace unsafe {
44extern macro TimesTaggedSize(intptr): intptr;
45extern macro Allocate(intptr, constexpr AllocationFlag): HeapObject;
46extern macro AllocateWasmArray(
47    intptr, constexpr InitializationMode): HeapObject;
48}
49
50namespace wasm {
51const kAnyTableType: constexpr int31
52    generates 'wasm::kWasmAnyRef.raw_bit_field()';
53const kAnyNonNullTableType: constexpr int31
54    generates 'wasm::kWasmAnyNonNullableRef.raw_bit_field()';
55
56extern macro WasmBuiltinsAssembler::LoadInstanceFromFrame(): WasmInstanceObject;
57
58// WasmInstanceObject has a field layout that Torque can't handle yet.
59// TODO(bbudge) Eliminate these functions when Torque is ready.
60extern macro WasmBuiltinsAssembler::LoadContextFromInstance(WasmInstanceObject):
61    NativeContext;
62extern macro WasmBuiltinsAssembler::LoadTablesFromInstance(WasmInstanceObject):
63    FixedArray;
64extern macro WasmBuiltinsAssembler::LoadInternalFunctionsFromInstance(
65    WasmInstanceObject): FixedArray;
66extern macro WasmBuiltinsAssembler::LoadManagedObjectMapsFromInstance(
67    WasmInstanceObject): FixedArray;
68
69macro LoadContextFromFrame(): NativeContext {
70  return LoadContextFromInstance(LoadInstanceFromFrame());
71}
72
73builtin WasmInt32ToHeapNumber(val: int32): HeapNumber {
74  return AllocateHeapNumberWithValue(Convert<float64>(val));
75}
76
77builtin WasmFuncRefToJS(val: WasmInternalFunction|Null): JSFunction|Null|
78    Undefined {
79  typeswitch (val) {
80    case (Null): {
81      return Null;
82    }
83    case (func: WasmInternalFunction): {
84      return func.external;
85    }
86  }
87}
88
89builtin WasmTaggedNonSmiToInt32(implicit context: Context)(val: JSAnyNotSmi):
90    int32 {
91  return ChangeTaggedNonSmiToInt32(val);
92}
93
94builtin WasmTaggedToFloat64(implicit context: Context)(val: JSAny): float64 {
95  return ChangeTaggedToFloat64(val);
96}
97
98builtin WasmMemoryGrow(numPages: int32): int32 {
99  if (!IsValidPositiveSmi(ChangeInt32ToIntPtr(numPages)))
100    return Int32Constant(-1);
101  const instance: WasmInstanceObject = LoadInstanceFromFrame();
102  const context: NativeContext = LoadContextFromInstance(instance);
103  const result: Smi =
104      runtime::WasmMemoryGrow(context, instance, SmiFromInt32(numPages));
105  return SmiToInt32(result);
106}
107
108builtin WasmTableInit(
109    dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, tableIndex: Smi,
110    segmentIndex: Smi): JSAny {
111  try {
112    const instance: WasmInstanceObject = LoadInstanceFromFrame();
113    const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds;
114    const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds;
115    const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds;
116    tail runtime::WasmTableInit(
117        LoadContextFromInstance(instance), instance, tableIndex, segmentIndex,
118        dst, src, size);
119  } label TableOutOfBounds deferred {
120    tail ThrowWasmTrapTableOutOfBounds();
121  }
122}
123
124builtin WasmTableCopy(
125    dstRaw: uint32, srcRaw: uint32, sizeRaw: uint32, dstTable: Smi,
126    srcTable: Smi): JSAny {
127  try {
128    const instance: WasmInstanceObject = LoadInstanceFromFrame();
129    const dst: Smi = Convert<PositiveSmi>(dstRaw) otherwise TableOutOfBounds;
130    const src: Smi = Convert<PositiveSmi>(srcRaw) otherwise TableOutOfBounds;
131    const size: Smi = Convert<PositiveSmi>(sizeRaw) otherwise TableOutOfBounds;
132    tail runtime::WasmTableCopy(
133        LoadContextFromInstance(instance), instance, dstTable, srcTable, dst,
134        src, size);
135  } label TableOutOfBounds deferred {
136    tail ThrowWasmTrapTableOutOfBounds();
137  }
138}
139
140builtin WasmTableFill(
141    table: Smi, startRaw: uint32, countRaw: uint32, value: Object): JSAny {
142  try {
143    const instance: WasmInstanceObject = LoadInstanceFromFrame();
144    const start: Smi =
145        Convert<PositiveSmi>(startRaw) otherwise TableOutOfBounds;
146    const count: Smi =
147        Convert<PositiveSmi>(countRaw) otherwise TableOutOfBounds;
148    tail runtime::WasmTableFill(
149        LoadContextFromInstance(instance), instance, table, start, value,
150        count);
151  } label TableOutOfBounds deferred {
152    tail ThrowWasmTrapTableOutOfBounds();
153  }
154}
155
156builtin WasmTableGrow(table: Smi, deltaRaw: uint32, value: Object): Smi {
157  try {
158    const instance: WasmInstanceObject = LoadInstanceFromFrame();
159    const delta: Smi =
160        Convert<PositiveSmi>(deltaRaw) otherwise TableOutOfBounds;
161    tail runtime::WasmTableGrow(
162        LoadContextFromInstance(instance), instance, table, value, delta);
163  } label TableOutOfBounds deferred {
164    return -1;
165  }
166}
167
168builtin WasmTableGet(tableIndex: intptr, index: int32): Object {
169  const instance: WasmInstanceObject = LoadInstanceFromFrame();
170  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
171  try {
172    dcheck(IsValidPositiveSmi(tableIndex));
173    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;
174
175    const tables: FixedArray = LoadTablesFromInstance(instance);
176    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
177        LoadFixedArrayElement(tables, tableIndex));
178    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
179    if (entryIndex >= entriesCount) goto IndexOutOfRange;
180
181    const entries: FixedArray = table.entries;
182    const entry: Object = LoadFixedArrayElement(entries, entryIndex);
183
184    try {
185      const entryObject: HeapObject =
186          TaggedToHeapObject<HeapObject>(entry) otherwise ReturnEntry;
187      if (IsTuple2Map(entryObject.map)) goto CallRuntime;
188      goto ReturnEntry;
189    } label ReturnEntry {
190      return entry;
191    }
192  } label CallRuntime deferred {
193    tail runtime::WasmFunctionTableGet(
194        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
195        SmiFromIntPtr(entryIndex));
196  } label IndexOutOfRange deferred {
197    tail ThrowWasmTrapTableOutOfBounds();
198  }
199}
200
201builtin WasmTableSet(tableIndex: intptr, index: int32, value: Object): Object {
202  const instance: WasmInstanceObject = LoadInstanceFromFrame();
203  const entryIndex: intptr = ChangeInt32ToIntPtr(index);
204  try {
205    dcheck(IsValidPositiveSmi(tableIndex));
206    if (!IsValidPositiveSmi(entryIndex)) goto IndexOutOfRange;
207
208    const tables: FixedArray = LoadTablesFromInstance(instance);
209    const table: WasmTableObject = %RawDownCast<WasmTableObject>(
210        LoadFixedArrayElement(tables, tableIndex));
211
212    // Fall back to the runtime to set funcrefs, since we have to update
213    // function dispatch tables.
214    // TODO(7748): Update this if further table types are supported.
215    const tableType: Smi = table.raw_type;
216    if (tableType != SmiConstant(kAnyTableType) &&
217        tableType != SmiConstant(kAnyNonNullTableType)) {
218      goto CallRuntime;
219    }
220
221    const entriesCount: intptr = Convert<intptr, Smi>(table.current_length);
222    if (entryIndex >= entriesCount) goto IndexOutOfRange;
223
224    const entries: FixedArray = table.entries;
225    StoreFixedArrayElement(entries, entryIndex, value);
226    return Undefined;
227  } label CallRuntime deferred {
228    tail runtime::WasmFunctionTableSet(
229        LoadContextFromInstance(instance), instance, SmiFromIntPtr(tableIndex),
230        SmiFromIntPtr(entryIndex), value);
231  } label IndexOutOfRange deferred {
232    tail ThrowWasmTrapTableOutOfBounds();
233  }
234}
235
236builtin WasmRefFunc(index: uint32): Object {
237  const instance: WasmInstanceObject = LoadInstanceFromFrame();
238  try {
239    const table: FixedArray = LoadInternalFunctionsFromInstance(instance);
240    if (table == Undefined) goto CallRuntime;
241    const functionIndex: intptr = Signed(ChangeUint32ToWord(index));
242    const result: Object = LoadFixedArrayElement(table, functionIndex);
243    if (result == Undefined) goto CallRuntime;
244    return result;
245  } label CallRuntime deferred {
246    tail runtime::WasmRefFunc(
247        LoadContextFromInstance(instance), instance, SmiFromUint32(index));
248  }
249}
250
251builtin WasmAllocateFixedArray(size: intptr): FixedArray {
252  if (size == 0) return kEmptyFixedArray;
253  return UnsafeCast<FixedArray>(AllocateFixedArray(
254      ElementsKind::PACKED_ELEMENTS, size, AllocationFlag::kNone));
255}
256
257builtin WasmThrow(tag: Object, values: FixedArray): JSAny {
258  tail runtime::WasmThrow(LoadContextFromFrame(), tag, values);
259}
260
261builtin WasmRethrow(exception: Object): JSAny {
262  if (exception == Null) tail ThrowWasmTrapRethrowNull();
263  tail runtime::WasmReThrow(LoadContextFromFrame(), exception);
264}
265
266// We need this for frames that do not have the instance in the parameters.
267// Currently, this is CapiCallWrapper frames.
268builtin WasmRethrowExplicitContext(
269    exception: Object, explicitContext: Context): JSAny {
270  if (exception == Null) tail ThrowWasmTrapRethrowNull();
271  tail runtime::WasmReThrow(explicitContext, exception);
272}
273
274builtin WasmTriggerTierUp(): JSAny {
275  const instance: WasmInstanceObject = LoadInstanceFromFrame();
276  tail runtime::WasmTriggerTierUp(LoadContextFromFrame(), instance);
277}
278
279builtin WasmStackGuard(): JSAny {
280  tail runtime::WasmStackGuard(LoadContextFromFrame());
281}
282
283builtin WasmStackOverflow(): JSAny {
284  tail runtime::ThrowWasmStackOverflow(LoadContextFromFrame());
285}
286
287builtin WasmTraceMemory(info: Smi): JSAny {
288  tail runtime::WasmTraceMemory(LoadContextFromFrame(), info);
289}
290
291builtin WasmTraceEnter(): JSAny {
292  tail runtime::WasmTraceEnter(LoadContextFromFrame());
293}
294
295builtin WasmTraceExit(info: Smi): JSAny {
296  tail runtime::WasmTraceExit(LoadContextFromFrame(), info);
297}
298
299builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray {
300  const map: Map = GetFastPackedElementsJSArrayMap();
301  return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size);
302}
303
304builtin WasmAllocateStructWithRtt(rtt: Map): HeapObject {
305  const typeInfo: WasmTypeInfo = %RawDownCast<WasmTypeInfo>(
306      rtt.constructor_or_back_pointer_or_native_context);
307  const instanceSize: intptr = SmiUntag(typeInfo.instance_size);
308  const result: HeapObject = unsafe::Allocate(
309      instanceSize, AllocationFlag::kAllowLargeObjectAllocation);
310  *UnsafeConstCast(&result.map) = rtt;
311  // TODO(ishell): consider removing properties_or_hash field from WasmObjects.
312  %RawDownCast<WasmStruct>(result).properties_or_hash = kEmptyFixedArray;
313  return result;
314}
315
316macro WasmAllocateArray(
317    rtt: Map, length: uint32, elementSize: uint32,
318    initializationMode: constexpr InitializationMode): HeapObject {
319  // instanceSize = RoundUp(elementSize * length, kObjectAlignment)
320  //              + WasmArray::kHeaderSize
321  const instanceSize: intptr =
322      torque_internal::AlignTagged(
323          Convert<intptr>(length) * Convert<intptr>(elementSize)) +
324      Convert<intptr>(kWasmArrayHeaderSize);
325  const result: HeapObject =
326      unsafe::AllocateWasmArray(instanceSize, initializationMode);
327  *UnsafeConstCast(&result.map) = rtt;
328  // TODO(ishell): consider removing properties_or_hash field from WasmObjects.
329  %RawDownCast<WasmArray>(result).properties_or_hash = kEmptyFixedArray;
330  %RawDownCast<WasmArray>(result).length = length;
331  return result;
332}
333
334builtin WasmAllocateArray_Uninitialized(
335    rtt: Map, length: uint32, elementSize: uint32): HeapObject {
336  return WasmAllocateArray(
337      rtt, length, elementSize, InitializationMode::kUninitialized);
338}
339
340builtin WasmAllocateArray_InitZero(
341    rtt: Map, length: uint32, elementSize: uint32): HeapObject {
342  return WasmAllocateArray(
343      rtt, length, elementSize, InitializationMode::kInitializeToZero);
344}
345
346builtin WasmAllocateArray_InitNull(
347    rtt: Map, length: uint32, elementSize: uint32): HeapObject {
348  return WasmAllocateArray(
349      rtt, length, elementSize, InitializationMode::kInitializeToNull);
350}
351
352builtin WasmArrayInitFromData(
353    dataSegment: uint32, offset: uint32, length: uint32, rtt: Map): Object {
354  const instance = LoadInstanceFromFrame();
355  tail runtime::WasmArrayInitFromData(
356      LoadContextFromInstance(instance), instance, SmiFromUint32(dataSegment),
357      SmiFromUint32(offset), SmiFromUint32(length), rtt);
358}
359
360// We put all uint32 parameters at the beginning so that they are assigned to
361// registers.
362builtin WasmArrayCopyWithChecks(
363    dstIndex: uint32, srcIndex: uint32, length: uint32, dstObject: Object,
364    srcObject: Object): JSAny {
365  if (dstObject == Null) tail ThrowWasmTrapNullDereference();
366  if (srcObject == Null) tail ThrowWasmTrapNullDereference();
367  const dstArray = %RawDownCast<WasmArray>(dstObject);
368  const srcArray = %RawDownCast<WasmArray>(srcObject);
369  // Check that the end of the copying range is in-bounds and that the range
370  // does not overflow.
371  if (dstIndex + length > dstArray.length || dstIndex + length < dstIndex ||
372      srcIndex + length > srcArray.length || srcIndex + length < srcIndex) {
373    tail ThrowWasmTrapArrayOutOfBounds();
374  }
375  if (length == 0) return Undefined;
376  tail runtime::WasmArrayCopy(
377      LoadContextFromFrame(), dstArray, SmiFromUint32(dstIndex), srcArray,
378      SmiFromUint32(srcIndex), SmiFromUint32(length));
379}
380
381builtin WasmArrayCopy(
382    dstIndex: uint32, srcIndex: uint32, length: uint32, dstArray: WasmArray,
383    srcArray: WasmArray): JSAny {
384  if (length == 0) return Undefined;
385  tail runtime::WasmArrayCopy(
386      LoadContextFromFrame(), dstArray, SmiFromUint32(dstIndex), srcArray,
387      SmiFromUint32(srcIndex), SmiFromUint32(length));
388}
389
390// Redeclaration with different typing (value is an Object, not JSAny).
391extern transitioning runtime
392CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, Object): void;
393
394transitioning builtin WasmAllocateObjectWrapper(implicit context: Context)(
395    obj: Object): JSObject {
396  // Note: {obj} can be null, or i31ref. The code below is agnostic to that.
397  const wrapper = NewJSObject();
398  const symbol = WasmWrappedObjectSymbolConstant();
399  CreateDataProperty(wrapper, symbol, obj);
400  return wrapper;
401}
402
403builtin WasmSubtypeCheck(objectSupertypes: FixedArray, rtt: Map): int32 {
404  const rttSupertypeLength: Smi =
405      %RawDownCast<WasmTypeInfo>(
406          rtt.constructor_or_back_pointer_or_native_context)
407          .supertypes.length;
408
409  if (objectSupertypes.length <= rttSupertypeLength) {
410    return 0;
411  }
412
413  const supertype: Map = %RawDownCast<Map>(
414      LoadFixedArrayElement(objectSupertypes, rttSupertypeLength));
415
416  if (supertype == rtt) return 1;
417  return 0;
418}
419
420builtin WasmInt32ToNumber(value: int32): Number {
421  return ChangeInt32ToTagged(value);
422}
423
424builtin WasmUint32ToNumber(value: uint32): Number {
425  return ChangeUint32ToTagged(value);
426}
427
428builtin UintPtr53ToNumber(value: uintptr): Number {
429  if (value <= kSmiMaxValue) return Convert<Smi>(Convert<intptr>(value));
430  const valueFloat = ChangeUintPtrToFloat64(value);
431  // Values need to be within [0..2^53], such that they can be represented as
432  // float64.
433  dcheck(ChangeFloat64ToUintPtr(valueFloat) == value);
434  return AllocateHeapNumberWithValue(valueFloat);
435}
436
437extern builtin I64ToBigInt(intptr): BigInt;
438
439builtin WasmAtomicNotify(offset: uintptr, count: uint32): uint32 {
440  const instance: WasmInstanceObject = LoadInstanceFromFrame();
441  const result: Smi = runtime::WasmAtomicNotify(
442      LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset),
443      WasmUint32ToNumber(count));
444  return Unsigned(SmiToInt32(result));
445}
446
447builtin WasmI32AtomicWait64(
448    offset: uintptr, expectedValue: int32, timeout: intptr): uint32 {
449  if constexpr (Is64()) {
450    const instance: WasmInstanceObject = LoadInstanceFromFrame();
451    const result: Smi = runtime::WasmI32AtomicWait(
452        LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset),
453        WasmInt32ToNumber(expectedValue), I64ToBigInt(timeout));
454    return Unsigned(SmiToInt32(result));
455  } else {
456    unreachable;
457  }
458}
459
460builtin WasmI64AtomicWait64(
461    offset: uintptr, expectedValue: intptr, timeout: intptr): uint32 {
462  if constexpr (Is64()) {
463    const instance: WasmInstanceObject = LoadInstanceFromFrame();
464    const result: Smi = runtime::WasmI64AtomicWait(
465        LoadContextFromInstance(instance), instance, UintPtr53ToNumber(offset),
466        I64ToBigInt(expectedValue), I64ToBigInt(timeout));
467    return Unsigned(SmiToInt32(result));
468  } else {
469    unreachable;
470  }
471}
472
473// Type feedback collection support for `call_ref`.
474
475extern macro GetCodeEntry(Code): RawPtr;
476extern macro GetCodeEntry(CodeDataContainer): RawPtr;
477
478struct TargetAndInstance {
479  target: RawPtr;
480  instance: HeapObject;  // WasmInstanceObject or WasmApiFunctionRef
481}
482
483macro GetTargetAndInstance(funcref: WasmInternalFunction): TargetAndInstance {
484  const ref = funcref.ref;
485  let target = funcref.foreign_address_ptr;
486  if (Signed(target) == IntPtrConstant(0)) {
487    target = GetCodeEntry(funcref.code);
488  }
489  return TargetAndInstance{target: target, instance: ref};
490}
491
492// Vector format:
493// Two slots per call_ref instruction. These slots' values can be:
494// - uninitialized: (0, <unused>). Note: we use {0} as the sentinel because
495//   it also works as default for vector slots used as counts.
496// - monomorphic: (funcref, count (smi)). The second slot is a counter for how
497//   often the funcref in the first slot has been seen.
498// - polymorphic: (fixed_array, <unused>). In this case, the array
499//   contains 2..4 pairs (funcref, count (smi)) (like monomorphic data).
500// - megamorphic: ("megamorphic" sentinel, <unused>)
501//
502// TODO(rstz): The counter might overflow if it exceeds the range of a Smi.
503// This can lead to incorrect inlining decisions.
504builtin CallRefIC(
505    vector: FixedArray, index: intptr,
506    funcref: WasmInternalFunction): TargetAndInstance {
507  const value = vector.objects[index];
508  if (value == funcref) {
509    // Monomorphic hit. Check for this case first to maximize its performance.
510    const count = UnsafeCast<Smi>(vector.objects[index + 1]) + SmiConstant(1);
511    vector.objects[index + 1] = count;
512    return GetTargetAndInstance(funcref);
513  }
514  // Check for polymorphic hit; its performance is second-most-important.
515  if (Is<FixedArray>(value)) {
516    const entries = UnsafeCast<FixedArray>(value);
517    for (let i: intptr = 0; i < entries.length_intptr; i += 2) {
518      if (entries.objects[i] == funcref) {
519        // Polymorphic hit.
520        const count = UnsafeCast<Smi>(entries.objects[i + 1]) + SmiConstant(1);
521        entries.objects[i + 1] = count;
522        return GetTargetAndInstance(funcref);
523      }
524    }
525  }
526  // All other cases are some sort of miss and must compute the target/
527  // instance. They all fall through to returning the computed data.
528  const result = GetTargetAndInstance(funcref);
529  if (TaggedEqual(value, SmiConstant(0))) {
530    // Was uninitialized.
531    vector.objects[index] = funcref;
532    vector.objects[index + 1] = SmiConstant(1);
533  } else if (Is<FixedArray>(value)) {
534    // Polymorphic miss.
535    const entries = UnsafeCast<FixedArray>(value);
536    if (entries.length == SmiConstant(8)) {  // 4 entries, 2 slots each.
537      vector.objects[index] = ic::kMegamorphicSymbol;
538      vector.objects[index + 1] = ic::kMegamorphicSymbol;
539    } else {
540      const newEntries = UnsafeCast<FixedArray>(AllocateFixedArray(
541          ElementsKind::PACKED_ELEMENTS, entries.length_intptr + 2,
542          AllocationFlag::kNone));
543      for (let i: intptr = 0; i < entries.length_intptr; i++) {
544        newEntries.objects[i] = entries.objects[i];
545      }
546      const newIndex = entries.length_intptr;
547      newEntries.objects[newIndex] = funcref;
548      newEntries.objects[newIndex + 1] = SmiConstant(1);
549      vector.objects[index] = newEntries;
550    }
551  } else if (Is<WasmInternalFunction>(value)) {
552    // Monomorphic miss.
553    const newEntries = UnsafeCast<FixedArray>(AllocateFixedArray(
554        ElementsKind::PACKED_ELEMENTS, 4, AllocationFlag::kNone));
555    newEntries.objects[0] = value;
556    newEntries.objects[1] = vector.objects[index + 1];
557    newEntries.objects[2] = funcref;
558    newEntries.objects[3] = SmiConstant(1);
559    vector.objects[index] = newEntries;
560    // Clear the first entry's counter; the specific value we write doesn't
561    // matter.
562    vector.objects[index + 1] = Undefined;
563  }
564  // The "ic::IsMegamorphic(value)" case doesn't need to do anything.
565  return result;
566}
567
568extern macro TryHasOwnProperty(HeapObject, Map, InstanceType, Name): never
569    labels Found, NotFound, Bailout;
570type OnNonExistent constexpr 'OnNonExistent';
571const kReturnUndefined: constexpr OnNonExistent
572    generates 'OnNonExistent::kReturnUndefined';
573extern macro SmiConstant(constexpr OnNonExistent): Smi;
574extern transitioning builtin GetPropertyWithReceiver(implicit context: Context)(
575    JSAny, Name, JSAny, Smi): JSAny;
576
577transitioning builtin WasmGetOwnProperty(implicit context: Context)(
578    object: Object, uniqueName: Name): JSAny {
579  try {
580    const heapObject: HeapObject =
581        TaggedToHeapObject(object) otherwise NotFound;
582    const receiver: JSReceiver =
583        Cast<JSReceiver>(heapObject) otherwise NotFound;
584    try {
585      TryHasOwnProperty(
586          receiver, receiver.map, receiver.instanceType, uniqueName)
587          otherwise Found, NotFound, NotFound;
588    } label Found {
589      tail GetPropertyWithReceiver(
590          receiver, uniqueName, receiver, SmiConstant(kReturnUndefined));
591    }
592  } label NotFound deferred {
593    return Undefined;
594  }
595}
596
597// Trap builtins.
598
599builtin WasmTrap(error: Smi): JSAny {
600  tail runtime::ThrowWasmError(LoadContextFromFrame(), error);
601}
602
603builtin ThrowWasmTrapUnreachable(): JSAny {
604  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable));
605}
606
607builtin ThrowWasmTrapMemOutOfBounds(): JSAny {
608  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapMemOutOfBounds));
609}
610
611builtin ThrowWasmTrapUnalignedAccess(): JSAny {
612  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnalignedAccess));
613}
614
615builtin ThrowWasmTrapDivByZero(): JSAny {
616  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivByZero));
617}
618
619builtin ThrowWasmTrapDivUnrepresentable(): JSAny {
620  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDivUnrepresentable));
621}
622
623builtin ThrowWasmTrapRemByZero(): JSAny {
624  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRemByZero));
625}
626
627builtin ThrowWasmTrapFloatUnrepresentable(): JSAny {
628  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFloatUnrepresentable));
629}
630
631builtin ThrowWasmTrapFuncSigMismatch(): JSAny {
632  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapFuncSigMismatch));
633}
634
635builtin ThrowWasmTrapDataSegmentOutOfBounds(): JSAny {
636  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapDataSegmentOutOfBounds));
637}
638
639builtin ThrowWasmTrapElemSegmentDropped(): JSAny {
640  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapElemSegmentDropped));
641}
642
643builtin ThrowWasmTrapTableOutOfBounds(): JSAny {
644  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapTableOutOfBounds));
645}
646
647builtin ThrowWasmTrapRethrowNull(): JSAny {
648  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapRethrowNull));
649}
650
651builtin ThrowWasmTrapNullDereference(): JSAny {
652  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapNullDereference));
653}
654
655builtin ThrowWasmTrapIllegalCast(): JSAny {
656  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapIllegalCast));
657}
658
659builtin ThrowWasmTrapArrayOutOfBounds(): JSAny {
660  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayOutOfBounds));
661}
662
663builtin ThrowWasmTrapArrayTooLarge(): JSAny {
664  tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapArrayTooLarge));
665}
666}
667