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