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(
}
Node* map = gasm_->LoadMap(object);
callbacks.succeed_if(gasm_->TaggedEqual(map, rtt));
if (!config.object_must_be_data_ref) {
callbacks.fail_if_not(gasm_->IsDataRefMap(map));
if (config.reference_kind == kFunction) {
// 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* supertypes = gasm_->LoadSupertypes(type_info);
Node* supertypes_length =
......
......@@ -165,9 +165,13 @@ struct WasmInstanceCacheNodes {
// the wasm decoder from the internal details of TurboFan.
class WasmGraphBuilder {
public:
enum ReferenceKind : bool { // --
kArrayOrStruct = true,
kFunction = false
};
struct ObjectReferenceKnowledge {
bool object_can_be_null;
bool object_must_be_data_ref;
ReferenceKind reference_kind;
int8_t rtt_depth;
};
enum EnforceBoundsCheck : bool { // --
......
......@@ -4421,14 +4421,21 @@ class LiftoffCompiler {
// Perform a regular type check. Check for exact match first.
__ LoadMap(tmp1.gp(), obj_reg.gp());
// {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.
// Subsequent code wouldn't handle e.g. funcrefs.
if (!is_data_ref_type(obj.type, decoder->module_)) {
EmitDataRefCheck(tmp1.gp(), no_match, tmp2, pinned);
if (decoder->module_->has_signature(rtt.type.ref_index())) {
// Function case: currently, the only way for a function to match an rtt
// is if its map is equal to that rtt.
__ 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
// supertypes list.
// Step 1: load the WasmTypeInfo into {tmp1}.
......
......@@ -988,7 +988,11 @@ class WasmGraphBuildingInterface {
StaticKnowledge result;
result.object_can_be_null = object_type.is_nullable();
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;
return result;
}
......
......@@ -184,29 +184,34 @@ class RttSubtypes : public ArrayList {
Handle<Map> AllocateSubRtt(Isolate* isolate,
Handle<WasmInstanceObject> instance, uint32_t type,
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.
DCHECK(parent->IsWasmStructMap() || parent->IsWasmArrayMap());
Handle<ArrayList> cache(parent->wasm_type_info().subtypes(), isolate);
Map maybe_cached = RttSubtypes::SearchSubtype(cache, type);
if (!maybe_cached.is_null()) return handle(maybe_cached, isolate);
// Allocate a fresh RTT otherwise.
const wasm::WasmModule* module = instance->module();
Handle<Map> rtt;
if (module->has_struct(type)) {
rtt = wasm::CreateStructMap(isolate, module, type, parent);
} else if (module->has_array(type)) {
rtt = wasm::CreateArrayMap(isolate, module, type, parent);
} else {
DCHECK(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.
rtt = Map::Copy(isolate, isolate->wasm_exported_function_map(),
"fresh function map for AllocateSubRtt");
DCHECK(module->has_array(type));
rtt = wasm::CreateArrayMap(isolate, module, type, parent);
}
cache = RttSubtypes::Insert(isolate, cache, type, rtt);
parent->wasm_type_info().set_subtypes(*cache);
return rtt;
......
......@@ -479,14 +479,6 @@ inline int declared_function_index(const WasmModule* module, int func_index) {
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
// output a truncation followed by '...' if they exceed a limit.
// Use like this:
......
......@@ -1002,11 +1002,23 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
&sig_func, {}, {WASM_REF_FUNC(sig_index), kExprEnd});
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},
{WASM_LOCAL_SET(0, WASM_REF_FUNC(func_index)),
WASM_REF_TEST(WASM_LOCAL_GET(0), WASM_RTT_CANON(other_sig_index)),
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();
Handle<Object> result_canon =
......@@ -1028,7 +1040,9 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) {
CHECK_EQ(cast_function->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) {
......
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