1// Copyright 2017 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#if !V8_ENABLE_WEBASSEMBLY
6#error This header should only be included if WebAssembly is enabled.
7#endif  // !V8_ENABLE_WEBASSEMBLY
8
9#ifndef V8_WASM_WASM_OBJECTS_INL_H_
10#define V8_WASM_WASM_OBJECTS_INL_H_
11
12#include <type_traits>
13
14#include "src/base/memory.h"
15#include "src/common/ptr-compr.h"
16#include "src/heap/heap-write-barrier-inl.h"
17#include "src/objects/contexts-inl.h"
18#include "src/objects/foreign.h"
19#include "src/objects/heap-number.h"
20#include "src/objects/js-array-buffer-inl.h"
21#include "src/objects/js-function-inl.h"
22#include "src/objects/js-objects-inl.h"
23#include "src/objects/managed.h"
24#include "src/objects/oddball-inl.h"
25#include "src/objects/script-inl.h"
26#include "src/roots/roots.h"
27#include "src/wasm/wasm-code-manager.h"
28#include "src/wasm/wasm-module.h"
29#include "src/wasm/wasm-objects.h"
30
31// Has to be the last include (doesn't have include guards)
32#include "src/objects/object-macros.h"
33
34namespace v8 {
35namespace internal {
36
37#include "torque-generated/src/wasm/wasm-objects-tq-inl.inc"
38
39TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTagObject)
40TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag)
41TQ_OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData)
42TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExportedFunctionData)
43TQ_OBJECT_CONSTRUCTORS_IMPL(WasmGlobalObject)
44OBJECT_CONSTRUCTORS_IMPL(WasmInstanceObject, JSObject)
45TQ_OBJECT_CONSTRUCTORS_IMPL(WasmObject)
46TQ_OBJECT_CONSTRUCTORS_IMPL(WasmMemoryObject)
47TQ_OBJECT_CONSTRUCTORS_IMPL(WasmModuleObject)
48TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTableObject)
49TQ_OBJECT_CONSTRUCTORS_IMPL(AsmWasmData)
50TQ_OBJECT_CONSTRUCTORS_IMPL(WasmFunctionData)
51TQ_OBJECT_CONSTRUCTORS_IMPL(WasmApiFunctionRef)
52TQ_OBJECT_CONSTRUCTORS_IMPL(WasmInternalFunction)
53TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo)
54TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct)
55TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray)
56TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject)
57TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject)
58TQ_OBJECT_CONSTRUCTORS_IMPL(WasmOnFulfilledData)
59
60CAST_ACCESSOR(WasmInstanceObject)
61
62#define OPTIONAL_ACCESSORS(holder, name, type, offset)                  \
63  DEF_GETTER(holder, has_##name, bool) {                                \
64    Object value = TaggedField<Object, offset>::load(cage_base, *this); \
65    return !value.IsUndefined(GetReadOnlyRoots(cage_base));             \
66  }                                                                     \
67  ACCESSORS_CHECKED2(holder, name, type, offset,                        \
68                     !value.IsUndefined(GetReadOnlyRoots(cage_base)), true)
69
70#define PRIMITIVE_ACCESSORS(holder, name, type, offset)               \
71  type holder::name() const {                                         \
72    return ReadMaybeUnalignedValue<type>(FIELD_ADDR(*this, offset));  \
73  }                                                                   \
74  void holder::set_##name(type value) {                               \
75    WriteMaybeUnalignedValue<type>(FIELD_ADDR(*this, offset), value); \
76  }
77
78#define SANDBOXED_POINTER_ACCESSORS(holder, name, type, offset)      \
79  type holder::name() const {                                        \
80    PtrComprCageBase sandbox_base = GetPtrComprCageBase(*this);      \
81    Address value = ReadSandboxedPointerField(offset, sandbox_base); \
82    return reinterpret_cast<type>(value);                            \
83  }                                                                  \
84  void holder::set_##name(type value) {                              \
85    PtrComprCageBase sandbox_base = GetPtrComprCageBase(*this);      \
86    Address addr = reinterpret_cast<Address>(value);                 \
87    WriteSandboxedPointerField(offset, sandbox_base, addr);          \
88  }
89
90// WasmModuleObject
91wasm::NativeModule* WasmModuleObject::native_module() const {
92  return managed_native_module().raw();
93}
94const std::shared_ptr<wasm::NativeModule>&
95WasmModuleObject::shared_native_module() const {
96  return managed_native_module().get();
97}
98const wasm::WasmModule* WasmModuleObject::module() const {
99  // TODO(clemensb): Remove this helper (inline in callers).
100  return native_module()->module();
101}
102bool WasmModuleObject::is_asm_js() {
103  bool asm_js = is_asmjs_module(module());
104  DCHECK_EQ(asm_js, script().IsUserJavaScript());
105  return asm_js;
106}
107
108// WasmMemoryObject
109OPTIONAL_ACCESSORS(WasmMemoryObject, instances, WeakArrayList, kInstancesOffset)
110
111// WasmGlobalObject
112ACCESSORS(WasmGlobalObject, untagged_buffer, JSArrayBuffer,
113          kUntaggedBufferOffset)
114ACCESSORS(WasmGlobalObject, tagged_buffer, FixedArray, kTaggedBufferOffset)
115
116wasm::ValueType WasmGlobalObject::type() const {
117  return wasm::ValueType::FromRawBitField(static_cast<uint32_t>(raw_type()));
118}
119void WasmGlobalObject::set_type(wasm::ValueType value) {
120  set_raw_type(static_cast<int>(value.raw_bit_field()));
121}
122
123int WasmGlobalObject::type_size() const { return type().value_kind_size(); }
124
125Address WasmGlobalObject::address() const {
126  DCHECK_NE(type(), wasm::kWasmAnyRef);
127  DCHECK_LE(offset() + type_size(), untagged_buffer().byte_length());
128  return Address(untagged_buffer().backing_store()) + offset();
129}
130
131int32_t WasmGlobalObject::GetI32() {
132  return base::ReadUnalignedValue<int32_t>(address());
133}
134
135int64_t WasmGlobalObject::GetI64() {
136  return base::ReadUnalignedValue<int64_t>(address());
137}
138
139float WasmGlobalObject::GetF32() {
140  return base::ReadUnalignedValue<float>(address());
141}
142
143double WasmGlobalObject::GetF64() {
144  return base::ReadUnalignedValue<double>(address());
145}
146
147Handle<Object> WasmGlobalObject::GetRef() {
148  // We use this getter for externref and funcref.
149  DCHECK(type().is_reference());
150  return handle(tagged_buffer().get(offset()), GetIsolate());
151}
152
153void WasmGlobalObject::SetI32(int32_t value) {
154  base::WriteUnalignedValue(address(), value);
155}
156
157void WasmGlobalObject::SetI64(int64_t value) {
158  base::WriteUnalignedValue(address(), value);
159}
160
161void WasmGlobalObject::SetF32(float value) {
162  base::WriteUnalignedValue(address(), value);
163}
164
165void WasmGlobalObject::SetF64(double value) {
166  base::WriteUnalignedValue(address(), value);
167}
168
169void WasmGlobalObject::SetExternRef(Handle<Object> value) {
170  DCHECK(type().is_reference_to(wasm::HeapType::kAny));
171  tagged_buffer().set(offset(), *value);
172}
173
174bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) {
175  DCHECK_EQ(type(), wasm::kWasmFuncRef);
176  if (value->IsNull() ||
177      WasmInternalFunction::FromExternal(value, isolate).ToHandle(&value)) {
178    tagged_buffer().set(offset(), *value);
179    return true;
180  }
181  return false;
182}
183
184// WasmInstanceObject
185SANDBOXED_POINTER_ACCESSORS(WasmInstanceObject, memory_start, byte*,
186                            kMemoryStartOffset)
187PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_size, size_t, kMemorySizeOffset)
188PRIMITIVE_ACCESSORS(WasmInstanceObject, isolate_root, Address,
189                    kIsolateRootOffset)
190PRIMITIVE_ACCESSORS(WasmInstanceObject, stack_limit_address, Address,
191                    kStackLimitAddressOffset)
192PRIMITIVE_ACCESSORS(WasmInstanceObject, real_stack_limit_address, Address,
193                    kRealStackLimitAddressOffset)
194PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_limit_address, Address*,
195                    kNewAllocationLimitAddressOffset)
196PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_top_address, Address*,
197                    kNewAllocationTopAddressOffset)
198PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_limit_address, Address*,
199                    kOldAllocationLimitAddressOffset)
200PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_top_address, Address*,
201                    kOldAllocationTopAddressOffset)
202PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_function_targets, Address*,
203                    kImportedFunctionTargetsOffset)
204PRIMITIVE_ACCESSORS(WasmInstanceObject, globals_start, byte*,
205                    kGlobalsStartOffset)
206PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_mutable_globals, Address*,
207                    kImportedMutableGlobalsOffset)
208PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_size, uint32_t,
209                    kIndirectFunctionTableSizeOffset)
210PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_sig_ids,
211                    uint32_t*, kIndirectFunctionTableSigIdsOffset)
212PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_targets,
213                    Address*, kIndirectFunctionTableTargetsOffset)
214PRIMITIVE_ACCESSORS(WasmInstanceObject, jump_table_start, Address,
215                    kJumpTableStartOffset)
216PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_starts, Address*,
217                    kDataSegmentStartsOffset)
218PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_sizes, uint32_t*,
219                    kDataSegmentSizesOffset)
220PRIMITIVE_ACCESSORS(WasmInstanceObject, dropped_elem_segments, byte*,
221                    kDroppedElemSegmentsOffset)
222PRIMITIVE_ACCESSORS(WasmInstanceObject, hook_on_function_call_address, Address,
223                    kHookOnFunctionCallAddressOffset)
224PRIMITIVE_ACCESSORS(WasmInstanceObject, tiering_budget_array, uint32_t*,
225                    kTieringBudgetArrayOffset)
226PRIMITIVE_ACCESSORS(WasmInstanceObject, break_on_entry, uint8_t,
227                    kBreakOnEntryOffset)
228
229ACCESSORS(WasmInstanceObject, module_object, WasmModuleObject,
230          kModuleObjectOffset)
231ACCESSORS(WasmInstanceObject, exports_object, JSObject, kExportsObjectOffset)
232ACCESSORS(WasmInstanceObject, native_context, Context, kNativeContextOffset)
233OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, WasmMemoryObject,
234                   kMemoryObjectOffset)
235OPTIONAL_ACCESSORS(WasmInstanceObject, untagged_globals_buffer, JSArrayBuffer,
236                   kUntaggedGlobalsBufferOffset)
237OPTIONAL_ACCESSORS(WasmInstanceObject, tagged_globals_buffer, FixedArray,
238                   kTaggedGlobalsBufferOffset)
239OPTIONAL_ACCESSORS(WasmInstanceObject, imported_mutable_globals_buffers,
240                   FixedArray, kImportedMutableGlobalsBuffersOffset)
241OPTIONAL_ACCESSORS(WasmInstanceObject, tables, FixedArray, kTablesOffset)
242OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_tables, FixedArray,
243                   kIndirectFunctionTablesOffset)
244ACCESSORS(WasmInstanceObject, imported_function_refs, FixedArray,
245          kImportedFunctionRefsOffset)
246OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_table_refs, FixedArray,
247                   kIndirectFunctionTableRefsOffset)
248OPTIONAL_ACCESSORS(WasmInstanceObject, managed_native_allocations, Foreign,
249                   kManagedNativeAllocationsOffset)
250OPTIONAL_ACCESSORS(WasmInstanceObject, tags_table, FixedArray, kTagsTableOffset)
251OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_internal_functions, FixedArray,
252                   kWasmInternalFunctionsOffset)
253ACCESSORS(WasmInstanceObject, managed_object_maps, FixedArray,
254          kManagedObjectMapsOffset)
255ACCESSORS(WasmInstanceObject, feedback_vectors, FixedArray,
256          kFeedbackVectorsOffset)
257
258void WasmInstanceObject::clear_padding() {
259  if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
260    DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
261    memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
262           FIELD_SIZE(kOptionalPaddingOffset));
263  }
264}
265
266ImportedFunctionEntry::ImportedFunctionEntry(
267    Handle<WasmInstanceObject> instance, int index)
268    : instance_(instance), index_(index) {
269  DCHECK_GE(index, 0);
270  DCHECK_LT(index, instance->module()->num_imported_functions);
271}
272
273// WasmExceptionPackage
274OBJECT_CONSTRUCTORS_IMPL(WasmExceptionPackage, JSObject)
275CAST_ACCESSOR(WasmExceptionPackage)
276
277// WasmExportedFunction
278WasmExportedFunction::WasmExportedFunction(Address ptr) : JSFunction(ptr) {
279  SLOW_DCHECK(IsWasmExportedFunction(*this));
280}
281CAST_ACCESSOR(WasmExportedFunction)
282
283// WasmFunctionData
284ACCESSORS(WasmFunctionData, internal, WasmInternalFunction, kInternalOffset)
285
286wasm::FunctionSig* WasmExportedFunctionData::sig() const {
287  return reinterpret_cast<wasm::FunctionSig*>(signature().foreign_address());
288}
289
290// WasmJSFunction
291WasmJSFunction::WasmJSFunction(Address ptr) : JSFunction(ptr) {
292  SLOW_DCHECK(IsWasmJSFunction(*this));
293}
294CAST_ACCESSOR(WasmJSFunction)
295
296// WasmJSFunctionData
297TQ_OBJECT_CONSTRUCTORS_IMPL(WasmJSFunctionData)
298
299// WasmCapiFunction
300WasmCapiFunction::WasmCapiFunction(Address ptr) : JSFunction(ptr) {
301  SLOW_DCHECK(IsWasmCapiFunction(*this));
302}
303CAST_ACCESSOR(WasmCapiFunction)
304
305// WasmExternalFunction
306WasmExternalFunction::WasmExternalFunction(Address ptr) : JSFunction(ptr) {
307  SLOW_DCHECK(IsWasmExternalFunction(*this));
308}
309CAST_ACCESSOR(WasmExternalFunction)
310
311// WasmIndirectFunctionTable
312TQ_OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable)
313PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, sig_ids, uint32_t*,
314                    kSigIdsOffset)
315PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, targets, Address*,
316                    kTargetsOffset)
317OPTIONAL_ACCESSORS(WasmIndirectFunctionTable, managed_native_allocations,
318                   Foreign, kManagedNativeAllocationsOffset)
319
320#undef OPTIONAL_ACCESSORS
321#undef READ_PRIMITIVE_FIELD
322#undef WRITE_PRIMITIVE_FIELD
323#undef PRIMITIVE_ACCESSORS
324
325wasm::ValueType WasmTableObject::type() {
326  return wasm::ValueType::FromRawBitField(raw_type());
327}
328
329bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; }
330
331// static
332Handle<Object> WasmObject::ReadValueAt(Isolate* isolate, Handle<HeapObject> obj,
333                                       wasm::ValueType type, uint32_t offset) {
334  Address field_address = obj->GetFieldAddress(offset);
335  switch (type.kind()) {
336    case wasm::kI8: {
337      int8_t value = base::Memory<int8_t>(field_address);
338      return handle(Smi::FromInt(value), isolate);
339    }
340    case wasm::kI16: {
341      int16_t value = base::Memory<int16_t>(field_address);
342      return handle(Smi::FromInt(value), isolate);
343    }
344    case wasm::kI32: {
345      int32_t value = base::Memory<int32_t>(field_address);
346      return isolate->factory()->NewNumberFromInt(value);
347    }
348    case wasm::kI64: {
349      int64_t value = base::ReadUnalignedValue<int64_t>(field_address);
350      return BigInt::FromInt64(isolate, value);
351    }
352    case wasm::kF32: {
353      float value = base::Memory<float>(field_address);
354      return isolate->factory()->NewNumber(value);
355    }
356    case wasm::kF64: {
357      double value = base::ReadUnalignedValue<double>(field_address);
358      return isolate->factory()->NewNumber(value);
359    }
360    case wasm::kS128:
361      // TODO(v8:11804): implement
362      UNREACHABLE();
363
364    case wasm::kRef:
365    case wasm::kOptRef: {
366      ObjectSlot slot(field_address);
367      return handle(slot.load(isolate), isolate);
368    }
369
370    case wasm::kRtt:
371      // Rtt values are not supposed to be made available to JavaScript side.
372      UNREACHABLE();
373
374    case wasm::kVoid:
375    case wasm::kBottom:
376      UNREACHABLE();
377  }
378}
379
380// static
381MaybeHandle<Object> WasmObject::ToWasmValue(Isolate* isolate,
382                                            wasm::ValueType type,
383                                            Handle<Object> value) {
384  switch (type.kind()) {
385    case wasm::kI8:
386    case wasm::kI16:
387    case wasm::kI32:
388    case wasm::kF32:
389    case wasm::kF64:
390      return Object::ToNumber(isolate, value);
391
392    case wasm::kI64:
393      return BigInt::FromObject(isolate, value);
394
395    case wasm::kRef:
396    case wasm::kOptRef: {
397      // TODO(v8:11804): implement ref type check
398      UNREACHABLE();
399    }
400
401    case wasm::kS128:
402      // TODO(v8:11804): implement
403      UNREACHABLE();
404
405    case wasm::kRtt:
406      // Rtt values are not supposed to be made available to JavaScript side.
407      UNREACHABLE();
408
409    case wasm::kVoid:
410    case wasm::kBottom:
411      UNREACHABLE();
412  }
413}
414
415// Conversions from Numeric objects.
416// static
417template <typename ElementType>
418ElementType WasmObject::FromNumber(Object value) {
419  // The value must already be prepared for storing to numeric fields.
420  DCHECK(value.IsNumber());
421  if (value.IsSmi()) {
422    return static_cast<ElementType>(Smi::ToInt(value));
423
424  } else if (value.IsHeapNumber()) {
425    double double_value = HeapNumber::cast(value).value();
426    if (std::is_same<ElementType, double>::value ||
427        std::is_same<ElementType, float>::value) {
428      return static_cast<ElementType>(double_value);
429    } else {
430      CHECK(std::is_integral<ElementType>::value);
431      return static_cast<ElementType>(DoubleToInt32(double_value));
432    }
433  }
434  UNREACHABLE();
435}
436
437// static
438void WasmObject::WriteValueAt(Isolate* isolate, Handle<HeapObject> obj,
439                              wasm::ValueType type, uint32_t offset,
440                              Handle<Object> value) {
441  Address field_address = obj->GetFieldAddress(offset);
442  switch (type.kind()) {
443    case wasm::kI8: {
444      auto scalar_value = FromNumber<int8_t>(*value);
445      base::Memory<int8_t>(field_address) = scalar_value;
446      break;
447    }
448    case wasm::kI16: {
449      auto scalar_value = FromNumber<int16_t>(*value);
450      base::Memory<int16_t>(field_address) = scalar_value;
451      break;
452    }
453    case wasm::kI32: {
454      auto scalar_value = FromNumber<int32_t>(*value);
455      base::Memory<int32_t>(field_address) = scalar_value;
456      break;
457    }
458    case wasm::kI64: {
459      int64_t scalar_value = BigInt::cast(*value).AsInt64();
460      base::WriteUnalignedValue<int64_t>(field_address, scalar_value);
461      break;
462    }
463    case wasm::kF32: {
464      auto scalar_value = FromNumber<float>(*value);
465      base::Memory<float>(field_address) = scalar_value;
466      break;
467    }
468    case wasm::kF64: {
469      auto scalar_value = FromNumber<double>(*value);
470      base::WriteUnalignedValue<double>(field_address, scalar_value);
471      break;
472    }
473    case wasm::kRef:
474    case wasm::kOptRef:
475      // TODO(v8:11804): implement
476      UNREACHABLE();
477
478    case wasm::kS128:
479      // TODO(v8:11804): implement
480      UNREACHABLE();
481
482    case wasm::kRtt:
483      // Rtt values are not supposed to be made available to JavaScript side.
484      UNREACHABLE();
485
486    case wasm::kVoid:
487    case wasm::kBottom:
488      UNREACHABLE();
489  }
490}
491
492wasm::StructType* WasmStruct::type(Map map) {
493  WasmTypeInfo type_info = map.wasm_type_info();
494  return reinterpret_cast<wasm::StructType*>(type_info.foreign_address());
495}
496
497wasm::StructType* WasmStruct::GcSafeType(Map map) {
498  DCHECK_EQ(WASM_STRUCT_TYPE, map.instance_type());
499  HeapObject raw = HeapObject::cast(map.constructor_or_back_pointer());
500  // The {Foreign} might be in the middle of being moved, which is why we
501  // can't read its map for a checked cast. But we can rely on its payload
502  // being intact in the old location.
503  Foreign foreign = Foreign::unchecked_cast(raw);
504  return reinterpret_cast<wasm::StructType*>(foreign.foreign_address());
505}
506
507int WasmStruct::Size(const wasm::StructType* type) {
508  // Object size must fit into a Smi (because of filler objects), and its
509  // computation must not overflow.
510  STATIC_ASSERT(Smi::kMaxValue <= kMaxInt);
511  DCHECK_LE(type->total_fields_size(), Smi::kMaxValue - kHeaderSize);
512  return std::max(kHeaderSize + static_cast<int>(type->total_fields_size()),
513                  Heap::kMinObjectSizeInTaggedWords * kTaggedSize);
514}
515
516// static
517void WasmStruct::EncodeInstanceSizeInMap(int instance_size, Map map) {
518  // WasmStructs can be bigger than the {map.instance_size_in_words} field
519  // can describe; yet we have to store the instance size somewhere on the
520  // map so that the GC can read it without relying on any other objects
521  // still being around. To solve this problem, we store the instance size
522  // in two other fields that are otherwise unused for WasmStructs.
523  STATIC_ASSERT(0xFFFF - kHeaderSize >
524                wasm::kMaxValueTypeSize * wasm::kV8MaxWasmStructFields);
525  map.SetWasmByte1(instance_size & 0xFF);
526  map.SetWasmByte2(instance_size >> 8);
527}
528
529// static
530int WasmStruct::DecodeInstanceSizeFromMap(Map map) {
531  return (map.WasmByte2() << 8) | map.WasmByte1();
532}
533
534int WasmStruct::GcSafeSize(Map map) { return DecodeInstanceSizeFromMap(map); }
535
536wasm::StructType* WasmStruct::type() const { return type(map()); }
537
538Address WasmStruct::RawFieldAddress(int raw_offset) {
539  int offset = WasmStruct::kHeaderSize + raw_offset;
540  return FIELD_ADDR(*this, offset);
541}
542
543ObjectSlot WasmStruct::RawField(int raw_offset) {
544  return ObjectSlot(RawFieldAddress(raw_offset));
545}
546
547// static
548Handle<Object> WasmStruct::GetField(Isolate* isolate, Handle<WasmStruct> obj,
549                                    uint32_t field_index) {
550  wasm::StructType* type = obj->type();
551  CHECK_LT(field_index, type->field_count());
552  wasm::ValueType field_type = type->field(field_index);
553  int offset = WasmStruct::kHeaderSize + type->field_offset(field_index);
554  return ReadValueAt(isolate, obj, field_type, offset);
555}
556
557// static
558void WasmStruct::SetField(Isolate* isolate, Handle<WasmStruct> obj,
559                          uint32_t field_index, Handle<Object> value) {
560  wasm::StructType* type = obj->type();
561  CHECK_LT(field_index, type->field_count());
562  wasm::ValueType field_type = type->field(field_index);
563  int offset = WasmStruct::kHeaderSize + type->field_offset(field_index);
564  WriteValueAt(isolate, obj, field_type, offset, value);
565}
566
567wasm::ArrayType* WasmArray::type(Map map) {
568  DCHECK_EQ(WASM_ARRAY_TYPE, map.instance_type());
569  WasmTypeInfo type_info = map.wasm_type_info();
570  return reinterpret_cast<wasm::ArrayType*>(type_info.foreign_address());
571}
572
573wasm::ArrayType* WasmArray::GcSafeType(Map map) {
574  DCHECK_EQ(WASM_ARRAY_TYPE, map.instance_type());
575  HeapObject raw = HeapObject::cast(map.constructor_or_back_pointer());
576  // The {Foreign} might be in the middle of being moved, which is why we
577  // can't read its map for a checked cast. But we can rely on its payload
578  // being intact in the old location.
579  Foreign foreign = Foreign::unchecked_cast(raw);
580  return reinterpret_cast<wasm::ArrayType*>(foreign.foreign_address());
581}
582
583wasm::ArrayType* WasmArray::type() const { return type(map()); }
584
585int WasmArray::SizeFor(Map map, int length) {
586  int element_size = DecodeElementSizeFromMap(map);
587  return kHeaderSize + RoundUp(element_size * length, kTaggedSize);
588}
589
590uint32_t WasmArray::element_offset(uint32_t index) {
591  DCHECK_LE(index, length());
592  return WasmArray::kHeaderSize +
593         index * type()->element_type().value_kind_size();
594}
595
596Address WasmArray::ElementAddress(uint32_t index) {
597  return ptr() + element_offset(index) - kHeapObjectTag;
598}
599
600ObjectSlot WasmArray::ElementSlot(uint32_t index) {
601  DCHECK_LE(index, length());
602  DCHECK(type()->element_type().is_reference());
603  return RawField(kHeaderSize + kTaggedSize * index);
604}
605
606// static
607Handle<Object> WasmArray::GetElement(Isolate* isolate, Handle<WasmArray> array,
608                                     uint32_t index) {
609  if (index >= array->length()) {
610    return isolate->factory()->undefined_value();
611  }
612  wasm::ValueType element_type = array->type()->element_type();
613  return ReadValueAt(isolate, array, element_type,
614                     array->element_offset(index));
615}
616
617// static
618void WasmArray::EncodeElementSizeInMap(int element_size, Map map) {
619  map.SetWasmByte1(element_size);
620}
621
622// static
623int WasmArray::DecodeElementSizeFromMap(Map map) { return map.WasmByte1(); }
624
625void WasmTypeInfo::clear_foreign_address(Isolate* isolate) {
626#ifdef V8_SANDBOXED_EXTERNAL_POINTERS
627  // Due to the type-specific pointer tags for external pointers, we need to
628  // allocate an entry in the table here even though it will just store nullptr.
629  AllocateExternalPointerEntries(isolate);
630#endif
631  set_foreign_address(isolate, 0);
632}
633
634#include "src/objects/object-macros-undef.h"
635
636}  // namespace internal
637}  // namespace v8
638
639#endif  // V8_WASM_WASM_OBJECTS_INL_H_
640