Commit 44fa3408 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Fixes around rtts, especially functions

Changes:
- Rename ObjectReferenceKnowledgs::object_must_be_data_ref to
  reference_kind, introduce an enum to describe it.
- In both compilers, remove the dynamic check whether the object is an
  array/struct. This is known statically. Instead, if we are checking
  for a function, just check for rtt equality and exit.
- Remove is_data_ref_type(), replace it in the compilers with calls to
  has_signature().
- Restructure AllocateSubRtt() to handle function rtts properly.
- Add a couple execution tests.

Bug: v8:7748
Change-Id: I46fbbfe2f2a7d29b583de0d536d71c534b98322f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2661460Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72477}
parent 102304d1
...@@ -5823,11 +5823,18 @@ void WasmGraphBuilder::TypeCheck( ...@@ -5823,11 +5823,18 @@ void WasmGraphBuilder::TypeCheck(
} }
Node* map = gasm_->LoadMap(object); Node* map = gasm_->LoadMap(object);
callbacks.succeed_if(gasm_->TaggedEqual(map, rtt));
if (!config.object_must_be_data_ref) { if (config.reference_kind == kFunction) {
callbacks.fail_if_not(gasm_->IsDataRefMap(map)); // Currently, the only way for a function to match an rtt is if its map
// is equal to that rtt.
callbacks.fail_if_not(gasm_->TaggedEqual(map, rtt));
return;
} }
DCHECK(config.reference_kind == kArrayOrStruct);
callbacks.succeed_if(gasm_->TaggedEqual(map, rtt));
Node* type_info = gasm_->LoadWasmTypeInfo(map); Node* type_info = gasm_->LoadWasmTypeInfo(map);
Node* supertypes = gasm_->LoadSupertypes(type_info); Node* supertypes = gasm_->LoadSupertypes(type_info);
Node* supertypes_length = Node* supertypes_length =
......
...@@ -165,9 +165,13 @@ struct WasmInstanceCacheNodes { ...@@ -165,9 +165,13 @@ struct WasmInstanceCacheNodes {
// the wasm decoder from the internal details of TurboFan. // the wasm decoder from the internal details of TurboFan.
class WasmGraphBuilder { class WasmGraphBuilder {
public: public:
enum ReferenceKind : bool { // --
kArrayOrStruct = true,
kFunction = false
};
struct ObjectReferenceKnowledge { struct ObjectReferenceKnowledge {
bool object_can_be_null; bool object_can_be_null;
bool object_must_be_data_ref; ReferenceKind reference_kind;
int8_t rtt_depth; int8_t rtt_depth;
}; };
enum EnforceBoundsCheck : bool { // -- enum EnforceBoundsCheck : bool { // --
......
...@@ -4421,14 +4421,21 @@ class LiftoffCompiler { ...@@ -4421,14 +4421,21 @@ class LiftoffCompiler {
// Perform a regular type check. Check for exact match first. // Perform a regular type check. Check for exact match first.
__ LoadMap(tmp1.gp(), obj_reg.gp()); __ LoadMap(tmp1.gp(), obj_reg.gp());
// {tmp1} now holds the object's map. // {tmp1} now holds the object's map.
__ emit_cond_jump(kEqual, &match, rtt.type, tmp1.gp(), rtt_reg.gp());
// If the object isn't guaranteed to be an array or struct, check that. if (decoder->module_->has_signature(rtt.type.ref_index())) {
// Subsequent code wouldn't handle e.g. funcrefs. // Function case: currently, the only way for a function to match an rtt
if (!is_data_ref_type(obj.type, decoder->module_)) { // is if its map is equal to that rtt.
EmitDataRefCheck(tmp1.gp(), no_match, tmp2, pinned); __ emit_cond_jump(kUnequal, no_match, rtt.type, tmp1.gp(), rtt_reg.gp());
__ bind(&match);
return obj_reg;
} }
// Array/struct case until the rest of the function.
// Check for rtt equality, and if not, check if the rtt is a struct/array
// rtt.
__ emit_cond_jump(kEqual, &match, rtt.type, tmp1.gp(), rtt_reg.gp());
// Constant-time subtyping check: load exactly one candidate RTT from the // Constant-time subtyping check: load exactly one candidate RTT from the
// supertypes list. // supertypes list.
// Step 1: load the WasmTypeInfo into {tmp1}. // Step 1: load the WasmTypeInfo into {tmp1}.
......
...@@ -988,7 +988,11 @@ class WasmGraphBuildingInterface { ...@@ -988,7 +988,11 @@ class WasmGraphBuildingInterface {
StaticKnowledge result; StaticKnowledge result;
result.object_can_be_null = object_type.is_nullable(); result.object_can_be_null = object_type.is_nullable();
DCHECK(object_type.is_object_reference_type()); // Checked by validation. DCHECK(object_type.is_object_reference_type()); // Checked by validation.
result.object_must_be_data_ref = is_data_ref_type(object_type, module); // In the bottom case, the result is irrelevant.
result.reference_kind =
rtt_type != kWasmBottom && module->has_signature(rtt_type.ref_index())
? compiler::WasmGraphBuilder::kFunction
: compiler::WasmGraphBuilder::kArrayOrStruct;
result.rtt_depth = rtt_type.has_depth() ? rtt_type.depth() : -1; result.rtt_depth = rtt_type.has_depth() ? rtt_type.depth() : -1;
return result; return result;
} }
......
...@@ -184,29 +184,34 @@ class RttSubtypes : public ArrayList { ...@@ -184,29 +184,34 @@ class RttSubtypes : public ArrayList {
Handle<Map> AllocateSubRtt(Isolate* isolate, Handle<Map> AllocateSubRtt(Isolate* isolate,
Handle<WasmInstanceObject> instance, uint32_t type, Handle<WasmInstanceObject> instance, uint32_t type,
Handle<Map> parent) { Handle<Map> parent) {
DCHECK(parent->IsWasmStructMap() || parent->IsWasmArrayMap() ||
parent->IsJSFunctionMap());
const wasm::WasmModule* module = instance->module();
if (module->has_signature(type)) {
// Currently, parent rtts for functions are meaningless,
// since (rtt.test func rtt) iff (func.map == rtt).
// Therefore, we simply create a fresh function map here.
// TODO(7748): Canonicalize rtts to make them work for identical function
// types.
return Map::Copy(isolate, isolate->wasm_exported_function_map(),
"fresh function map for AllocateSubRtt");
}
// Check for an existing RTT first. // Check for an existing RTT first.
DCHECK(parent->IsWasmStructMap() || parent->IsWasmArrayMap());
Handle<ArrayList> cache(parent->wasm_type_info().subtypes(), isolate); Handle<ArrayList> cache(parent->wasm_type_info().subtypes(), isolate);
Map maybe_cached = RttSubtypes::SearchSubtype(cache, type); Map maybe_cached = RttSubtypes::SearchSubtype(cache, type);
if (!maybe_cached.is_null()) return handle(maybe_cached, isolate); if (!maybe_cached.is_null()) return handle(maybe_cached, isolate);
// Allocate a fresh RTT otherwise. // Allocate a fresh RTT otherwise.
const wasm::WasmModule* module = instance->module();
Handle<Map> rtt; Handle<Map> rtt;
if (module->has_struct(type)) { if (module->has_struct(type)) {
rtt = wasm::CreateStructMap(isolate, module, type, parent); rtt = wasm::CreateStructMap(isolate, module, type, parent);
} else if (module->has_array(type)) {
rtt = wasm::CreateArrayMap(isolate, module, type, parent);
} else { } else {
DCHECK(module->has_signature(type)); DCHECK(module->has_array(type));
// Currently, parent rtts for functions are meaningless, rtt = wasm::CreateArrayMap(isolate, module, type, parent);
// since (rtt.test func rtt) iff (func.map == rtt).
// Therefore, we simply create a fresh function map here.
// TODO(7748): Canonicalize rtts to make them work for identical function
// types.
rtt = Map::Copy(isolate, isolate->wasm_exported_function_map(),
"fresh function map for AllocateSubRtt");
} }
cache = RttSubtypes::Insert(isolate, cache, type, rtt); cache = RttSubtypes::Insert(isolate, cache, type, rtt);
parent->wasm_type_info().set_subtypes(*cache); parent->wasm_type_info().set_subtypes(*cache);
return rtt; return rtt;
......
...@@ -479,14 +479,6 @@ inline int declared_function_index(const WasmModule* module, int func_index) { ...@@ -479,14 +479,6 @@ inline int declared_function_index(const WasmModule* module, int func_index) {
return declared_idx; return declared_idx;
} }
inline bool is_data_ref_type(ValueType type, const WasmModule* module) {
// TODO(7748): When we implement dataref (=any struct or array), support
// that here.
if (!type.has_index()) return false;
uint32_t index = type.ref_index();
return module->has_struct(index) || module->has_array(index);
}
// TruncatedUserString makes it easy to output names up to a certain length, and // TruncatedUserString makes it easy to output names up to a certain length, and
// output a truncation followed by '...' if they exceed a limit. // output a truncation followed by '...' if they exceed a limit.
// Use like this: // Use like this:
......
...@@ -1002,11 +1002,23 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) { ...@@ -1002,11 +1002,23 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
&sig_func, {}, {WASM_REF_FUNC(sig_index), kExprEnd}); &sig_func, {}, {WASM_REF_FUNC(sig_index), kExprEnd});
const byte test = tester.DefineFunction( const byte test = tester.DefineFunction(
tester.sigs.i_v(), {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(WASM_LOCAL_GET(0), WASM_RTT_CANON(sig_index)), kExprEnd});
const byte test_fail_1 = tester.DefineFunction(
tester.sigs.i_v(), {kWasmFuncRef}, tester.sigs.i_v(), {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)), {WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(WASM_LOCAL_GET(0), WASM_RTT_CANON(other_sig_index)), WASM_REF_TEST(WASM_LOCAL_GET(0), WASM_RTT_CANON(other_sig_index)),
kExprEnd}); kExprEnd});
const byte test_fail_2 = tester.DefineFunction(
tester.sigs.i_v(), {kWasmFuncRef},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(WASM_LOCAL_GET(0),
WASM_RTT_SUB(sig_index, WASM_RTT_CANON(sig_index))),
kExprEnd});
tester.CompileModule(); tester.CompileModule();
Handle<Object> result_canon = Handle<Object> result_canon =
...@@ -1028,7 +1040,9 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) { ...@@ -1028,7 +1040,9 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
CHECK_EQ(cast_function->code().raw_instruction_start(), CHECK_EQ(cast_function->code().raw_instruction_start(),
cast_function_reference->code().raw_instruction_start()); cast_function_reference->code().raw_instruction_start());
tester.CheckResult(test, 0); tester.CheckResult(test, 1);
tester.CheckResult(test_fail_1, 0);
tester.CheckResult(test_fail_2, 0);
} }
WASM_COMPILED_EXEC_TEST(CallRef) { WASM_COMPILED_EXEC_TEST(CallRef) {
......
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