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