Commit 38b1bff1 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Support RTTs of generic types ("eqref" etc)

By introducing a globally known map for each generic type.
These maps are never used to allocate objects, they only
serve as sentinels for generic heap types.

Bug: v8:7748
Change-Id: I950a8c712dc1510759a833fe9122b9e9a6222dc2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2288860
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68755}
parent 273f4e42
......@@ -5356,8 +5356,26 @@ Node* WasmGraphBuilder::ArrayNew(uint32_t array_index,
Node* WasmGraphBuilder::RttCanon(wasm::HeapType type) {
if (type.is_generic()) {
// TODO(7748): Implement this.
UNIMPLEMENTED();
switch (type.representation()) {
case wasm::HeapType::kEq:
return LOAD_FULL_POINTER(
BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(RootIndex::kWasmRttEqrefMap));
case wasm::HeapType::kExtern:
return LOAD_FULL_POINTER(
BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(RootIndex::kWasmRttExternrefMap));
case wasm::HeapType::kFunc:
return LOAD_FULL_POINTER(
BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(RootIndex::kWasmRttFuncrefMap));
case wasm::HeapType::kI31:
return LOAD_FULL_POINTER(
BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(RootIndex::kWasmRttI31refMap));
default:
UNREACHABLE();
}
}
// This logic is duplicated from module-instantiate.cc.
// TODO(jkummerow): Find a nicer solution.
......@@ -5375,11 +5393,6 @@ Node* WasmGraphBuilder::RttCanon(wasm::HeapType type) {
}
Node* WasmGraphBuilder::RttSub(wasm::HeapType type, Node* parent_rtt) {
if (type.is_generic()) {
// TODO(7748): Implement this. {type} could be eqref, with {parent_rtt}
// being (rtt.canon anyref).
UNIMPLEMENTED();
}
return CALL_BUILTIN(
WasmAllocateRtt,
graph()->NewNode(
......@@ -5389,6 +5402,8 @@ Node* WasmGraphBuilder::RttSub(wasm::HeapType type, Node* parent_rtt) {
}
Node* WasmGraphBuilder::RefTest(Node* object, Node* rtt) {
// TODO(7748): Check if {object} is null.
// TODO(7748): Check if {object} is an i31ref.
Node* map = gasm_->Load(MachineType::TaggedPointer(), object,
HeapObject::kMapOffset - kHeapObjectTag);
// TODO(7748): Add a fast path for map == rtt.
......@@ -5399,6 +5414,8 @@ Node* WasmGraphBuilder::RefTest(Node* object, Node* rtt) {
Node* WasmGraphBuilder::RefCast(Node* object, Node* rtt,
wasm::WasmCodePosition position) {
// TODO(7748): Check if {object} is null.
// TODO(7748): Check if {object} is an i31ref.
Node* map = gasm_->Load(MachineType::TaggedPointer(), object,
HeapObject::kMapOffset - kHeapObjectTag);
// TODO(7748): Add a fast path for map == rtt.
......
......@@ -128,16 +128,19 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
int inobject_properties) {
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
bool is_js_object = InstanceTypeChecker::IsJSObject(instance_type);
bool is_wasm_object =
(instance_type == WASM_STRUCT_TYPE || instance_type == WASM_ARRAY_TYPE);
DCHECK_IMPLIES(is_js_object &&
!Map::CanHaveFastTransitionableElementsKind(instance_type),
IsDictionaryElementsKind(elements_kind) ||
IsTerminalElementsKind(elements_kind));
HeapObject result;
// JSObjects have maps with a mutable prototype_validity_cell, so they cannot
// go in RO_SPACE.
// go in RO_SPACE. Maps for managed Wasm objects have mutable subtype lists.
bool is_mutable = is_js_object || is_wasm_object;
AllocationResult allocation =
AllocateRaw(Map::kSize, is_js_object ? AllocationType::kMap
: AllocationType::kReadOnly);
AllocateRaw(Map::kSize, is_mutable ? AllocationType::kMap
: AllocationType::kReadOnly);
if (!allocation.To(&result)) return allocation;
result.set_map_after_allocation(ReadOnlyRoots(this).meta_map(),
......@@ -505,6 +508,13 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_MAP(CODE_DATA_CONTAINER_TYPE, CodeDataContainer::kSize,
code_data_container)
// The wasm_rttcanon_* maps are never used for real objects, only as
// sentinels. They are maps so that they fit in with their subtype maps
// (which are real maps).
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_eqref)
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_externref)
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_funcref)
ALLOCATE_MAP(WASM_STRUCT_TYPE, 0, wasm_rttcanon_i31ref)
ALLOCATE_MAP(WASM_TYPE_INFO_TYPE, WasmTypeInfo::kSize, wasm_type_info)
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
......@@ -604,6 +614,36 @@ bool Heap::CreateInitialMaps() {
set_empty_closure_feedback_cell_array(ClosureFeedbackCellArray::cast(obj));
}
// Set up the WasmTypeInfo objects for built-in generic Wasm RTTs.
#define ALLOCATE_TYPE_INFO(which) \
{ \
int slot_count = ArrayList::kHeaderFields; \
if (!AllocateRaw(ArrayList::SizeFor(slot_count), AllocationType::kOld) \
.To(&obj)) { \
return false; \
} \
obj.set_map_after_allocation(roots.array_list_map()); \
ArrayList subtypes = ArrayList::cast(obj); \
subtypes.set_length(slot_count); \
subtypes.SetLength(0); \
if (!AllocateRaw(WasmTypeInfo::kSize, AllocationType::kOld).To(&obj)) { \
return false; \
} \
obj.set_map_after_allocation(roots.wasm_type_info_map(), \
SKIP_WRITE_BARRIER); \
WasmTypeInfo type_info = WasmTypeInfo::cast(obj); \
type_info.set_subtypes(subtypes); \
type_info.set_parent(roots.null_map()); \
type_info.clear_foreign_address(isolate()); \
wasm_rttcanon_##which##_map().set_wasm_type_info(type_info); \
}
ALLOCATE_TYPE_INFO(eqref)
ALLOCATE_TYPE_INFO(externref)
ALLOCATE_TYPE_INFO(funcref)
ALLOCATE_TYPE_INFO(i31ref)
#undef ALLOCATE_TYPE_INFO
DCHECK(!InYoungGeneration(roots.empty_fixed_array()));
roots.bigint_map().SetConstructorFunctionIndex(
......
......@@ -453,11 +453,14 @@ class ArrayList : public TorqueGeneratedArrayList<ArrayList, FixedArray> {
// number returned by Length() is stored in the first entry.
static Handle<FixedArray> Elements(Isolate* isolate, Handle<ArrayList> array);
static const int kHeaderFields = 1;
private:
static Handle<ArrayList> EnsureSpace(Isolate* isolate,
Handle<ArrayList> array, int length);
static const int kLengthIndex = 0;
static const int kFirstIndex = 1;
STATIC_ASSERT(kHeaderFields == kFirstIndex);
TQ_OBJECT_CONSTRUCTORS(ArrayList)
};
......
......@@ -41,6 +41,7 @@ class Foreign : public TorqueGeneratedForeign<Foreign, HeapObject> {
friend class Factory;
friend class SerializerDeserializer;
friend class StartupSerializer;
friend class WasmTypeInfo;
inline void set_foreign_address(Isolate* isolate, Address value);
......
......@@ -208,6 +208,10 @@ class Symbol;
/* Maps */ \
V(Map, external_map, ExternalMap) \
V(Map, message_object_map, JSMessageObjectMap) \
V(Map, wasm_rttcanon_eqref_map, WasmRttEqrefMap) \
V(Map, wasm_rttcanon_externref_map, WasmRttExternrefMap) \
V(Map, wasm_rttcanon_funcref_map, WasmRttFuncrefMap) \
V(Map, wasm_rttcanon_i31ref_map, WasmRttI31refMap) \
/* Canonical empty values */ \
V(Script, empty_script, EmptyScript) \
V(FeedbackCell, many_closures_cell, ManyClosuresCell) \
......
......@@ -513,8 +513,8 @@ class RttSubtypes : public ArrayList {
// here, if empirical data indicates that that would be worthwhile.
int count = array->Length();
for (int i = 0; i < count; i += 2) {
if (Smi::cast(array->get(i)).value() == static_cast<int>(type_index)) {
return Map::cast(array->get(i + 1));
if (Smi::cast(array->Get(i)).value() == static_cast<int>(type_index)) {
return Map::cast(array->Get(i + 1));
}
}
return {};
......@@ -530,7 +530,6 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateRtt) {
CONVERT_UINT32_ARG_CHECKED(type_index, 0);
CONVERT_ARG_HANDLE_CHECKED(Map, parent, 1);
// Check for an existing RTT first.
// TODO(7748): Support {parent} RTTs for generic heap types ("eqref" etc).
DCHECK(parent->IsWasmStructMap() || parent->IsWasmArrayMap());
Handle<ArrayList> cache(parent->wasm_type_info().subtypes(), isolate);
Map maybe_cached = RttSubtypes::SearchSubtype(cache, type_index);
......@@ -541,7 +540,9 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateRtt) {
isolate);
const wasm::WasmModule* module = instance->module();
Handle<Map> rtt;
if (module->has_struct(type_index)) {
if (wasm::HeapType(type_index).is_generic()) {
rtt = wasm::CreateGenericRtt(isolate, module, parent);
} else if (module->has_struct(type_index)) {
rtt = wasm::CreateStructMap(isolate, module, type_index, parent);
} else if (module->has_array(type_index)) {
rtt = wasm::CreateArrayMap(isolate, module, type_index, parent);
......
......@@ -92,13 +92,13 @@ class CompileImportWrapperTask final : public CancelableTask {
Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
int struct_index, Handle<Map> rtt_parent) {
const wasm::StructType* type = module->struct_type(struct_index);
int inobject_properties = 0;
const int inobject_properties = 0;
DCHECK_LE(type->total_fields_size(), kMaxInt - WasmStruct::kHeaderSize);
int instance_size =
const int instance_size =
WasmStruct::kHeaderSize + static_cast<int>(type->total_fields_size());
InstanceType instance_type = WASM_STRUCT_TYPE;
const InstanceType instance_type = WASM_STRUCT_TYPE;
// TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
reinterpret_cast<Address>(type), rtt_parent);
Handle<Map> map = isolate->factory()->NewMap(
......@@ -110,10 +110,10 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
int array_index, Handle<Map> rtt_parent) {
const wasm::ArrayType* type = module->array_type(array_index);
int inobject_properties = 0;
int instance_size = kVariableSizeSentinel;
InstanceType instance_type = WASM_ARRAY_TYPE;
ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
const int inobject_properties = 0;
const int instance_size = kVariableSizeSentinel;
const InstanceType instance_type = WASM_ARRAY_TYPE;
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
reinterpret_cast<Address>(type), rtt_parent);
Handle<Map> map = isolate->factory()->NewMap(
......@@ -122,6 +122,20 @@ Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
return map;
}
Handle<Map> CreateGenericRtt(Isolate* isolate, const WasmModule* module,
Handle<Map> rtt_parent) {
const int inobject_properties = 0;
const int instance_size = 0;
const InstanceType instance_type = WASM_STRUCT_TYPE; // Fake; good enough.
const ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
Handle<WasmTypeInfo> type_info =
isolate->factory()->NewWasmTypeInfo(0, rtt_parent);
Handle<Map> map = isolate->factory()->NewMap(
instance_type, instance_size, elements_kind, inobject_properties);
map->set_wasm_type_info(*type_info);
return map;
}
// A helper class to simplify instantiating a module from a module object.
// It closes over the {Isolate}, the {ErrorThrower}, etc.
class InstanceBuilder {
......
......@@ -444,6 +444,10 @@ int WasmArray::SizeFor(Map map, int length) {
return kHeaderSize + RoundUp(element_size * length, kTaggedSize);
}
void WasmTypeInfo::clear_foreign_address(Isolate* isolate) {
set_foreign_address(isolate, 0);
}
#include "src/objects/object-macros-undef.h"
} // namespace internal
......
......@@ -896,6 +896,8 @@ class AsmWasmData : public Struct {
class WasmTypeInfo : public TorqueGeneratedWasmTypeInfo<WasmTypeInfo, Foreign> {
public:
inline void clear_foreign_address(Isolate* isolate);
DECL_CAST(WasmTypeInfo)
DECL_PRINTER(WasmTypeInfo)
......@@ -944,6 +946,8 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
int struct_index, Handle<Map> rtt_parent);
Handle<Map> CreateArrayMap(Isolate* isolate, const WasmModule* module,
int array_index, Handle<Map> rtt_parent);
Handle<Map> CreateGenericRtt(Isolate* isolate, const WasmModule* module,
Handle<Map> rtt_parent);
} // namespace wasm
......
......@@ -562,6 +562,8 @@ TEST(BasicRTT) {
ValueType kRttSubtypes[] = {
ValueType::Rtt(static_cast<HeapType>(subtype_index), 2)};
FunctionSig sig_t2_v(1, 0, kRttSubtypes);
ValueType kRttTypesDeeper[] = {ValueType::Rtt(type_index, 2)};
FunctionSig sig_t3_v(1, 0, kRttTypesDeeper);
ValueType kRefTypes[] = {ref(type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
......@@ -570,6 +572,9 @@ TEST(BasicRTT) {
const uint32_t kRttSub = tester.DefineFunction(
&sig_t2_v, {},
{WASM_RTT_CANON(type_index), WASM_RTT_SUB(subtype_index), kExprEnd});
const uint32_t kRttSubGeneric = tester.DefineFunction(
&sig_t3_v, {},
{WASM_RTT_CANON(kLocalEqRef), WASM_RTT_SUB(type_index), kExprEnd});
const uint32_t kStructWithRtt = tester.DefineFunction(
&sig_q_v, {},
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
......@@ -626,6 +631,15 @@ TEST(BasicRTT) {
CHECK_EQ(reinterpret_cast<Address>(
tester.instance()->module()->struct_type(subtype_index)),
submap->wasm_type_info().foreign_address());
Handle<Object> subref_result_canonicalized =
tester.GetResultObject(kRttSub).ToHandleChecked();
CHECK(subref_result.is_identical_to(subref_result_canonicalized));
Handle<Object> sub_generic_1 =
tester.GetResultObject(kRttSubGeneric).ToHandleChecked();
Handle<Object> sub_generic_2 =
tester.GetResultObject(kRttSubGeneric).ToHandleChecked();
CHECK(sub_generic_1.is_identical_to(sub_generic_2));
Handle<Object> s = tester.GetResultObject(kStructWithRtt).ToHandleChecked();
CHECK(s->IsWasmStruct());
......
......@@ -358,6 +358,10 @@ KNOWN_MAPS = {
("read_only_space", 0x03ca1): (78, "StoreHandler3Map"),
("map_space", 0x00121): (1057, "ExternalMap"),
("map_space", 0x00149): (1072, "JSMessageObjectMap"),
("map_space", 0x00171): (181, "WasmRttEqrefMap"),
("map_space", 0x00199): (181, "WasmRttExternrefMap"),
("map_space", 0x001c1): (181, "WasmRttFuncrefMap"),
("map_space", 0x001e9): (181, "WasmRttI31refMap"),
}
# List of known V8 objects.
......@@ -419,49 +423,49 @@ KNOWN_OBJECTS = {
("old_space", 0x003c9): "RegExpResultIndicesAccessor",
("old_space", 0x0040d): "StringLengthAccessor",
("old_space", 0x00451): "InvalidPrototypeValidityCell",
("old_space", 0x00459): "EmptyScript",
("old_space", 0x00499): "ManyClosuresCell",
("old_space", 0x004a5): "ArrayConstructorProtector",
("old_space", 0x004b9): "NoElementsProtector",
("old_space", 0x004cd): "IsConcatSpreadableProtector",
("old_space", 0x004e1): "ArraySpeciesProtector",
("old_space", 0x004f5): "TypedArraySpeciesProtector",
("old_space", 0x00509): "PromiseSpeciesProtector",
("old_space", 0x0051d): "RegExpSpeciesProtector",
("old_space", 0x00531): "StringLengthProtector",
("old_space", 0x00545): "ArrayIteratorProtector",
("old_space", 0x00559): "ArrayBufferDetachingProtector",
("old_space", 0x0056d): "PromiseHookProtector",
("old_space", 0x00581): "PromiseResolveProtector",
("old_space", 0x00595): "MapIteratorProtector",
("old_space", 0x005a9): "PromiseThenProtector",
("old_space", 0x005bd): "SetIteratorProtector",
("old_space", 0x005d1): "StringIteratorProtector",
("old_space", 0x005e5): "SingleCharacterStringCache",
("old_space", 0x009ed): "StringSplitCache",
("old_space", 0x00df5): "RegExpMultipleCache",
("old_space", 0x011fd): "BuiltinsConstantsTable",
("old_space", 0x015a5): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x015cd): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x015f5): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x0161d): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x01645): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x0166d): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x01695): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x016bd): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x016e5): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x0170d): "PromiseAllResolveElementSharedFun",
("old_space", 0x01735): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x0175d): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x01785): "PromiseAnyRejectElementSharedFun",
("old_space", 0x017ad): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x017d5): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x017fd): "PromiseCatchFinallySharedFun",
("old_space", 0x01825): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x0184d): "PromiseThenFinallySharedFun",
("old_space", 0x01875): "PromiseThrowerFinallySharedFun",
("old_space", 0x0189d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x018c5): "ProxyRevokeSharedFun",
("old_space", 0x004d9): "EmptyScript",
("old_space", 0x00519): "ManyClosuresCell",
("old_space", 0x00525): "ArrayConstructorProtector",
("old_space", 0x00539): "NoElementsProtector",
("old_space", 0x0054d): "IsConcatSpreadableProtector",
("old_space", 0x00561): "ArraySpeciesProtector",
("old_space", 0x00575): "TypedArraySpeciesProtector",
("old_space", 0x00589): "PromiseSpeciesProtector",
("old_space", 0x0059d): "RegExpSpeciesProtector",
("old_space", 0x005b1): "StringLengthProtector",
("old_space", 0x005c5): "ArrayIteratorProtector",
("old_space", 0x005d9): "ArrayBufferDetachingProtector",
("old_space", 0x005ed): "PromiseHookProtector",
("old_space", 0x00601): "PromiseResolveProtector",
("old_space", 0x00615): "MapIteratorProtector",
("old_space", 0x00629): "PromiseThenProtector",
("old_space", 0x0063d): "SetIteratorProtector",
("old_space", 0x00651): "StringIteratorProtector",
("old_space", 0x00665): "SingleCharacterStringCache",
("old_space", 0x00a6d): "StringSplitCache",
("old_space", 0x00e75): "RegExpMultipleCache",
("old_space", 0x0127d): "BuiltinsConstantsTable",
("old_space", 0x01625): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0164d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x01675): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x0169d): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x016c5): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x016ed): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x01715): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0173d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x01765): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x0178d): "PromiseAllResolveElementSharedFun",
("old_space", 0x017b5): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x017dd): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x01805): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0182d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x01855): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0187d): "PromiseCatchFinallySharedFun",
("old_space", 0x018a5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x018cd): "PromiseThenFinallySharedFun",
("old_space", 0x018f5): "PromiseThrowerFinallySharedFun",
("old_space", 0x0191d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x01945): "ProxyRevokeSharedFun",
}
# Lower 32 bits of first page addresses for various heap spaces.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment