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