[wasm-gc] Store instance/element size directly on Map
It must be possible to determine an object's size on the heap without relying on the presence of any other objects. Specifically, if an object and its WasmTypeInfo die at the same time, they can be swept in any order, and the sweeper may need to know their sizes. This patch solves the problem by repurposing two bytes in the Map, where WasmStructs can store their instance size, and WasmArrays can store their element size (which can be used to compute their size). Fixed: chromium:1240670 Change-Id: Ib960fd0a409936aff1aef4daafed4c38b8497880 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3106649 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/main@{#76391}
This commit is contained in:
parent
cedb1121fe
commit
30f5140fb0
@ -466,6 +466,28 @@ void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) {
|
||||
DCHECK_EQ(unused_in_property_array, UnusedPropertyFields());
|
||||
}
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
uint8_t Map::WasmByte1() const {
|
||||
DCHECK(IsWasmObjectMap());
|
||||
return inobject_properties_start_or_constructor_function_index();
|
||||
}
|
||||
|
||||
uint8_t Map::WasmByte2() const {
|
||||
DCHECK(IsWasmObjectMap());
|
||||
return used_or_unused_instance_size_in_words();
|
||||
}
|
||||
|
||||
void Map::SetWasmByte1(uint8_t value) {
|
||||
CHECK(IsWasmObjectMap());
|
||||
set_inobject_properties_start_or_constructor_function_index(value);
|
||||
}
|
||||
|
||||
void Map::SetWasmByte2(uint8_t value) {
|
||||
CHECK(IsWasmObjectMap());
|
||||
set_used_or_unused_instance_size_in_words(value);
|
||||
}
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
byte Map::bit_field() const {
|
||||
// TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the
|
||||
// map's store synchronization.
|
||||
|
@ -850,6 +850,12 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
|
||||
InstanceType instance_type);
|
||||
inline bool CanHaveFastTransitionableElementsKind() const;
|
||||
|
||||
// Maps for Wasm objects can use certain fields for other purposes.
|
||||
inline uint8_t WasmByte1() const;
|
||||
inline uint8_t WasmByte2() const;
|
||||
inline void SetWasmByte1(uint8_t value);
|
||||
inline void SetWasmByte2(uint8_t value);
|
||||
|
||||
private:
|
||||
// This byte encodes either the instance size without the in-object slack or
|
||||
// the slack size in properties backing store.
|
||||
|
@ -727,7 +727,7 @@ class WasmArray::BodyDescriptor final : public BodyDescriptorBase {
|
||||
}
|
||||
|
||||
static inline int SizeOf(Map map, HeapObject object) {
|
||||
return WasmArray::GcSafeSizeFor(map, WasmArray::cast(object).length());
|
||||
return WasmArray::SizeFor(map, WasmArray::cast(object).length());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2291,7 +2291,7 @@ int HeapObject::SizeFromMap(Map map) const {
|
||||
return WasmStruct::GcSafeSize(map);
|
||||
}
|
||||
if (instance_type == WASM_ARRAY_TYPE) {
|
||||
return WasmArray::GcSafeSizeFor(map, WasmArray::cast(*this).length());
|
||||
return WasmArray::SizeFor(map, WasmArray::cast(*this).length());
|
||||
}
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE);
|
||||
|
@ -163,6 +163,7 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
|
||||
map->SetInstanceDescriptors(isolate, *descriptors,
|
||||
descriptors->number_of_descriptors());
|
||||
map->set_is_extensible(false);
|
||||
WasmStruct::EncodeInstanceSizeInMap(real_instance_size, *map);
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -188,6 +189,8 @@ Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
|
||||
map->SetInstanceDescriptors(isolate, *descriptors,
|
||||
descriptors->number_of_descriptors());
|
||||
map->set_is_extensible(false);
|
||||
WasmArray::EncodeElementSizeInMap(type->element_type().element_size_bytes(),
|
||||
*map);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -558,11 +558,26 @@ int WasmStruct::Size(const wasm::StructType* type) {
|
||||
Heap::kMinObjectSizeInTaggedWords * kTaggedSize);
|
||||
}
|
||||
|
||||
int WasmStruct::GcSafeSize(Map map) {
|
||||
wasm::StructType* type = GcSafeType(map);
|
||||
return Size(type);
|
||||
// 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) {
|
||||
@ -613,12 +628,7 @@ wasm::ArrayType* WasmArray::GcSafeType(Map map) {
|
||||
wasm::ArrayType* WasmArray::type() const { return type(map()); }
|
||||
|
||||
int WasmArray::SizeFor(Map map, int length) {
|
||||
int element_size = type(map)->element_type().element_size_bytes();
|
||||
return kHeaderSize + RoundUp(element_size * length, kTaggedSize);
|
||||
}
|
||||
|
||||
int WasmArray::GcSafeSizeFor(Map map, int length) {
|
||||
int element_size = GcSafeType(map)->element_type().element_size_bytes();
|
||||
int element_size = DecodeElementSizeFromMap(map);
|
||||
return kHeaderSize + RoundUp(element_size * length, kTaggedSize);
|
||||
}
|
||||
|
||||
@ -634,6 +644,14 @@ Handle<Object> WasmArray::GetElement(Isolate* isolate, Handle<WasmArray> array,
|
||||
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
|
||||
|
@ -901,6 +901,8 @@ class WasmStruct : public TorqueGeneratedWasmStruct<WasmStruct, WasmObject> {
|
||||
static inline wasm::StructType* GcSafeType(Map map);
|
||||
static inline int Size(const wasm::StructType* type);
|
||||
static inline int GcSafeSize(Map map);
|
||||
static inline void EncodeInstanceSizeInMap(int instance_size, Map map);
|
||||
static inline int DecodeInstanceSizeFromMap(Map map);
|
||||
|
||||
// Returns the address of the field at given offset.
|
||||
inline Address RawFieldAddress(int raw_offset);
|
||||
@ -937,7 +939,6 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
|
||||
wasm::WasmValue GetElement(uint32_t index);
|
||||
|
||||
static inline int SizeFor(Map map, int length);
|
||||
static inline int GcSafeSizeFor(Map map, int length);
|
||||
|
||||
// Returns boxed value of the array's element.
|
||||
static inline Handle<Object> GetElement(Isolate* isolate,
|
||||
@ -955,6 +956,9 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
|
||||
return (SmiTagging<4>::kSmiMaxValue - kHeaderSize) >> element_shift;
|
||||
}
|
||||
|
||||
static inline void EncodeElementSizeInMap(int element_size, Map map);
|
||||
static inline int DecodeElementSizeFromMap(Map map);
|
||||
|
||||
DECL_PRINTER(WasmArray)
|
||||
|
||||
class BodyDescriptor;
|
||||
|
Loading…
Reference in New Issue
Block a user