[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:
Jakob Kummerow 2021-08-19 14:18:56 +02:00 committed by V8 LUCI CQ
parent cedb1121fe
commit 30f5140fb0
7 changed files with 65 additions and 12 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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());
}
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;