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
34 namespace v8 {
35 namespace internal {
36
37 #include "torque-generated/src/wasm/wasm-objects-tq-inl.inc"
38
39 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTagObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag)40 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag)
41 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData)
42 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExportedFunctionData)
43 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmGlobalObject)
44 OBJECT_CONSTRUCTORS_IMPL(WasmInstanceObject, JSObject)
45 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmObject)
46 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmMemoryObject)
47 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmModuleObject)
48 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTableObject)
49 TQ_OBJECT_CONSTRUCTORS_IMPL(AsmWasmData)
50 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmFunctionData)
51 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmApiFunctionRef)
52 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmInternalFunction)
53 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo)
54 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct)
55 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray)
56 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmContinuationObject)
57 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmSuspenderObject)
58 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmOnFulfilledData)
59
60 CAST_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
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().value_kind_size(); }
124
address()125 Address 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
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::kAny));
171 tagged_buffer().set(offset(), *value);
172 }
173
SetFuncRef(Isolate * isolate,Handle<Object> value)174 bool 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
SANDBOXED_POINTER_ACCESSORS(WasmInstanceObject,memory_start,byte *,kMemoryStartOffset)185 SANDBOXED_POINTER_ACCESSORS(WasmInstanceObject, memory_start, byte*,
186 kMemoryStartOffset)
187 PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_size, size_t, kMemorySizeOffset)
188 PRIMITIVE_ACCESSORS(WasmInstanceObject, isolate_root, Address,
189 kIsolateRootOffset)
190 PRIMITIVE_ACCESSORS(WasmInstanceObject, stack_limit_address, Address,
191 kStackLimitAddressOffset)
192 PRIMITIVE_ACCESSORS(WasmInstanceObject, real_stack_limit_address, Address,
193 kRealStackLimitAddressOffset)
194 PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_limit_address, Address*,
195 kNewAllocationLimitAddressOffset)
196 PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_top_address, Address*,
197 kNewAllocationTopAddressOffset)
198 PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_limit_address, Address*,
199 kOldAllocationLimitAddressOffset)
200 PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_top_address, Address*,
201 kOldAllocationTopAddressOffset)
202 PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_function_targets, Address*,
203 kImportedFunctionTargetsOffset)
204 PRIMITIVE_ACCESSORS(WasmInstanceObject, globals_start, byte*,
205 kGlobalsStartOffset)
206 PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_mutable_globals, Address*,
207 kImportedMutableGlobalsOffset)
208 PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_size, uint32_t,
209 kIndirectFunctionTableSizeOffset)
210 PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_sig_ids,
211 uint32_t*, kIndirectFunctionTableSigIdsOffset)
212 PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_targets,
213 Address*, kIndirectFunctionTableTargetsOffset)
214 PRIMITIVE_ACCESSORS(WasmInstanceObject, jump_table_start, Address,
215 kJumpTableStartOffset)
216 PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_starts, Address*,
217 kDataSegmentStartsOffset)
218 PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_sizes, uint32_t*,
219 kDataSegmentSizesOffset)
220 PRIMITIVE_ACCESSORS(WasmInstanceObject, dropped_elem_segments, byte*,
221 kDroppedElemSegmentsOffset)
222 PRIMITIVE_ACCESSORS(WasmInstanceObject, hook_on_function_call_address, Address,
223 kHookOnFunctionCallAddressOffset)
224 PRIMITIVE_ACCESSORS(WasmInstanceObject, tiering_budget_array, uint32_t*,
225 kTieringBudgetArrayOffset)
226 PRIMITIVE_ACCESSORS(WasmInstanceObject, break_on_entry, uint8_t,
227 kBreakOnEntryOffset)
228
229 ACCESSORS(WasmInstanceObject, module_object, WasmModuleObject,
230 kModuleObjectOffset)
231 ACCESSORS(WasmInstanceObject, exports_object, JSObject, kExportsObjectOffset)
232 ACCESSORS(WasmInstanceObject, native_context, Context, kNativeContextOffset)
233 OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, WasmMemoryObject,
234 kMemoryObjectOffset)
235 OPTIONAL_ACCESSORS(WasmInstanceObject, untagged_globals_buffer, JSArrayBuffer,
236 kUntaggedGlobalsBufferOffset)
237 OPTIONAL_ACCESSORS(WasmInstanceObject, tagged_globals_buffer, FixedArray,
238 kTaggedGlobalsBufferOffset)
239 OPTIONAL_ACCESSORS(WasmInstanceObject, imported_mutable_globals_buffers,
240 FixedArray, kImportedMutableGlobalsBuffersOffset)
241 OPTIONAL_ACCESSORS(WasmInstanceObject, tables, FixedArray, kTablesOffset)
242 OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_tables, FixedArray,
243 kIndirectFunctionTablesOffset)
244 ACCESSORS(WasmInstanceObject, imported_function_refs, FixedArray,
245 kImportedFunctionRefsOffset)
246 OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_table_refs, FixedArray,
247 kIndirectFunctionTableRefsOffset)
248 OPTIONAL_ACCESSORS(WasmInstanceObject, managed_native_allocations, Foreign,
249 kManagedNativeAllocationsOffset)
250 OPTIONAL_ACCESSORS(WasmInstanceObject, tags_table, FixedArray, kTagsTableOffset)
251 OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_internal_functions, FixedArray,
252 kWasmInternalFunctionsOffset)
253 ACCESSORS(WasmInstanceObject, managed_object_maps, FixedArray,
254 kManagedObjectMapsOffset)
255 ACCESSORS(WasmInstanceObject, feedback_vectors, FixedArray,
256 kFeedbackVectorsOffset)
257
258 void 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
ImportedFunctionEntry(Handle<WasmInstanceObject> instance,int index)266 ImportedFunctionEntry::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
OBJECT_CONSTRUCTORS_IMPL(WasmExceptionPackage,JSObject)274 OBJECT_CONSTRUCTORS_IMPL(WasmExceptionPackage, JSObject)
275 CAST_ACCESSOR(WasmExceptionPackage)
276
277 // WasmExportedFunction
278 WasmExportedFunction::WasmExportedFunction(Address ptr) : JSFunction(ptr) {
279 SLOW_DCHECK(IsWasmExportedFunction(*this));
280 }
281 CAST_ACCESSOR(WasmExportedFunction)
282
283 // WasmFunctionData
ACCESSORS(WasmFunctionData,internal,WasmInternalFunction,kInternalOffset)284 ACCESSORS(WasmFunctionData, internal, WasmInternalFunction, kInternalOffset)
285
286 wasm::FunctionSig* WasmExportedFunctionData::sig() const {
287 return reinterpret_cast<wasm::FunctionSig*>(signature().foreign_address());
288 }
289
290 // WasmJSFunction
WasmJSFunction(Address ptr)291 WasmJSFunction::WasmJSFunction(Address ptr) : JSFunction(ptr) {
292 SLOW_DCHECK(IsWasmJSFunction(*this));
293 }
294 CAST_ACCESSOR(WasmJSFunction)
295
296 // WasmJSFunctionData
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmJSFunctionData)297 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmJSFunctionData)
298
299 // WasmCapiFunction
300 WasmCapiFunction::WasmCapiFunction(Address ptr) : JSFunction(ptr) {
301 SLOW_DCHECK(IsWasmCapiFunction(*this));
302 }
CAST_ACCESSOR(WasmCapiFunction)303 CAST_ACCESSOR(WasmCapiFunction)
304
305 // WasmExternalFunction
306 WasmExternalFunction::WasmExternalFunction(Address ptr) : JSFunction(ptr) {
307 SLOW_DCHECK(IsWasmExternalFunction(*this));
308 }
309 CAST_ACCESSOR(WasmExternalFunction)
310
311 // WasmIndirectFunctionTable
TQ_OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable)312 TQ_OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable)
313 PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, sig_ids, uint32_t*,
314 kSigIdsOffset)
315 PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, targets, Address*,
316 kTargetsOffset)
317 OPTIONAL_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
325 wasm::ValueType WasmTableObject::type() {
326 return wasm::ValueType::FromRawBitField(raw_type());
327 }
328
has_maximum_pages()329 bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; }
330
331 // static
ReadValueAt(Isolate * isolate,Handle<HeapObject> obj,wasm::ValueType type,uint32_t offset)332 Handle<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
ToWasmValue(Isolate * isolate,wasm::ValueType type,Handle<Object> value)381 MaybeHandle<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
417 template <typename ElementType>
FromNumber(Object value)418 ElementType 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
WriteValueAt(Isolate * isolate,Handle<HeapObject> obj,wasm::ValueType type,uint32_t offset,Handle<Object> value)438 void 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
type(Map map)492 wasm::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
GcSafeType(Map map)497 wasm::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
Size(const wasm::StructType * type)507 int 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
EncodeInstanceSizeInMap(int instance_size,Map map)517 void 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
DecodeInstanceSizeFromMap(Map map)530 int WasmStruct::DecodeInstanceSizeFromMap(Map map) {
531 return (map.WasmByte2() << 8) | map.WasmByte1();
532 }
533
GcSafeSize(Map map)534 int WasmStruct::GcSafeSize(Map map) { return DecodeInstanceSizeFromMap(map); }
535
type()536 wasm::StructType* WasmStruct::type() const { return type(map()); }
537
RawFieldAddress(int raw_offset)538 Address WasmStruct::RawFieldAddress(int raw_offset) {
539 int offset = WasmStruct::kHeaderSize + raw_offset;
540 return FIELD_ADDR(*this, offset);
541 }
542
RawField(int raw_offset)543 ObjectSlot WasmStruct::RawField(int raw_offset) {
544 return ObjectSlot(RawFieldAddress(raw_offset));
545 }
546
547 // static
GetField(Isolate * isolate,Handle<WasmStruct> obj,uint32_t field_index)548 Handle<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
SetField(Isolate * isolate,Handle<WasmStruct> obj,uint32_t field_index,Handle<Object> value)558 void 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
type(Map map)567 wasm::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
GcSafeType(Map map)573 wasm::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
type()583 wasm::ArrayType* WasmArray::type() const { return type(map()); }
584
SizeFor(Map map,int length)585 int WasmArray::SizeFor(Map map, int length) {
586 int element_size = DecodeElementSizeFromMap(map);
587 return kHeaderSize + RoundUp(element_size * length, kTaggedSize);
588 }
589
element_offset(uint32_t index)590 uint32_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
ElementAddress(uint32_t index)596 Address WasmArray::ElementAddress(uint32_t index) {
597 return ptr() + element_offset(index) - kHeapObjectTag;
598 }
599
ElementSlot(uint32_t index)600 ObjectSlot 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
GetElement(Isolate * isolate,Handle<WasmArray> array,uint32_t index)607 Handle<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
EncodeElementSizeInMap(int element_size,Map map)618 void WasmArray::EncodeElementSizeInMap(int element_size, Map map) {
619 map.SetWasmByte1(element_size);
620 }
621
622 // static
DecodeElementSizeFromMap(Map map)623 int WasmArray::DecodeElementSizeFromMap(Map map) { return map.WasmByte1(); }
624
clear_foreign_address(Isolate * isolate)625 void 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