[wasm-gc] Implement ref.is_array, ref.as_array
Bug: v8:7748 Change-Id: Ieedb5bb0d6555cdf6c628f6700f7116ca142a2d2 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3376963 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#78577}
This commit is contained in:
parent
e557383c83
commit
c7f2108019
@ -5762,15 +5762,16 @@ void WasmGraphBuilder::DataCheck(Node* object, bool object_can_be_null,
|
||||
callbacks.fail_if_not(gasm_->IsDataRefMap(map), BranchHint::kTrue);
|
||||
}
|
||||
|
||||
void WasmGraphBuilder::FuncCheck(Node* object, bool object_can_be_null,
|
||||
Callbacks callbacks) {
|
||||
void WasmGraphBuilder::ManagedObjectInstanceCheck(Node* object,
|
||||
bool object_can_be_null,
|
||||
InstanceType instance_type,
|
||||
Callbacks callbacks) {
|
||||
if (object_can_be_null) {
|
||||
callbacks.fail_if(IsNull(object), BranchHint::kFalse);
|
||||
}
|
||||
callbacks.fail_if(gasm_->IsI31(object), BranchHint::kFalse);
|
||||
callbacks.fail_if_not(
|
||||
gasm_->HasInstanceType(object, WASM_INTERNAL_FUNCTION_TYPE),
|
||||
BranchHint::kTrue);
|
||||
callbacks.fail_if_not(gasm_->HasInstanceType(object, instance_type),
|
||||
BranchHint::kTrue);
|
||||
}
|
||||
|
||||
void WasmGraphBuilder::BrOnCastAbs(
|
||||
@ -5863,7 +5864,8 @@ void WasmGraphBuilder::BrOnData(Node* object, Node* /*rtt*/,
|
||||
|
||||
Node* WasmGraphBuilder::RefIsFunc(Node* object, bool object_can_be_null) {
|
||||
auto done = gasm_->MakeLabel(MachineRepresentation::kWord32);
|
||||
FuncCheck(object, object_can_be_null, TestCallbacks(&done));
|
||||
ManagedObjectInstanceCheck(object, object_can_be_null,
|
||||
WASM_INTERNAL_FUNCTION_TYPE, TestCallbacks(&done));
|
||||
gasm_->Goto(&done, Int32Constant(1));
|
||||
gasm_->Bind(&done);
|
||||
return done.PhiAt(0);
|
||||
@ -5872,7 +5874,9 @@ Node* WasmGraphBuilder::RefIsFunc(Node* object, bool object_can_be_null) {
|
||||
Node* WasmGraphBuilder::RefAsFunc(Node* object, bool object_can_be_null,
|
||||
wasm::WasmCodePosition position) {
|
||||
auto done = gasm_->MakeLabel();
|
||||
FuncCheck(object, object_can_be_null, CastCallbacks(&done, position));
|
||||
ManagedObjectInstanceCheck(object, object_can_be_null,
|
||||
WASM_INTERNAL_FUNCTION_TYPE,
|
||||
CastCallbacks(&done, position));
|
||||
gasm_->Goto(&done);
|
||||
gasm_->Bind(&done);
|
||||
return object;
|
||||
@ -5885,10 +5889,31 @@ void WasmGraphBuilder::BrOnFunc(Node* object, Node* /*rtt*/,
|
||||
Node** no_match_effect) {
|
||||
BrOnCastAbs(match_control, match_effect, no_match_control, no_match_effect,
|
||||
[=](Callbacks callbacks) -> void {
|
||||
return FuncCheck(object, config.object_can_be_null, callbacks);
|
||||
return ManagedObjectInstanceCheck(
|
||||
object, config.object_can_be_null,
|
||||
WASM_INTERNAL_FUNCTION_TYPE, callbacks);
|
||||
});
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RefIsArray(Node* object, bool object_can_be_null) {
|
||||
auto done = gasm_->MakeLabel(MachineRepresentation::kWord32);
|
||||
ManagedObjectInstanceCheck(object, object_can_be_null, WASM_ARRAY_TYPE,
|
||||
TestCallbacks(&done));
|
||||
gasm_->Goto(&done, Int32Constant(1));
|
||||
gasm_->Bind(&done);
|
||||
return done.PhiAt(0);
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RefAsArray(Node* object, bool object_can_be_null,
|
||||
wasm::WasmCodePosition position) {
|
||||
auto done = gasm_->MakeLabel();
|
||||
ManagedObjectInstanceCheck(object, object_can_be_null, WASM_ARRAY_TYPE,
|
||||
CastCallbacks(&done, position));
|
||||
gasm_->Goto(&done);
|
||||
gasm_->Bind(&done);
|
||||
return object;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RefIsI31(Node* object) { return gasm_->IsI31(object); }
|
||||
|
||||
Node* WasmGraphBuilder::RefAsI31(Node* object,
|
||||
|
@ -522,6 +522,9 @@ class WasmGraphBuilder {
|
||||
void BrOnFunc(Node* object, Node* rtt, ObjectReferenceKnowledge config,
|
||||
Node** match_control, Node** match_effect,
|
||||
Node** no_match_control, Node** no_match_effect);
|
||||
Node* RefIsArray(Node* object, bool object_can_be_null);
|
||||
Node* RefAsArray(Node* object, bool object_can_be_null,
|
||||
wasm::WasmCodePosition position);
|
||||
Node* RefIsI31(Node* object);
|
||||
Node* RefAsI31(Node* object, wasm::WasmCodePosition position);
|
||||
void BrOnI31(Node* object, Node* rtt, ObjectReferenceKnowledge config,
|
||||
@ -719,7 +722,9 @@ class WasmGraphBuilder {
|
||||
void TypeCheck(Node* object, Node* rtt, ObjectReferenceKnowledge config,
|
||||
bool null_succeeds, Callbacks callbacks);
|
||||
void DataCheck(Node* object, bool object_can_be_null, Callbacks callbacks);
|
||||
void FuncCheck(Node* object, bool object_can_be_null, Callbacks callbacks);
|
||||
void ManagedObjectInstanceCheck(Node* object, bool object_can_be_null,
|
||||
InstanceType instance_type,
|
||||
Callbacks callbacks);
|
||||
|
||||
void BrOnCastAbs(Node** match_control, Node** match_effect,
|
||||
Node** no_match_control, Node** no_match_effect,
|
||||
|
@ -5599,58 +5599,35 @@ class LiftoffCompiler {
|
||||
// through to match.
|
||||
LiftoffRegister DataCheck(const Value& obj, Label* no_match,
|
||||
LiftoffRegList pinned, Register opt_scratch) {
|
||||
LiftoffRegister obj_reg = pinned.set(__ PopToRegister(pinned));
|
||||
TypeCheckRegisters registers =
|
||||
TypeCheckPrelude(obj, no_match, pinned, opt_scratch);
|
||||
EmitDataRefCheck(registers.map_reg.gp(), no_match, registers.tmp_reg,
|
||||
pinned);
|
||||
return registers.obj_reg;
|
||||
}
|
||||
|
||||
// Reserve all temporary registers up front, so that the cache state
|
||||
// tracking doesn't get confused by the following conditional jumps.
|
||||
LiftoffRegister tmp1 =
|
||||
opt_scratch != no_reg
|
||||
? LiftoffRegister(opt_scratch)
|
||||
: pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LiftoffRegister tmp2 = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
|
||||
if (obj.type.is_nullable()) {
|
||||
LoadNullValue(tmp1.gp(), pinned);
|
||||
__ emit_cond_jump(kEqual, no_match, kOptRef, obj_reg.gp(), tmp1.gp());
|
||||
}
|
||||
|
||||
__ emit_smi_check(obj_reg.gp(), no_match, LiftoffAssembler::kJumpOnSmi);
|
||||
|
||||
// Load the object's map and check if it is a struct/array map.
|
||||
__ LoadMap(tmp1.gp(), obj_reg.gp());
|
||||
EmitDataRefCheck(tmp1.gp(), no_match, tmp2, pinned);
|
||||
|
||||
return obj_reg;
|
||||
LiftoffRegister ArrayCheck(const Value& obj, Label* no_match,
|
||||
LiftoffRegList pinned, Register opt_scratch) {
|
||||
TypeCheckRegisters registers =
|
||||
TypeCheckPrelude(obj, no_match, pinned, opt_scratch);
|
||||
__ Load(registers.map_reg, registers.map_reg.gp(), no_reg,
|
||||
wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset),
|
||||
LoadType::kI32Load16U, pinned);
|
||||
__ emit_i32_cond_jumpi(kUnequal, no_match, registers.map_reg.gp(),
|
||||
WASM_ARRAY_TYPE);
|
||||
return registers.obj_reg;
|
||||
}
|
||||
|
||||
LiftoffRegister FuncCheck(const Value& obj, Label* no_match,
|
||||
LiftoffRegList pinned, Register opt_scratch) {
|
||||
LiftoffRegister obj_reg = pinned.set(__ PopToRegister(pinned));
|
||||
|
||||
// Reserve all temporary registers up front, so that the cache state
|
||||
// tracking doesn't get confused by the following conditional jumps.
|
||||
LiftoffRegister tmp1 =
|
||||
opt_scratch != no_reg
|
||||
? LiftoffRegister(opt_scratch)
|
||||
: pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
|
||||
if (obj.type.is_nullable()) {
|
||||
LoadNullValue(tmp1.gp(), pinned);
|
||||
__ emit_cond_jump(kEqual, no_match, kOptRef, obj_reg.gp(), tmp1.gp());
|
||||
}
|
||||
|
||||
__ emit_smi_check(obj_reg.gp(), no_match, LiftoffAssembler::kJumpOnSmi);
|
||||
|
||||
// Load the object's map and check if its InstaceType field is that of a
|
||||
// function.
|
||||
__ LoadMap(tmp1.gp(), obj_reg.gp());
|
||||
__ Load(tmp1, tmp1.gp(), no_reg,
|
||||
TypeCheckRegisters registers =
|
||||
TypeCheckPrelude(obj, no_match, pinned, opt_scratch);
|
||||
__ Load(registers.map_reg, registers.map_reg.gp(), no_reg,
|
||||
wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset),
|
||||
LoadType::kI32Load16U, pinned);
|
||||
__ emit_i32_cond_jumpi(kUnequal, no_match, tmp1.gp(),
|
||||
__ emit_i32_cond_jumpi(kUnequal, no_match, registers.map_reg.gp(),
|
||||
WASM_INTERNAL_FUNCTION_TYPE);
|
||||
|
||||
return obj_reg;
|
||||
return registers.obj_reg;
|
||||
}
|
||||
|
||||
LiftoffRegister I31Check(const Value& object, Label* no_match,
|
||||
@ -5695,6 +5672,11 @@ class LiftoffCompiler {
|
||||
return AbstractTypeCheck<&LiftoffCompiler::FuncCheck>(object);
|
||||
}
|
||||
|
||||
void RefIsArray(FullDecoder* /* decoder */, const Value& object,
|
||||
Value* /* result_val */) {
|
||||
return AbstractTypeCheck<&LiftoffCompiler::ArrayCheck>(object);
|
||||
}
|
||||
|
||||
void RefIsI31(FullDecoder* decoder, const Value& object,
|
||||
Value* /* result */) {
|
||||
return AbstractTypeCheck<&LiftoffCompiler::I31Check>(object);
|
||||
@ -5726,6 +5708,11 @@ class LiftoffCompiler {
|
||||
return AbstractTypeCast<&LiftoffCompiler::I31Check>(object, decoder, kRef);
|
||||
}
|
||||
|
||||
void RefAsArray(FullDecoder* decoder, const Value& object, Value* result) {
|
||||
return AbstractTypeCast<&LiftoffCompiler::ArrayCheck>(object, decoder,
|
||||
kRef);
|
||||
}
|
||||
|
||||
template <TypeChecker type_checker>
|
||||
void BrOnAbstractType(const Value& object, FullDecoder* decoder,
|
||||
uint32_t br_depth) {
|
||||
@ -6242,6 +6229,35 @@ class LiftoffCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeCheckRegisters {
|
||||
LiftoffRegister obj_reg, map_reg, tmp_reg;
|
||||
};
|
||||
|
||||
TypeCheckRegisters TypeCheckPrelude(const Value& obj, Label* no_match,
|
||||
LiftoffRegList pinned,
|
||||
Register opt_scratch) {
|
||||
LiftoffRegister obj_reg = pinned.set(__ PopToRegister(pinned));
|
||||
|
||||
// Reserve all temporary registers up front, so that the cache state
|
||||
// tracking doesn't get confused by the following conditional jumps.
|
||||
LiftoffRegister map_reg =
|
||||
opt_scratch != no_reg
|
||||
? LiftoffRegister(opt_scratch)
|
||||
: pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
LiftoffRegister tmp_reg = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
|
||||
|
||||
if (obj.type.is_nullable()) {
|
||||
LoadNullValue(map_reg.gp(), pinned);
|
||||
__ emit_cond_jump(kEqual, no_match, kOptRef, obj_reg.gp(), map_reg.gp());
|
||||
}
|
||||
|
||||
__ emit_smi_check(obj_reg.gp(), no_match, LiftoffAssembler::kJumpOnSmi);
|
||||
|
||||
__ LoadMap(map_reg.gp(), obj_reg.gp());
|
||||
|
||||
return {obj_reg, map_reg, tmp_reg};
|
||||
}
|
||||
|
||||
void EmitDataRefCheck(Register map, Label* not_data_ref, LiftoffRegister tmp,
|
||||
LiftoffRegList pinned) {
|
||||
constexpr int kInstanceTypeOffset =
|
||||
|
@ -1072,9 +1072,11 @@ struct ControlBase : public PcForErrors<validate> {
|
||||
F(RefIsFunc, const Value& object, Value* result) \
|
||||
F(RefIsData, const Value& object, Value* result) \
|
||||
F(RefIsI31, const Value& object, Value* result) \
|
||||
F(RefIsArray, const Value& object, Value* result) \
|
||||
F(RefAsFunc, const Value& object, Value* result) \
|
||||
F(RefAsData, const Value& object, Value* result) \
|
||||
F(RefAsI31, const Value& object, Value* result) \
|
||||
F(RefAsArray, const Value& object, Value* result) \
|
||||
F(BrOnFunc, const Value& object, Value* value_on_branch, uint32_t br_depth) \
|
||||
F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \
|
||||
F(BrOnI31, const Value& object, Value* value_on_branch, uint32_t br_depth) \
|
||||
@ -4772,6 +4774,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
|
||||
ABSTRACT_TYPE_CHECK(Data)
|
||||
ABSTRACT_TYPE_CHECK(Func)
|
||||
ABSTRACT_TYPE_CHECK(I31)
|
||||
ABSTRACT_TYPE_CHECK(Array)
|
||||
#undef ABSTRACT_TYPE_CHECK
|
||||
|
||||
#define ABSTRACT_TYPE_CAST(heap_type) \
|
||||
@ -4789,6 +4792,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
|
||||
ABSTRACT_TYPE_CAST(Data)
|
||||
ABSTRACT_TYPE_CAST(Func)
|
||||
ABSTRACT_TYPE_CAST(I31)
|
||||
ABSTRACT_TYPE_CAST(Array)
|
||||
#undef ABSTRACT_TYPE_CAST
|
||||
|
||||
case kExprBrOnData:
|
||||
|
@ -1248,6 +1248,15 @@ class WasmGraphBuildingInterface {
|
||||
br_depth, false);
|
||||
}
|
||||
|
||||
void RefIsArray(FullDecoder* decoder, const Value& object, Value* result) {
|
||||
result->node = builder_->RefIsArray(object.node, object.type.is_nullable());
|
||||
}
|
||||
|
||||
void RefAsArray(FullDecoder* decoder, const Value& object, Value* result) {
|
||||
result->node = builder_->RefAsArray(object.node, object.type.is_nullable(),
|
||||
decoder->position());
|
||||
}
|
||||
|
||||
void RefIsI31(FullDecoder* decoder, const Value& object, Value* result) {
|
||||
result->node = builder_->RefIsI31(object.node);
|
||||
}
|
||||
|
@ -431,9 +431,11 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
|
||||
CASE_OP(RefIsFunc, "ref.is_func")
|
||||
CASE_OP(RefIsData, "ref.is_data")
|
||||
CASE_OP(RefIsI31, "ref.is_i31")
|
||||
CASE_OP(RefIsArray, "ref.is_array")
|
||||
CASE_OP(RefAsFunc, "ref.as_func")
|
||||
CASE_OP(RefAsData, "ref.as_data")
|
||||
CASE_OP(RefAsI31, "ref.as_i31")
|
||||
CASE_OP(RefAsArray, "ref.as_array")
|
||||
CASE_OP(BrOnFunc, "br_on_func")
|
||||
CASE_OP(BrOnData, "br_on_data")
|
||||
CASE_OP(BrOnI31, "br_on_i31")
|
||||
|
@ -699,9 +699,11 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
|
||||
V(RefIsFunc, 0xfb50, _) \
|
||||
V(RefIsData, 0xfb51, _) \
|
||||
V(RefIsI31, 0xfb52, _) \
|
||||
V(RefIsArray, 0xfb53, _) /* not standardized - V8 experimental */ \
|
||||
V(RefAsFunc, 0xfb58, _) \
|
||||
V(RefAsData, 0xfb59, _) \
|
||||
V(RefAsI31, 0xfb5a, _) \
|
||||
V(RefAsArray, 0xfb5b, _) /* not standardized - V8 experimental */ \
|
||||
V(BrOnFunc, 0xfb60, _) \
|
||||
V(BrOnData, 0xfb61, _) \
|
||||
V(BrOnI31, 0xfb62, _) \
|
||||
|
@ -1894,9 +1894,10 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
WasmGCTester tester(execution_tier);
|
||||
|
||||
byte array_index = tester.DefineArray(kWasmI32, true);
|
||||
byte struct_index = tester.DefineStruct({F(kWasmI32, true)});
|
||||
byte function_index =
|
||||
tester.DefineFunction(tester.sigs.v_v(), {}, {kExprEnd});
|
||||
byte sig_index = 1;
|
||||
byte sig_index = 2;
|
||||
|
||||
// This is just so func_index counts as "declared".
|
||||
tester.AddGlobal(ValueType::Ref(sig_index, kNullable), false,
|
||||
@ -1905,6 +1906,9 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
byte kDataCheckNull = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {},
|
||||
{WASM_REF_IS_DATA(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
|
||||
byte kArrayCheckNull = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {},
|
||||
{WASM_REF_IS_ARRAY(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
|
||||
byte kFuncCheckNull = tester.DefineFunction(
|
||||
tester.sigs.i_v(), {},
|
||||
{WASM_REF_IS_FUNC(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
|
||||
@ -1916,6 +1920,10 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
tester.DefineFunction(tester.sigs.i_v(), {},
|
||||
{WASM_REF_AS_DATA(WASM_REF_NULL(kAnyRefCode)),
|
||||
WASM_DROP, WASM_I32V(1), kExprEnd});
|
||||
byte kArrayCastNull =
|
||||
tester.DefineFunction(tester.sigs.i_v(), {},
|
||||
{WASM_REF_AS_ARRAY(WASM_REF_NULL(kAnyRefCode)),
|
||||
WASM_DROP, WASM_I32V(1), kExprEnd});
|
||||
byte kFuncCastNull =
|
||||
tester.DefineFunction(tester.sigs.i_v(), {},
|
||||
{WASM_REF_AS_FUNC(WASM_REF_NULL(kAnyRefCode)),
|
||||
@ -1934,6 +1942,12 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
DATA, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
WASM_RTT_CANON(array_index)));
|
||||
byte kDataCheckFailure = TYPE_CHECK(DATA, WASM_I31_NEW(WASM_I32V(42)));
|
||||
byte kArrayCheckSuccess = TYPE_CHECK(
|
||||
ARRAY, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
WASM_RTT_CANON(array_index)));
|
||||
byte kArrayCheckFailure =
|
||||
TYPE_CHECK(ARRAY, WASM_STRUCT_NEW_DEFAULT_WITH_RTT(
|
||||
struct_index, WASM_RTT_CANON(struct_index)));
|
||||
byte kFuncCheckSuccess = TYPE_CHECK(FUNC, WASM_REF_FUNC(function_index));
|
||||
byte kFuncCheckFailure = TYPE_CHECK(
|
||||
FUNC, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
@ -1954,6 +1968,10 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
DATA, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
WASM_RTT_CANON(array_index)));
|
||||
byte kDataCastFailure = TYPE_CAST(DATA, WASM_I31_NEW(WASM_I32V(42)));
|
||||
byte kArrayCastSuccess = TYPE_CAST(
|
||||
DATA, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
WASM_RTT_CANON(array_index)));
|
||||
byte kArrayCastFailure = TYPE_CAST(DATA, WASM_I31_NEW(WASM_I32V(42)));
|
||||
byte kFuncCastSuccess = TYPE_CAST(FUNC, WASM_REF_FUNC(function_index));
|
||||
byte kFuncCastFailure = TYPE_CAST(
|
||||
FUNC, WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
|
||||
@ -2018,26 +2036,32 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
|
||||
tester.CompileModule();
|
||||
|
||||
tester.CheckResult(kDataCheckNull, 0);
|
||||
tester.CheckResult(kArrayCheckNull, 0);
|
||||
tester.CheckResult(kFuncCheckNull, 0);
|
||||
tester.CheckResult(kI31CheckNull, 0);
|
||||
|
||||
tester.CheckHasThrown(kDataCastNull);
|
||||
tester.CheckHasThrown(kArrayCastNull);
|
||||
tester.CheckHasThrown(kFuncCastNull);
|
||||
tester.CheckHasThrown(kI31CastNull);
|
||||
|
||||
tester.CheckResult(kDataCheckSuccess, 1);
|
||||
tester.CheckResult(kArrayCheckSuccess, 1);
|
||||
tester.CheckResult(kFuncCheckSuccess, 1);
|
||||
tester.CheckResult(kI31CheckSuccess, 1);
|
||||
|
||||
tester.CheckResult(kDataCheckFailure, 0);
|
||||
tester.CheckResult(kArrayCheckFailure, 0);
|
||||
tester.CheckResult(kFuncCheckFailure, 0);
|
||||
tester.CheckResult(kI31CheckFailure, 0);
|
||||
|
||||
tester.CheckResult(kDataCastSuccess, 1);
|
||||
tester.CheckResult(kArrayCastSuccess, 1);
|
||||
tester.CheckResult(kFuncCastSuccess, 1);
|
||||
tester.CheckResult(kI31CastSuccess, 1);
|
||||
|
||||
tester.CheckHasThrown(kDataCastFailure);
|
||||
tester.CheckHasThrown(kArrayCastFailure);
|
||||
tester.CheckHasThrown(kFuncCastFailure);
|
||||
tester.CheckHasThrown(kI31CastFailure);
|
||||
|
||||
|
@ -531,9 +531,11 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
|
||||
|
||||
#define WASM_REF_IS_FUNC(ref) ref, WASM_GC_OP(kExprRefIsFunc)
|
||||
#define WASM_REF_IS_DATA(ref) ref, WASM_GC_OP(kExprRefIsData)
|
||||
#define WASM_REF_IS_ARRAY(ref) ref, WASM_GC_OP(kExprRefIsArray)
|
||||
#define WASM_REF_IS_I31(ref) ref, WASM_GC_OP(kExprRefIsI31)
|
||||
#define WASM_REF_AS_FUNC(ref) ref, WASM_GC_OP(kExprRefAsFunc)
|
||||
#define WASM_REF_AS_DATA(ref) ref, WASM_GC_OP(kExprRefAsData)
|
||||
#define WASM_REF_AS_ARRAY(ref) ref, WASM_GC_OP(kExprRefAsArray)
|
||||
#define WASM_REF_AS_I31(ref) ref, WASM_GC_OP(kExprRefAsI31)
|
||||
#define WASM_BR_ON_FUNC(depth) \
|
||||
WASM_GC_OP(kExprBrOnFunc), static_cast<byte>(depth)
|
||||
|
@ -507,9 +507,11 @@ let kExprBrOnCastStaticFail = 0x47;
|
||||
let kExprRefIsFunc = 0x50;
|
||||
let kExprRefIsData = 0x51;
|
||||
let kExprRefIsI31 = 0x52;
|
||||
let kExprRefIsArray = 0x53;
|
||||
let kExprRefAsFunc = 0x58;
|
||||
let kExprRefAsData = 0x59;
|
||||
let kExprRefAsI31 = 0x5a;
|
||||
let kExprRefAsArray = 0x5b;
|
||||
let kExprBrOnFunc = 0x60;
|
||||
let kExprBrOnData = 0x61;
|
||||
let kExprBrOnI31 = 0x62;
|
||||
|
Loading…
Reference in New Issue
Block a user