| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #if !V8_ENABLE_WEBASSEMBLY |
| #error This header should only be included if WebAssembly is enabled. |
| #endif // !V8_ENABLE_WEBASSEMBLY |
| |
| #ifndef V8_WASM_WASM_OBJECTS_INL_H_ |
| #define V8_WASM_WASM_OBJECTS_INL_H_ |
| |
| #include <type_traits> |
| |
| #include "src/base/memory.h" |
| #include "src/heap/heap-write-barrier-inl.h" |
| #include "src/objects/contexts-inl.h" |
| #include "src/objects/foreign.h" |
| #include "src/objects/heap-number.h" |
| #include "src/objects/js-array-buffer-inl.h" |
| #include "src/objects/js-function-inl.h" |
| #include "src/objects/js-objects-inl.h" |
| #include "src/objects/managed.h" |
| #include "src/objects/oddball-inl.h" |
| #include "src/objects/script-inl.h" |
| #include "src/roots/roots.h" |
| #include "src/wasm/wasm-code-manager.h" |
| #include "src/wasm/wasm-module.h" |
| #include "src/wasm/wasm-objects.h" |
| |
| // Has to be the last include (doesn't have include guards) |
| #include "src/objects/object-macros.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #include "torque-generated/src/wasm/wasm-objects-tq-inl.inc" |
| |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTagObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExportedFunctionData) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmGlobalObject) |
| OBJECT_CONSTRUCTORS_IMPL(WasmInstanceObject, JSObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmMemoryObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmModuleObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTableObject) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(AsmWasmData) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmFunctionData) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmTypeInfo) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmStruct) |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmArray) |
| |
| CAST_ACCESSOR(WasmInstanceObject) |
| |
| #define OPTIONAL_ACCESSORS(holder, name, type, offset) \ |
| DEF_GETTER(holder, has_##name, bool) { \ |
| Object value = TaggedField<Object, offset>::load(cage_base, *this); \ |
| return !value.IsUndefined(GetReadOnlyRoots(cage_base)); \ |
| } \ |
| ACCESSORS_CHECKED2(holder, name, type, offset, \ |
| !value.IsUndefined(GetReadOnlyRoots(cage_base)), true) |
| |
| #define PRIMITIVE_ACCESSORS(holder, name, type, offset) \ |
| type holder::name() const { \ |
| if (COMPRESS_POINTERS_BOOL && alignof(type) > kTaggedSize) { \ |
| /* TODO(ishell, v8:8875): When pointer compression is enabled 8-byte */ \ |
| /* size fields (external pointers, doubles and BigInt data) are only */ \ |
| /* kTaggedSize aligned so we have to use unaligned pointer friendly */ \ |
| /* way of accessing them in order to avoid undefined behavior in C++ */ \ |
| /* code. */ \ |
| return base::ReadUnalignedValue<type>(FIELD_ADDR(*this, offset)); \ |
| } else { \ |
| return *reinterpret_cast<type const*>(FIELD_ADDR(*this, offset)); \ |
| } \ |
| } \ |
| void holder::set_##name(type value) { \ |
| if (COMPRESS_POINTERS_BOOL && alignof(type) > kTaggedSize) { \ |
| /* TODO(ishell, v8:8875): When pointer compression is enabled 8-byte */ \ |
| /* size fields (external pointers, doubles and BigInt data) are only */ \ |
| /* kTaggedSize aligned so we have to use unaligned pointer friendly */ \ |
| /* way of accessing them in order to avoid undefined behavior in C++ */ \ |
| /* code. */ \ |
| base::WriteUnalignedValue<type>(FIELD_ADDR(*this, offset), value); \ |
| } else { \ |
| *reinterpret_cast<type*>(FIELD_ADDR(*this, offset)) = value; \ |
| } \ |
| } |
| |
| // WasmModuleObject |
| wasm::NativeModule* WasmModuleObject::native_module() const { |
| return managed_native_module().raw(); |
| } |
| const std::shared_ptr<wasm::NativeModule>& |
| WasmModuleObject::shared_native_module() const { |
| return managed_native_module().get(); |
| } |
| const wasm::WasmModule* WasmModuleObject::module() const { |
| // TODO(clemensb): Remove this helper (inline in callers). |
| return native_module()->module(); |
| } |
| bool WasmModuleObject::is_asm_js() { |
| bool asm_js = is_asmjs_module(module()); |
| DCHECK_EQ(asm_js, script().IsUserJavaScript()); |
| return asm_js; |
| } |
| |
| // WasmMemoryObject |
| OPTIONAL_ACCESSORS(WasmMemoryObject, instances, WeakArrayList, kInstancesOffset) |
| |
| // WasmGlobalObject |
| ACCESSORS(WasmGlobalObject, untagged_buffer, JSArrayBuffer, |
| kUntaggedBufferOffset) |
| ACCESSORS(WasmGlobalObject, tagged_buffer, FixedArray, kTaggedBufferOffset) |
| |
| wasm::ValueType WasmGlobalObject::type() const { |
| return wasm::ValueType::FromRawBitField(static_cast<uint32_t>(raw_type())); |
| } |
| void WasmGlobalObject::set_type(wasm::ValueType value) { |
| set_raw_type(static_cast<int>(value.raw_bit_field())); |
| } |
| |
| int WasmGlobalObject::type_size() const { return type().element_size_bytes(); } |
| |
| Address WasmGlobalObject::address() const { |
| DCHECK_NE(type(), wasm::kWasmExternRef); |
| DCHECK_LE(offset() + type_size(), untagged_buffer().byte_length()); |
| return Address(untagged_buffer().backing_store()) + offset(); |
| } |
| |
| int32_t WasmGlobalObject::GetI32() { |
| return base::ReadUnalignedValue<int32_t>(address()); |
| } |
| |
| int64_t WasmGlobalObject::GetI64() { |
| return base::ReadUnalignedValue<int64_t>(address()); |
| } |
| |
| float WasmGlobalObject::GetF32() { |
| return base::ReadUnalignedValue<float>(address()); |
| } |
| |
| double WasmGlobalObject::GetF64() { |
| return base::ReadUnalignedValue<double>(address()); |
| } |
| |
| Handle<Object> WasmGlobalObject::GetRef() { |
| // We use this getter for externref and funcref. |
| DCHECK(type().is_reference()); |
| return handle(tagged_buffer().get(offset()), GetIsolate()); |
| } |
| |
| void WasmGlobalObject::SetI32(int32_t value) { |
| base::WriteUnalignedValue(address(), value); |
| } |
| |
| void WasmGlobalObject::SetI64(int64_t value) { |
| base::WriteUnalignedValue(address(), value); |
| } |
| |
| void WasmGlobalObject::SetF32(float value) { |
| base::WriteUnalignedValue(address(), value); |
| } |
| |
| void WasmGlobalObject::SetF64(double value) { |
| base::WriteUnalignedValue(address(), value); |
| } |
| |
| void WasmGlobalObject::SetExternRef(Handle<Object> value) { |
| DCHECK(type().is_reference_to(wasm::HeapType::kExtern) || |
| type().is_reference_to(wasm::HeapType::kAny)); |
| tagged_buffer().set(offset(), *value); |
| } |
| |
| bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) { |
| DCHECK_EQ(type(), wasm::kWasmFuncRef); |
| if (!value->IsNull(isolate) && |
| !WasmExternalFunction::IsWasmExternalFunction(*value) && |
| !WasmCapiFunction::IsWasmCapiFunction(*value)) { |
| return false; |
| } |
| tagged_buffer().set(offset(), *value); |
| return true; |
| } |
| |
| // WasmInstanceObject |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_start, byte*, kMemoryStartOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, memory_size, size_t, kMemorySizeOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, isolate_root, Address, |
| kIsolateRootOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, stack_limit_address, Address, |
| kStackLimitAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, real_stack_limit_address, Address, |
| kRealStackLimitAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_limit_address, Address*, |
| kNewAllocationLimitAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, new_allocation_top_address, Address*, |
| kNewAllocationTopAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_limit_address, Address*, |
| kOldAllocationLimitAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, old_allocation_top_address, Address*, |
| kOldAllocationTopAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_function_targets, Address*, |
| kImportedFunctionTargetsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, globals_start, byte*, |
| kGlobalsStartOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, imported_mutable_globals, Address*, |
| kImportedMutableGlobalsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_size, uint32_t, |
| kIndirectFunctionTableSizeOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_sig_ids, |
| uint32_t*, kIndirectFunctionTableSigIdsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, indirect_function_table_targets, |
| Address*, kIndirectFunctionTableTargetsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, jump_table_start, Address, |
| kJumpTableStartOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_starts, Address*, |
| kDataSegmentStartsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, data_segment_sizes, uint32_t*, |
| kDataSegmentSizesOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, dropped_elem_segments, byte*, |
| kDroppedElemSegmentsOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, hook_on_function_call_address, Address, |
| kHookOnFunctionCallAddressOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, num_liftoff_function_calls_array, |
| uint32_t*, kNumLiftoffFunctionCallsArrayOffset) |
| PRIMITIVE_ACCESSORS(WasmInstanceObject, break_on_entry, uint8_t, |
| kBreakOnEntryOffset) |
| |
| ACCESSORS(WasmInstanceObject, module_object, WasmModuleObject, |
| kModuleObjectOffset) |
| ACCESSORS(WasmInstanceObject, exports_object, JSObject, kExportsObjectOffset) |
| ACCESSORS(WasmInstanceObject, native_context, Context, kNativeContextOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, WasmMemoryObject, |
| kMemoryObjectOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, untagged_globals_buffer, JSArrayBuffer, |
| kUntaggedGlobalsBufferOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, tagged_globals_buffer, FixedArray, |
| kTaggedGlobalsBufferOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, imported_mutable_globals_buffers, |
| FixedArray, kImportedMutableGlobalsBuffersOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, tables, FixedArray, kTablesOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_tables, FixedArray, |
| kIndirectFunctionTablesOffset) |
| ACCESSORS(WasmInstanceObject, imported_function_refs, FixedArray, |
| kImportedFunctionRefsOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, indirect_function_table_refs, FixedArray, |
| kIndirectFunctionTableRefsOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, managed_native_allocations, Foreign, |
| kManagedNativeAllocationsOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, tags_table, FixedArray, kTagsTableOffset) |
| OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_external_functions, FixedArray, |
| kWasmExternalFunctionsOffset) |
| ACCESSORS(WasmInstanceObject, managed_object_maps, FixedArray, |
| kManagedObjectMapsOffset) |
| |
| void WasmInstanceObject::clear_padding() { |
| if (FIELD_SIZE(kOptionalPaddingOffset) != 0) { |
| DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset)); |
| memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0, |
| FIELD_SIZE(kOptionalPaddingOffset)); |
| } |
| } |
| |
| IndirectFunctionTableEntry::IndirectFunctionTableEntry( |
| Handle<WasmInstanceObject> instance, int table_index, int entry_index) |
| : instance_(table_index == 0 ? instance |
| : Handle<WasmInstanceObject>::null()), |
| table_(table_index != 0 |
| ? handle(WasmIndirectFunctionTable::cast( |
| instance->indirect_function_tables().get( |
| table_index)), |
| instance->GetIsolate()) |
| : Handle<WasmIndirectFunctionTable>::null()), |
| index_(entry_index) { |
| DCHECK_GE(entry_index, 0); |
| DCHECK_LT(entry_index, table_index == 0 |
| ? instance->indirect_function_table_size() |
| : table_->size()); |
| } |
| |
| IndirectFunctionTableEntry::IndirectFunctionTableEntry( |
| Handle<WasmIndirectFunctionTable> table, int entry_index) |
| : instance_(Handle<WasmInstanceObject>::null()), |
| table_(table), |
| index_(entry_index) { |
| DCHECK_GE(entry_index, 0); |
| DCHECK_LT(entry_index, table_->size()); |
| } |
| |
| ImportedFunctionEntry::ImportedFunctionEntry( |
| Handle<WasmInstanceObject> instance, int index) |
| : instance_(instance), index_(index) { |
| DCHECK_GE(index, 0); |
| DCHECK_LT(index, instance->module()->num_imported_functions); |
| } |
| |
| // WasmExceptionPackage |
| OBJECT_CONSTRUCTORS_IMPL(WasmExceptionPackage, JSObject) |
| CAST_ACCESSOR(WasmExceptionPackage) |
| |
| // WasmExportedFunction |
| WasmExportedFunction::WasmExportedFunction(Address ptr) : JSFunction(ptr) { |
| SLOW_DCHECK(IsWasmExportedFunction(*this)); |
| } |
| CAST_ACCESSOR(WasmExportedFunction) |
| |
| // WasmFunctionData |
| ACCESSORS(WasmFunctionData, ref, Object, kRefOffset) |
| |
| DEF_GETTER(WasmFunctionData, wrapper_code, Code) { |
| return FromCodeT(TorqueGeneratedClass::wrapper_code(cage_base)); |
| } |
| void WasmFunctionData::set_wrapper_code(Code code, WriteBarrierMode mode) { |
| TorqueGeneratedClass::set_wrapper_code(ToCodeT(code), mode); |
| } |
| |
| wasm::FunctionSig* WasmExportedFunctionData::sig() const { |
| return reinterpret_cast<wasm::FunctionSig*>(signature().foreign_address()); |
| } |
| |
| // WasmJSFunction |
| WasmJSFunction::WasmJSFunction(Address ptr) : JSFunction(ptr) { |
| SLOW_DCHECK(IsWasmJSFunction(*this)); |
| } |
| CAST_ACCESSOR(WasmJSFunction) |
| |
| // WasmJSFunctionData |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmJSFunctionData) |
| ACCESSORS(WasmJSFunctionData, raw_wasm_to_js_wrapper_code, CodeT, |
| kWasmToJsWrapperCodeOffset) |
| |
| DEF_GETTER(WasmJSFunctionData, wasm_to_js_wrapper_code, Code) { |
| return FromCodeT(raw_wasm_to_js_wrapper_code(cage_base)); |
| } |
| void WasmJSFunctionData::set_wasm_to_js_wrapper_code(Code code, |
| WriteBarrierMode mode) { |
| set_raw_wasm_to_js_wrapper_code(ToCodeT(code), mode); |
| } |
| |
| // WasmCapiFunction |
| WasmCapiFunction::WasmCapiFunction(Address ptr) : JSFunction(ptr) { |
| SLOW_DCHECK(IsWasmCapiFunction(*this)); |
| } |
| CAST_ACCESSOR(WasmCapiFunction) |
| |
| // WasmExternalFunction |
| WasmExternalFunction::WasmExternalFunction(Address ptr) : JSFunction(ptr) { |
| SLOW_DCHECK(IsWasmExternalFunction(*this)); |
| } |
| CAST_ACCESSOR(WasmExternalFunction) |
| |
| // WasmIndirectFunctionTable |
| TQ_OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable) |
| PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, sig_ids, uint32_t*, |
| kSigIdsOffset) |
| PRIMITIVE_ACCESSORS(WasmIndirectFunctionTable, targets, Address*, |
| kTargetsOffset) |
| OPTIONAL_ACCESSORS(WasmIndirectFunctionTable, managed_native_allocations, |
| Foreign, kManagedNativeAllocationsOffset) |
| |
| #undef OPTIONAL_ACCESSORS |
| #undef READ_PRIMITIVE_FIELD |
| #undef WRITE_PRIMITIVE_FIELD |
| #undef PRIMITIVE_ACCESSORS |
| |
| wasm::ValueType WasmTableObject::type() { |
| return wasm::ValueType::FromRawBitField(raw_type()); |
| } |
| |
| bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; } |
| |
| // static |
| Handle<Object> WasmObject::ReadValueAt(Isolate* isolate, Handle<HeapObject> obj, |
| wasm::ValueType type, uint32_t offset) { |
| Address field_address = obj->GetFieldAddress(offset); |
| switch (type.kind()) { |
| case wasm::kI8: { |
| int8_t value = base::Memory<int8_t>(field_address); |
| return handle(Smi::FromInt(value), isolate); |
| } |
| case wasm::kI16: { |
| int16_t value = base::Memory<int16_t>(field_address); |
| return handle(Smi::FromInt(value), isolate); |
| } |
| case wasm::kI32: { |
| int32_t value = base::Memory<int32_t>(field_address); |
| return isolate->factory()->NewNumberFromInt(value); |
| } |
| case wasm::kI64: { |
| int64_t value = base::ReadUnalignedValue<int64_t>(field_address); |
| return BigInt::FromInt64(isolate, value); |
| } |
| case wasm::kF32: { |
| float value = base::Memory<float>(field_address); |
| return isolate->factory()->NewNumber(value); |
| } |
| case wasm::kF64: { |
| double value = base::ReadUnalignedValue<double>(field_address); |
| return isolate->factory()->NewNumber(value); |
| } |
| case wasm::kS128: |
| // TODO(v8:11804): implement |
| UNREACHABLE(); |
| |
| case wasm::kRef: |
| case wasm::kOptRef: { |
| ObjectSlot slot(field_address); |
| return handle(slot.load(isolate), isolate); |
| } |
| |
| case wasm::kRtt: |
| case wasm::kRttWithDepth: |
| // Rtt values are not supposed to be made available to JavaScript side. |
| UNREACHABLE(); |
| |
| case wasm::kVoid: |
| case wasm::kBottom: |
| UNREACHABLE(); |
| } |
| } |
| |
| // static |
| MaybeHandle<Object> WasmObject::ToWasmValue(Isolate* isolate, |
| wasm::ValueType type, |
| Handle<Object> value) { |
| switch (type.kind()) { |
| case wasm::kI8: |
| case wasm::kI16: |
| case wasm::kI32: |
| case wasm::kF32: |
| case wasm::kF64: |
| return Object::ToNumber(isolate, value); |
| |
| case wasm::kI64: |
| return BigInt::FromObject(isolate, value); |
| |
| case wasm::kRef: |
| case wasm::kOptRef: { |
| // TODO(v8:11804): implement ref type check |
| UNREACHABLE(); |
| } |
| |
| case wasm::kS128: |
| // TODO(v8:11804): implement |
| UNREACHABLE(); |
| |
| case wasm::kRtt: |
| case wasm::kRttWithDepth: |
| // Rtt values are not supposed to be made available to JavaScript side. |
| UNREACHABLE(); |
| |
| case wasm::kVoid: |
| case wasm::kBottom: |
| UNREACHABLE(); |
| } |
| } |
| |
| // Conversions from Numeric objects. |
| // static |
| template <typename ElementType> |
| ElementType WasmObject::FromNumber(Object value) { |
| // The value must already be prepared for storing to numeric fields. |
| DCHECK(value.IsNumber()); |
| if (value.IsSmi()) { |
| return static_cast<ElementType>(Smi::ToInt(value)); |
| |
| } else if (value.IsHeapNumber()) { |
| double double_value = HeapNumber::cast(value).value(); |
| if (std::is_same<ElementType, double>::value || |
| std::is_same<ElementType, float>::value) { |
| return static_cast<ElementType>(double_value); |
| } else { |
| CHECK(std::is_integral<ElementType>::value); |
| return static_cast<ElementType>(DoubleToInt32(double_value)); |
| } |
| } |
| UNREACHABLE(); |
| } |
| |
| // static |
| void WasmObject::WriteValueAt(Isolate* isolate, Handle<HeapObject> obj, |
| wasm::ValueType type, uint32_t offset, |
| Handle<Object> value) { |
| Address field_address = obj->GetFieldAddress(offset); |
| switch (type.kind()) { |
| case wasm::kI8: { |
| auto scalar_value = FromNumber<int8_t>(*value); |
| base::Memory<int8_t>(field_address) = scalar_value; |
| break; |
| } |
| case wasm::kI16: { |
| auto scalar_value = FromNumber<int16_t>(*value); |
| base::Memory<int16_t>(field_address) = scalar_value; |
| break; |
| } |
| case wasm::kI32: { |
| auto scalar_value = FromNumber<int32_t>(*value); |
| base::Memory<int32_t>(field_address) = scalar_value; |
| break; |
| } |
| case wasm::kI64: { |
| int64_t scalar_value = BigInt::cast(*value).AsInt64(); |
| base::WriteUnalignedValue<int64_t>(field_address, scalar_value); |
| break; |
| } |
| case wasm::kF32: { |
| auto scalar_value = FromNumber<float>(*value); |
| base::Memory<float>(field_address) = scalar_value; |
| break; |
| } |
| case wasm::kF64: { |
| auto scalar_value = FromNumber<double>(*value); |
| base::WriteUnalignedValue<double>(field_address, scalar_value); |
| break; |
| } |
| case wasm::kRef: |
| case wasm::kOptRef: |
| // TODO(v8:11804): implement |
| UNREACHABLE(); |
| |
| case wasm::kS128: |
| // TODO(v8:11804): implement |
| UNREACHABLE(); |
| |
| case wasm::kRtt: |
| case wasm::kRttWithDepth: |
| // Rtt values are not supposed to be made available to JavaScript side. |
| UNREACHABLE(); |
| |
| case wasm::kVoid: |
| case wasm::kBottom: |
| UNREACHABLE(); |
| } |
| } |
| |
| wasm::StructType* WasmStruct::type(Map map) { |
| WasmTypeInfo type_info = map.wasm_type_info(); |
| return reinterpret_cast<wasm::StructType*>(type_info.foreign_address()); |
| } |
| |
| wasm::StructType* WasmStruct::GcSafeType(Map map) { |
| DCHECK_EQ(WASM_STRUCT_TYPE, map.instance_type()); |
| HeapObject raw = HeapObject::cast(map.constructor_or_back_pointer()); |
| MapWord map_word = raw.map_word(kRelaxedLoad); |
| HeapObject forwarded = |
| map_word.IsForwardingAddress() ? map_word.ToForwardingAddress() : raw; |
| Foreign foreign = Foreign::cast(forwarded); |
| return reinterpret_cast<wasm::StructType*>(foreign.foreign_address()); |
| } |
| |
| int WasmStruct::Size(const wasm::StructType* type) { |
| // Object size must fit into a Smi (because of filler objects), and its |
| // computation must not overflow. |
| STATIC_ASSERT(Smi::kMaxValue <= kMaxInt); |
| DCHECK_LE(type->total_fields_size(), Smi::kMaxValue - kHeaderSize); |
| return std::max(kHeaderSize + static_cast<int>(type->total_fields_size()), |
| Heap::kMinObjectSizeInTaggedWords * kTaggedSize); |
| } |
| |
| // static |
| void WasmStruct::EncodeInstanceSizeInMap(int instance_size, Map map) { |
| // WasmStructs can be bigger than the {map.instance_size_in_words} field |
| // can describe; yet we have to store the instance size somewhere on the |
| // map so that the GC can read it without relying on any other objects |
| // still being around. To solve this problem, we store the instance size |
| // in two other fields that are otherwise unused for WasmStructs. |
| STATIC_ASSERT(0xFFFF - kHeaderSize > |
| wasm::kMaxValueTypeSize * wasm::kV8MaxWasmStructFields); |
| map.SetWasmByte1(instance_size & 0xFF); |
| map.SetWasmByte2(instance_size >> 8); |
| } |
| |
| // static |
| int WasmStruct::DecodeInstanceSizeFromMap(Map map) { |
| return (map.WasmByte2() << 8) | map.WasmByte1(); |
| } |
| |
| int WasmStruct::GcSafeSize(Map map) { return DecodeInstanceSizeFromMap(map); } |
| |
| wasm::StructType* WasmStruct::type() const { return type(map()); } |
| |
| Address WasmStruct::RawFieldAddress(int raw_offset) { |
| int offset = WasmStruct::kHeaderSize + raw_offset; |
| return FIELD_ADDR(*this, offset); |
| } |
| |
| ObjectSlot WasmStruct::RawField(int raw_offset) { |
| return ObjectSlot(RawFieldAddress(raw_offset)); |
| } |
| |
| // static |
| Handle<Object> WasmStruct::GetField(Isolate* isolate, Handle<WasmStruct> obj, |
| uint32_t field_index) { |
| wasm::StructType* type = obj->type(); |
| CHECK_LT(field_index, type->field_count()); |
| wasm::ValueType field_type = type->field(field_index); |
| int offset = WasmStruct::kHeaderSize + type->field_offset(field_index); |
| return ReadValueAt(isolate, obj, field_type, offset); |
| } |
| |
| // static |
| void WasmStruct::SetField(Isolate* isolate, Handle<WasmStruct> obj, |
| uint32_t field_index, Handle<Object> value) { |
| wasm::StructType* type = obj->type(); |
| CHECK_LT(field_index, type->field_count()); |
| wasm::ValueType field_type = type->field(field_index); |
| int offset = WasmStruct::kHeaderSize + type->field_offset(field_index); |
| WriteValueAt(isolate, obj, field_type, offset, value); |
| } |
| |
| wasm::ArrayType* WasmArray::type(Map map) { |
| DCHECK_EQ(WASM_ARRAY_TYPE, map.instance_type()); |
| WasmTypeInfo type_info = map.wasm_type_info(); |
| return reinterpret_cast<wasm::ArrayType*>(type_info.foreign_address()); |
| } |
| |
| wasm::ArrayType* WasmArray::GcSafeType(Map map) { |
| DCHECK_EQ(WASM_ARRAY_TYPE, map.instance_type()); |
| HeapObject raw = HeapObject::cast(map.constructor_or_back_pointer()); |
| MapWord map_word = raw.map_word(kRelaxedLoad); |
| HeapObject forwarded = |
| map_word.IsForwardingAddress() ? map_word.ToForwardingAddress() : raw; |
| Foreign foreign = Foreign::cast(forwarded); |
| return reinterpret_cast<wasm::ArrayType*>(foreign.foreign_address()); |
| } |
| |
| wasm::ArrayType* WasmArray::type() const { return type(map()); } |
| |
| int WasmArray::SizeFor(Map map, int length) { |
| int element_size = DecodeElementSizeFromMap(map); |
| return kHeaderSize + RoundUp(element_size * length, kTaggedSize); |
| } |
| |
| // static |
| Handle<Object> WasmArray::GetElement(Isolate* isolate, Handle<WasmArray> array, |
| uint32_t index) { |
| if (index >= array->length()) { |
| return isolate->factory()->undefined_value(); |
| } |
| wasm::ValueType element_type = array->type()->element_type(); |
| uint32_t offset = |
| WasmArray::kHeaderSize + index * element_type.element_size_bytes(); |
| return ReadValueAt(isolate, array, element_type, offset); |
| } |
| |
| // static |
| void WasmArray::EncodeElementSizeInMap(int element_size, Map map) { |
| map.SetWasmByte1(element_size); |
| } |
| |
| // static |
| int WasmArray::DecodeElementSizeFromMap(Map map) { return map.WasmByte1(); } |
| |
| void WasmTypeInfo::clear_foreign_address(Isolate* isolate) { |
| #ifdef V8_HEAP_SANDBOX |
| // Due to the type-specific pointer tags for external pointers, we need to |
| // allocate an entry in the table here even though it will just store nullptr. |
| AllocateExternalPointerEntries(isolate); |
| #endif |
| set_foreign_address(isolate, 0); |
| } |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_WASM_WASM_OBJECTS_INL_H_ |