[wasm-gc] Implement br_on_array, br_on_non_array

Bug: v8:7748
Change-Id: I5280a22240ef5e920f701e991ed13d8b8881fc6b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3377122
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78584}
This commit is contained in:
Manos Koukoutos 2022-01-12 10:03:54 +00:00 committed by V8 LUCI CQ
parent 93f28d16c7
commit 38117eba49
10 changed files with 229 additions and 143 deletions

View File

@ -5914,6 +5914,19 @@ Node* WasmGraphBuilder::RefAsArray(Node* object, bool object_can_be_null,
return object;
}
void WasmGraphBuilder::BrOnArray(Node* object, Node* /*rtt*/,
ObjectReferenceKnowledge config,
Node** match_control, Node** match_effect,
Node** no_match_control,
Node** no_match_effect) {
BrOnCastAbs(match_control, match_effect, no_match_control, no_match_effect,
[=](Callbacks callbacks) -> void {
return ManagedObjectInstanceCheck(object,
config.object_can_be_null,
WASM_ARRAY_TYPE, callbacks);
});
}
Node* WasmGraphBuilder::RefIsI31(Node* object) { return gasm_->IsI31(object); }
Node* WasmGraphBuilder::RefAsI31(Node* object,

View File

@ -525,6 +525,9 @@ class WasmGraphBuilder {
Node* RefIsArray(Node* object, bool object_can_be_null);
Node* RefAsArray(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position);
void BrOnArray(Node* object, Node* rtt, ObjectReferenceKnowledge config,
Node** match_control, Node** match_effect,
Node** no_match_control, Node** no_match_effect);
Node* RefIsI31(Node* object);
Node* RefAsI31(Node* object, wasm::WasmCodePosition position);
void BrOnI31(Node* object, Node* rtt, ObjectReferenceKnowledge config,

View File

@ -5773,6 +5773,12 @@ class LiftoffCompiler {
br_depth);
}
void BrOnArray(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
return BrOnAbstractType<&LiftoffCompiler::ArrayCheck>(object, decoder,
br_depth);
}
void BrOnNonData(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
return BrOnNonAbstractType<&LiftoffCompiler::DataCheck>(object, decoder,
@ -5791,6 +5797,12 @@ class LiftoffCompiler {
br_depth);
}
void BrOnNonArray(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
return BrOnNonAbstractType<&LiftoffCompiler::ArrayCheck>(object, decoder,
br_depth);
}
void Forward(FullDecoder* decoder, const Value& from, Value* to) {
// Nothing to do here.
}

View File

@ -945,146 +945,149 @@ struct ControlBase : public PcForErrors<validate> {
WasmRttSubMode mode) \
F(DoReturn, uint32_t drop_values)
#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) \
/* Control: */ \
F(Block, Control* block) \
F(Loop, Control* block) \
F(Try, Control* block) \
F(If, const Value& cond, Control* if_block) \
F(FallThruTo, Control* c) \
F(PopControl, Control* block) \
/* Instructions: */ \
F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
Value* result) \
F(RefAsNonNull, const Value& arg, Value* result) \
F(Drop) \
F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \
F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \
F(LocalTee, const Value& value, Value* result, \
const IndexImmediate<validate>& imm) \
F(AllocateLocals, base::Vector<Value> local_values) \
F(DeallocateLocals, uint32_t count) \
F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \
F(TableGet, const Value& index, Value* result, \
const IndexImmediate<validate>& imm) \
F(TableSet, const Value& index, const Value& value, \
const IndexImmediate<validate>& imm) \
F(Trap, TrapReason reason) \
F(NopForTestingUnsupportedInLiftoff) \
F(Select, const Value& cond, const Value& fval, const Value& tval, \
Value* result) \
F(BrOrRet, uint32_t depth, uint32_t drop_values) \
F(BrIf, const Value& cond, uint32_t depth) \
F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
F(Else, Control* if_block) \
F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, Value* result) \
F(LoadTransform, LoadType type, LoadTransformationKind transform, \
const MemoryAccessImmediate<validate>& imm, const Value& index, \
Value* result) \
F(LoadLane, LoadType type, const Value& value, const Value& index, \
const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \
Value* result) \
F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, const Value& value) \
F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, const Value& value, const uint8_t laneidx) \
F(CurrentMemoryPages, Value* result) \
F(MemoryGrow, const Value& value, Value* result) \
F(CallDirect, const CallFunctionImmediate<validate>& imm, \
const Value args[], Value returns[]) \
F(CallIndirect, const Value& index, \
const CallIndirectImmediate<validate>& imm, const Value args[], \
Value returns[]) \
F(CallRef, const Value& func_ref, const FunctionSig* sig, \
uint32_t sig_index, const Value args[], const Value returns[]) \
F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \
uint32_t sig_index, const Value args[]) \
F(ReturnCall, const CallFunctionImmediate<validate>& imm, \
const Value args[]) \
F(ReturnCallIndirect, const Value& index, \
const CallIndirectImmediate<validate>& imm, const Value args[]) \
F(BrOnNull, const Value& ref_object, uint32_t depth, \
bool pass_null_along_branch, Value* result_on_fallthrough) \
F(BrOnNonNull, const Value& ref_object, uint32_t depth) \
F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \
F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
const base::Vector<Value> inputs, Value* result) \
F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \
F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \
const Value& input0, const Value& input1, Value* result) \
F(Throw, const TagIndexImmediate<validate>& imm, \
const base::Vector<Value>& args) \
F(Rethrow, Control* block) \
F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \
base::Vector<Value> caught_values) \
F(Delegate, uint32_t depth, Control* block) \
F(CatchAll, Control* block) \
F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \
const MemoryAccessImmediate<validate>& imm, Value* result) \
F(AtomicFence) \
F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(DataDrop, const IndexImmediate<validate>& imm) \
F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
const Value& value, const Value& size) \
F(TableInit, const TableInitImmediate<validate>& imm, \
base::Vector<Value> args) \
F(ElemDrop, const IndexImmediate<validate>& imm) \
F(TableCopy, const TableCopyImmediate<validate>& imm, \
base::Vector<Value> args) \
F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \
const Value& delta, Value* result) \
F(TableSize, const IndexImmediate<validate>& imm, Value* result) \
F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \
const Value& value, const Value& count) \
F(StructGet, const Value& struct_object, \
const FieldImmediate<validate>& field, bool is_signed, Value* result) \
F(StructSet, const Value& struct_object, \
const FieldImmediate<validate>& field, const Value& field_value) \
F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& initial_value, const Value& rtt, \
Value* result) \
F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& rtt, Value* result) \
F(ArrayGet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \
bool is_signed, Value* result) \
F(ArraySet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \
const Value& value) \
F(ArrayLen, const Value& array_obj, Value* result) \
F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \
const Value& dst_index, const Value& length) \
F(I31New, const Value& input, Value* result) \
F(I31GetS, const Value& input, Value* result) \
F(I31GetU, const Value& input, Value* result) \
F(RefTest, const Value& obj, const Value& rtt, Value* result) \
F(RefCast, const Value& obj, const Value& rtt, Value* result) \
F(AssertNull, const Value& obj, Value* result) \
F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \
uint32_t depth) \
F(BrOnCastFail, const Value& obj, const Value& rtt, \
Value* result_on_fallthrough, uint32_t depth) \
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) \
F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \
#define INTERFACE_NON_CONSTANT_FUNCTIONS(F) /* force 80 columns */ \
/* Control: */ \
F(Block, Control* block) \
F(Loop, Control* block) \
F(Try, Control* block) \
F(If, const Value& cond, Control* if_block) \
F(FallThruTo, Control* c) \
F(PopControl, Control* block) \
/* Instructions: */ \
F(UnOp, WasmOpcode opcode, const Value& value, Value* result) \
F(BinOp, WasmOpcode opcode, const Value& lhs, const Value& rhs, \
Value* result) \
F(RefAsNonNull, const Value& arg, Value* result) \
F(Drop) \
F(LocalGet, Value* result, const IndexImmediate<validate>& imm) \
F(LocalSet, const Value& value, const IndexImmediate<validate>& imm) \
F(LocalTee, const Value& value, Value* result, \
const IndexImmediate<validate>& imm) \
F(AllocateLocals, base::Vector<Value> local_values) \
F(DeallocateLocals, uint32_t count) \
F(GlobalSet, const Value& value, const GlobalIndexImmediate<validate>& imm) \
F(TableGet, const Value& index, Value* result, \
const IndexImmediate<validate>& imm) \
F(TableSet, const Value& index, const Value& value, \
const IndexImmediate<validate>& imm) \
F(Trap, TrapReason reason) \
F(NopForTestingUnsupportedInLiftoff) \
F(Select, const Value& cond, const Value& fval, const Value& tval, \
Value* result) \
F(BrOrRet, uint32_t depth, uint32_t drop_values) \
F(BrIf, const Value& cond, uint32_t depth) \
F(BrTable, const BranchTableImmediate<validate>& imm, const Value& key) \
F(Else, Control* if_block) \
F(LoadMem, LoadType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, Value* result) \
F(LoadTransform, LoadType type, LoadTransformationKind transform, \
const MemoryAccessImmediate<validate>& imm, const Value& index, \
Value* result) \
F(LoadLane, LoadType type, const Value& value, const Value& index, \
const MemoryAccessImmediate<validate>& imm, const uint8_t laneidx, \
Value* result) \
F(StoreMem, StoreType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, const Value& value) \
F(StoreLane, StoreType type, const MemoryAccessImmediate<validate>& imm, \
const Value& index, const Value& value, const uint8_t laneidx) \
F(CurrentMemoryPages, Value* result) \
F(MemoryGrow, const Value& value, Value* result) \
F(CallDirect, const CallFunctionImmediate<validate>& imm, \
const Value args[], Value returns[]) \
F(CallIndirect, const Value& index, \
const CallIndirectImmediate<validate>& imm, const Value args[], \
Value returns[]) \
F(CallRef, const Value& func_ref, const FunctionSig* sig, \
uint32_t sig_index, const Value args[], const Value returns[]) \
F(ReturnCallRef, const Value& func_ref, const FunctionSig* sig, \
uint32_t sig_index, const Value args[]) \
F(ReturnCall, const CallFunctionImmediate<validate>& imm, \
const Value args[]) \
F(ReturnCallIndirect, const Value& index, \
const CallIndirectImmediate<validate>& imm, const Value args[]) \
F(BrOnNull, const Value& ref_object, uint32_t depth, \
bool pass_null_along_branch, Value* result_on_fallthrough) \
F(BrOnNonNull, const Value& ref_object, uint32_t depth) \
F(SimdOp, WasmOpcode opcode, base::Vector<Value> args, Value* result) \
F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
const base::Vector<Value> inputs, Value* result) \
F(S128Const, const Simd128Immediate<validate>& imm, Value* result) \
F(Simd8x16ShuffleOp, const Simd128Immediate<validate>& imm, \
const Value& input0, const Value& input1, Value* result) \
F(Throw, const TagIndexImmediate<validate>& imm, \
const base::Vector<Value>& args) \
F(Rethrow, Control* block) \
F(CatchException, const TagIndexImmediate<validate>& imm, Control* block, \
base::Vector<Value> caught_values) \
F(Delegate, uint32_t depth, Control* block) \
F(CatchAll, Control* block) \
F(AtomicOp, WasmOpcode opcode, base::Vector<Value> args, \
const MemoryAccessImmediate<validate>& imm, Value* result) \
F(AtomicFence) \
F(MemoryInit, const MemoryInitImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(DataDrop, const IndexImmediate<validate>& imm) \
F(MemoryCopy, const MemoryCopyImmediate<validate>& imm, const Value& dst, \
const Value& src, const Value& size) \
F(MemoryFill, const MemoryIndexImmediate<validate>& imm, const Value& dst, \
const Value& value, const Value& size) \
F(TableInit, const TableInitImmediate<validate>& imm, \
base::Vector<Value> args) \
F(ElemDrop, const IndexImmediate<validate>& imm) \
F(TableCopy, const TableCopyImmediate<validate>& imm, \
base::Vector<Value> args) \
F(TableGrow, const IndexImmediate<validate>& imm, const Value& value, \
const Value& delta, Value* result) \
F(TableSize, const IndexImmediate<validate>& imm, Value* result) \
F(TableFill, const IndexImmediate<validate>& imm, const Value& start, \
const Value& value, const Value& count) \
F(StructGet, const Value& struct_object, \
const FieldImmediate<validate>& field, bool is_signed, Value* result) \
F(StructSet, const Value& struct_object, \
const FieldImmediate<validate>& field, const Value& field_value) \
F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& initial_value, const Value& rtt, \
Value* result) \
F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& rtt, Value* result) \
F(ArrayGet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \
bool is_signed, Value* result) \
F(ArraySet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \
const Value& value) \
F(ArrayLen, const Value& array_obj, Value* result) \
F(ArrayCopy, const Value& src, const Value& src_index, const Value& dst, \
const Value& dst_index, const Value& length) \
F(I31New, const Value& input, Value* result) \
F(I31GetS, const Value& input, Value* result) \
F(I31GetU, const Value& input, Value* result) \
F(RefTest, const Value& obj, const Value& rtt, Value* result) \
F(RefCast, const Value& obj, const Value& rtt, Value* result) \
F(AssertNull, const Value& obj, Value* result) \
F(BrOnCast, const Value& obj, const Value& rtt, Value* result_on_branch, \
uint32_t depth) \
F(BrOnCastFail, const Value& obj, const Value& rtt, \
Value* result_on_fallthrough, uint32_t depth) \
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) \
F(BrOnArray, const Value& object, Value* value_on_branch, uint32_t br_depth) \
F(BrOnNonFunc, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonData, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonArray, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth)
// Generic Wasm bytecode decoder with utilities for decoding immediates,
@ -4797,6 +4800,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
case kExprBrOnData:
case kExprBrOnFunc:
case kExprBrOnArray:
case kExprBrOnI31: {
NON_CONST_ONLY
BranchDepthImmediate<validate> branch_depth(this,
@ -4823,7 +4827,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
HeapType::Representation heap_type =
opcode == kExprBrOnFunc
? HeapType::kFunc
: opcode == kExprBrOnData ? HeapType::kData : HeapType::kI31;
: opcode == kExprBrOnData
? HeapType::kData
: opcode == kExprBrOnArray ? HeapType::kArray
: HeapType::kI31;
Value result_on_branch =
CreateValue(ValueType::Ref(heap_type, kNonNullable));
Push(result_on_branch);
@ -4837,6 +4844,8 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CALL_INTERFACE(BrOnFunc, obj, value_on_branch, branch_depth.depth);
} else if (opcode == kExprBrOnData) {
CALL_INTERFACE(BrOnData, obj, value_on_branch, branch_depth.depth);
} else if (opcode == kExprBrOnArray) {
CALL_INTERFACE(BrOnArray, obj, value_on_branch, branch_depth.depth);
} else {
CALL_INTERFACE(BrOnI31, obj, value_on_branch, branch_depth.depth);
}
@ -4848,6 +4857,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
case kExprBrOnNonData:
case kExprBrOnNonFunc:
case kExprBrOnNonArray:
case kExprBrOnNonI31: {
NON_CONST_ONLY
BranchDepthImmediate<validate> branch_depth(this,
@ -4869,7 +4879,10 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
HeapType::Representation heap_type =
opcode == kExprBrOnNonFunc
? HeapType::kFunc
: opcode == kExprBrOnNonData ? HeapType::kData : HeapType::kI31;
: opcode == kExprBrOnNonData
? HeapType::kData
: opcode == kExprBrOnNonArray ? HeapType::kArray
: HeapType::kI31;
Value value_on_fallthrough =
CreateValue(ValueType::Ref(heap_type, kNonNullable));
@ -4880,6 +4893,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
} else if (opcode == kExprBrOnNonData) {
CALL_INTERFACE(BrOnNonData, obj, &value_on_fallthrough,
branch_depth.depth);
} else if (opcode == kExprBrOnNonArray) {
CALL_INTERFACE(BrOnNonArray, obj, &value_on_fallthrough,
branch_depth.depth);
} else {
CALL_INTERFACE(BrOnNonI31, obj, &value_on_fallthrough,
branch_depth.depth);

View File

@ -1257,6 +1257,20 @@ class WasmGraphBuildingInterface {
decoder->position());
}
void BrOnArray(FullDecoder* decoder, const Value& object,
Value* value_on_branch, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>(
decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
true);
}
void BrOnNonArray(FullDecoder* decoder, const Value& object,
Value* value_on_fallthrough, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>(
decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
br_depth, false);
}
void RefIsI31(FullDecoder* decoder, const Value& object, Value* result) {
result->node = builder_->RefIsI31(object.node);
}

View File

@ -439,9 +439,11 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_OP(BrOnFunc, "br_on_func")
CASE_OP(BrOnData, "br_on_data")
CASE_OP(BrOnI31, "br_on_i31")
CASE_OP(BrOnArray, "br_on_array")
CASE_OP(BrOnNonFunc, "br_on_non_func")
CASE_OP(BrOnNonData, "br_on_non_data")
CASE_OP(BrOnNonI31, "br_on_non_i31")
CASE_OP(BrOnNonArray, "br_on_non_array")
case kNumericPrefix:
case kSimdPrefix:

View File

@ -707,9 +707,11 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(BrOnFunc, 0xfb60, _) \
V(BrOnData, 0xfb61, _) \
V(BrOnI31, 0xfb62, _) \
V(BrOnArray, 0xfb66, _) /* not standardized - V8 experimental */ \
V(BrOnNonFunc, 0xfb63, _) \
V(BrOnNonData, 0xfb64, _) \
V(BrOnNonI31, 0xfb65, _)
V(BrOnNonI31, 0xfb65, _) \
V(BrOnNonArray, 0xfb67, _) /* not standardized - V8 experimental */
#define FOREACH_ATOMIC_0_OPERAND_OPCODE(V) \
/* AtomicFence does not target a particular linear memory. */ \

View File

@ -2000,6 +2000,11 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
byte kBrOnDataNotTaken = BR_ON(DATA, Data, WASM_REF_FUNC(function_index));
byte kBrOnFuncTaken = BR_ON(FUNC, Func, WASM_REF_FUNC(function_index));
byte kBrOnFuncNotTaken = BR_ON(FUNC, Func, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnArrayTaken =
BR_ON(ARRAY, Array,
WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
WASM_RTT_CANON(array_index)));
byte kBrOnArrayNotTaken = BR_ON(ARRAY, Array, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnI31Taken = BR_ON(I31, I31, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnI31NotTaken =
BR_ON(I31, I31,
@ -2026,6 +2031,12 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
byte kBrOnNonFuncNotTaken =
BR_ON_NON(FUNC, Func, WASM_REF_FUNC(function_index));
byte kBrOnNonFuncTaken = BR_ON_NON(FUNC, Func, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnNonArrayNotTaken =
BR_ON_NON(ARRAY, Array,
WASM_ARRAY_NEW_DEFAULT_WITH_RTT(array_index, WASM_I32V(10),
WASM_RTT_CANON(array_index)));
byte kBrOnNonArrayTaken =
BR_ON_NON(ARRAY, Array, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnNonI31NotTaken = BR_ON_NON(I31, I31, WASM_I31_NEW(WASM_I32V(42)));
byte kBrOnNonI31Taken =
BR_ON_NON(I31, I31,
@ -2069,6 +2080,8 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
tester.CheckResult(kBrOnDataNotTaken, 0);
tester.CheckResult(kBrOnFuncTaken, 1);
tester.CheckResult(kBrOnFuncNotTaken, 0);
tester.CheckResult(kBrOnArrayTaken, 1);
tester.CheckResult(kBrOnArrayNotTaken, 0);
tester.CheckResult(kBrOnI31Taken, 1);
tester.CheckResult(kBrOnI31NotTaken, 0);
@ -2076,6 +2089,8 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
tester.CheckResult(kBrOnNonDataNotTaken, 1);
tester.CheckResult(kBrOnNonFuncTaken, 0);
tester.CheckResult(kBrOnNonFuncNotTaken, 1);
tester.CheckResult(kBrOnNonArrayTaken, 0);
tester.CheckResult(kBrOnNonArrayNotTaken, 1);
tester.CheckResult(kBrOnNonI31Taken, 0);
tester.CheckResult(kBrOnNonI31NotTaken, 1);
}

View File

@ -539,11 +539,15 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#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)
#define WASM_BR_ON_ARRAY(depth) \
WASM_GC_OP(kExprBrOnArray), static_cast<byte>(depth)
#define WASM_BR_ON_DATA(depth) \
WASM_GC_OP(kExprBrOnData), static_cast<byte>(depth)
#define WASM_BR_ON_I31(depth) WASM_GC_OP(kExprBrOnI31), static_cast<byte>(depth)
#define WASM_BR_ON_NON_FUNC(depth) \
WASM_GC_OP(kExprBrOnNonFunc), static_cast<byte>(depth)
#define WASM_BR_ON_NON_ARRAY(depth) \
WASM_GC_OP(kExprBrOnNonArray), static_cast<byte>(depth)
#define WASM_BR_ON_NON_DATA(depth) \
WASM_GC_OP(kExprBrOnNonData), static_cast<byte>(depth)
#define WASM_BR_ON_NON_I31(depth) \

View File

@ -515,6 +515,11 @@ let kExprRefAsArray = 0x5b;
let kExprBrOnFunc = 0x60;
let kExprBrOnData = 0x61;
let kExprBrOnI31 = 0x62;
let kExprBrOnArray = 0x66;
let kExprBrOnNonFunc = 0x63;
let kExprBrOnNonData = 0x64;
let kExprBrOnNonI31 = 0x65;
let kExprBrOnNonArray = 0x67;
// Numeric opcodes.
let kExprI32SConvertSatF32 = 0x00;