Reland "Reland "[wasm-gc] Ref types: Convert dataref to structref""

This is a reland of commit 3b883e787d

Fixed a test case that was merged in the meantime still using the old
kExprRefAsData which is now called kExprRefAsStruct.

Original change's description:
> Reland "[wasm-gc] Ref types: Convert dataref to structref"
>
> This is a reland of commit 20327d1599
>
> Changed in reland:
> - Added new flag wasm-gc-structref-as-dataref which defaults to true
>   and preserves the existing behavior.
> - Passing --no-wasm-gc-structref-as-dataref enables the new behavior.
> - The flag affects static subtyping information between structref and
>   arrays and the corresponding cast, test and br_on instructions.
> - Even with the old behavior the name still changed to "structref".
>
> Original change's description:
> > [wasm-gc] Ref types: Convert dataref to structref
> >
> > This change changes the type hierarchy in a non-backwards compatible
> > way: dataref is replaced with structref meaning that arrayref is
> > no longer a subtype of it.
> >
> > Bug: v8:7748
> > Change-Id: I965267d9ed11ea7c7d7df133cc39ee63e6b5abc3
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3929041
> > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> > Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#83515}
>
> Bug: v8:7748
> Change-Id: I2d8dd49dbc56246c087ac93452a87f860ead2195
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3945109
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#83697}

Bug: v8:7748
Change-Id: I54f7b141ffc5b7597420fa0c838412be825a260b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3952936
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83706}
This commit is contained in:
Matthias Liedtke 2022-10-14 10:46:34 +02:00 committed by V8 LUCI CQ
parent aed66041b3
commit d4a3ebeb2b
39 changed files with 446 additions and 385 deletions

View File

@ -5431,12 +5431,12 @@ WasmGraphBuilder::Callbacks WasmGraphBuilder::BranchCallbacks(
void WasmGraphBuilder::DataCheck(Node* object, bool object_can_be_null,
Callbacks callbacks, bool null_succeeds) {
// TODO(7748): Only used for backwards compatibility in combination with
// v8_flags.wasm_gc_structref_as_dataref. Remove.
if (object_can_be_null) {
if (null_succeeds) {
callbacks.succeed_if(IsNull(object), BranchHint::kFalse);
} else {
// TODO(7748): Is the extra null check actually beneficial for
// performance?
callbacks.fail_if(IsNull(object), BranchHint::kFalse);
}
}
@ -5530,8 +5530,8 @@ Node* WasmGraphBuilder::RefTestAbstract(Node* object, wasm::HeapType type,
return RefIsEq(object, is_nullable, null_succeeds);
case wasm::HeapType::kI31:
return RefIsI31(object, null_succeeds);
case wasm::HeapType::kData:
return RefIsData(object, is_nullable, null_succeeds);
case wasm::HeapType::kStruct:
return RefIsStruct(object, is_nullable, null_succeeds);
case wasm::HeapType::kArray:
return RefIsArray(object, is_nullable, null_succeeds);
case wasm::HeapType::kAny:
@ -5572,36 +5572,52 @@ Node* WasmGraphBuilder::RefIsEq(Node* object, bool object_can_be_null,
return done.PhiAt(0);
}
Node* WasmGraphBuilder::RefIsData(Node* object, bool object_can_be_null,
bool null_succeeds) {
Node* WasmGraphBuilder::RefIsStruct(Node* object, bool object_can_be_null,
bool null_succeeds) {
auto done = gasm_->MakeLabel(MachineRepresentation::kWord32);
DataCheck(object, object_can_be_null, TestCallbacks(&done), null_succeeds);
if (!v8_flags.wasm_gc_structref_as_dataref) {
ManagedObjectInstanceCheck(object, object_can_be_null, WASM_STRUCT_TYPE,
TestCallbacks(&done), null_succeeds);
} else {
DataCheck(object, object_can_be_null, TestCallbacks(&done), null_succeeds);
}
gasm_->Goto(&done, Int32Constant(1));
gasm_->Bind(&done);
return done.PhiAt(0);
}
Node* WasmGraphBuilder::RefAsData(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position) {
Node* WasmGraphBuilder::RefAsStruct(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position) {
bool null_succeeds = false;
auto done = gasm_->MakeLabel();
DataCheck(object, object_can_be_null, CastCallbacks(&done, position),
null_succeeds);
if (!v8_flags.wasm_gc_structref_as_dataref) {
ManagedObjectInstanceCheck(object, object_can_be_null, WASM_STRUCT_TYPE,
CastCallbacks(&done, position), null_succeeds);
} else {
DataCheck(object, object_can_be_null, CastCallbacks(&done, position),
null_succeeds);
}
gasm_->Goto(&done);
gasm_->Bind(&done);
return object;
}
void WasmGraphBuilder::BrOnData(Node* object, Node* /*rtt*/,
WasmTypeCheckConfig config,
Node** match_control, Node** match_effect,
Node** no_match_control,
Node** no_match_effect) {
void WasmGraphBuilder::BrOnStruct(Node* object, Node* /*rtt*/,
WasmTypeCheckConfig config,
Node** match_control, Node** match_effect,
Node** no_match_control,
Node** no_match_effect) {
bool null_succeeds = false;
BrOnCastAbs(match_control, match_effect, no_match_control, no_match_effect,
[=](Callbacks callbacks) -> void {
return DataCheck(object, config.object_can_be_null, callbacks,
null_succeeds);
if (!v8_flags.wasm_gc_structref_as_dataref) {
return ManagedObjectInstanceCheck(
object, config.object_can_be_null, WASM_STRUCT_TYPE,
callbacks, null_succeeds);
} else {
return DataCheck(object, config.object_can_be_null, callbacks,
null_succeeds);
}
});
}
@ -6407,7 +6423,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
gasm_->Bind(&done);
return done.PhiAt(0);
}
case wasm::HeapType::kData:
case wasm::HeapType::kStruct:
case wasm::HeapType::kArray:
// TODO(7748): Update this when JS interop is settled.
if (type.kind() == wasm::kRefNull) {
@ -6548,7 +6564,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::HeapType::kI31:
UNREACHABLE();
case wasm::HeapType::kFunc:
case wasm::HeapType::kData:
case wasm::HeapType::kStruct:
case wasm::HeapType::kArray:
case wasm::HeapType::kEq:
default: {

View File

@ -501,12 +501,12 @@ class WasmGraphBuilder {
Node** match_control, Node** match_effect,
Node** no_match_control, Node** no_match_effect);
Node* RefIsEq(Node* object, bool object_can_be_null, bool null_succeeds);
Node* RefIsData(Node* object, bool object_can_be_null, bool null_succeeds);
Node* RefAsData(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position);
void BrOnData(Node* object, Node* rtt, WasmTypeCheckConfig config,
Node** match_control, Node** match_effect,
Node** no_match_control, Node** no_match_effect);
Node* RefIsStruct(Node* object, bool object_can_be_null, bool null_succeeds);
Node* RefAsStruct(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position);
void BrOnStruct(Node* object, Node* rtt, WasmTypeCheckConfig config,
Node** match_control, Node** match_effect,
Node** no_match_control, Node** no_match_effect);
Node* RefIsArray(Node* object, bool object_can_be_null, bool null_succeeds);
Node* RefAsArray(Node* object, bool object_can_be_null,
wasm::WasmCodePosition position);

View File

@ -1116,6 +1116,8 @@ DEFINE_IMPLICATION(experimental_wasm_stack_switching,
experimental_wasm_type_reflection)
DEFINE_BOOL(wasm_gc_js_interop, true, "experimental WasmGC-JS interop")
DEFINE_BOOL(wasm_gc_structref_as_dataref, true,
"compatibility mode: Treat structref as dataref")
DEFINE_BOOL(wasm_staging, false, "enable staged wasm features")

View File

@ -5997,8 +5997,8 @@ class LiftoffCompiler {
return RefIsEq(decoder, obj, result_val, null_succeeds);
case HeapType::kI31:
return RefIsI31(decoder, obj, result_val, null_succeeds);
case HeapType::kData:
return RefIsData(decoder, obj, result_val, null_succeeds);
case HeapType::kStruct:
return RefIsStruct(decoder, obj, result_val, null_succeeds);
case HeapType::kArray:
return RefIsArray(decoder, obj, result_val, null_succeeds);
case HeapType::kAny:
@ -6139,15 +6139,19 @@ class LiftoffCompiler {
}
// Abstract type checkers. They all fall through on match.
void DataCheck(TypeCheck& check, const FreezeCacheState& frozen) {
void StructCheck(TypeCheck& check, const FreezeCacheState& frozen) {
LoadInstanceType(check, frozen, check.no_match);
// We're going to test a range of WasmObject instance types with a single
// unsigned comparison.
Register tmp = check.instance_type();
__ emit_i32_subi(tmp, tmp, FIRST_WASM_OBJECT_TYPE);
__ emit_i32_cond_jumpi(kUnsignedGreaterThan, check.no_match, tmp,
LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE,
frozen);
LiftoffRegister instance_type(check.instance_type());
if (!v8_flags.wasm_gc_structref_as_dataref) {
__ emit_i32_cond_jumpi(kUnequal, check.no_match, check.instance_type(),
WASM_STRUCT_TYPE, frozen);
} else {
Register tmp = check.instance_type();
__ emit_i32_subi(tmp, tmp, FIRST_WASM_OBJECT_TYPE);
__ emit_i32_cond_jumpi(kUnsignedGreaterThan, check.no_match, tmp,
LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE,
frozen);
}
}
void ArrayCheck(TypeCheck& check, const FreezeCacheState& frozen) {
@ -6206,9 +6210,9 @@ class LiftoffCompiler {
__ PushRegister(kI32, result);
}
void RefIsData(FullDecoder* /* decoder */, const Value& object,
Value* /* result_val */, bool null_succeeds = false) {
AbstractTypeCheck<&LiftoffCompiler::DataCheck>(object, null_succeeds);
void RefIsStruct(FullDecoder* /* decoder */, const Value& object,
Value* /* result_val */, bool null_succeeds = false) {
AbstractTypeCheck<&LiftoffCompiler::StructCheck>(object, null_succeeds);
}
void RefIsEq(FullDecoder* /* decoder */, const Value& object,
@ -6238,9 +6242,9 @@ class LiftoffCompiler {
(this->*type_checker)(check, frozen);
}
void RefAsData(FullDecoder* decoder, const Value& object,
Value* /* result */) {
AbstractTypeCast<&LiftoffCompiler::DataCheck>(object, decoder, kRef);
void RefAsStruct(FullDecoder* decoder, const Value& object,
Value* /* result */) {
AbstractTypeCast<&LiftoffCompiler::StructCheck>(object, decoder, kRef);
}
void RefAsI31(FullDecoder* decoder, const Value& object, Value* result) {
@ -6294,9 +6298,9 @@ class LiftoffCompiler {
__ bind(&end);
}
void BrOnData(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
BrOnAbstractType<&LiftoffCompiler::DataCheck>(object, decoder, br_depth);
void BrOnStruct(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
BrOnAbstractType<&LiftoffCompiler::StructCheck>(object, decoder, br_depth);
}
void BrOnI31(FullDecoder* decoder, const Value& object,
@ -6309,9 +6313,10 @@ class LiftoffCompiler {
BrOnAbstractType<&LiftoffCompiler::ArrayCheck>(object, decoder, br_depth);
}
void BrOnNonData(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
BrOnNonAbstractType<&LiftoffCompiler::DataCheck>(object, decoder, br_depth);
void BrOnNonStruct(FullDecoder* decoder, const Value& object,
Value* /* value_on_branch */, uint32_t br_depth) {
BrOnNonAbstractType<&LiftoffCompiler::StructCheck>(object, decoder,
br_depth);
}
void BrOnNonI31(FullDecoder* decoder, const Value& object,

View File

@ -238,7 +238,7 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
switch (code) {
case kEqRefCode:
case kI31RefCode:
case kDataRefCode:
case kStructRefCode:
case kArrayRefCode:
case kAnyRefCode:
case kNoneCode:
@ -313,7 +313,7 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
switch (code) {
case kEqRefCode:
case kI31RefCode:
case kDataRefCode:
case kStructRefCode:
case kArrayRefCode:
case kAnyRefCode:
case kNoneCode:
@ -1076,17 +1076,18 @@ struct ControlBase : public PcForErrors<validate> {
uint32_t depth) \
F(BrOnCastFail, const Value& obj, const Value& rtt, \
Value* result_on_fallthrough, uint32_t depth) \
F(RefIsData, const Value& object, Value* result) \
F(RefIsStruct, const Value& object, Value* result) \
F(RefIsEq, const Value& object, Value* result) \
F(RefIsI31, const Value& object, Value* result) \
F(RefIsArray, const Value& object, Value* result) \
F(RefAsData, const Value& object, Value* result) \
F(RefAsStruct, const Value& object, Value* result) \
F(RefAsI31, const Value& object, Value* result) \
F(RefAsArray, const Value& object, Value* result) \
F(BrOnData, const Value& object, Value* value_on_branch, uint32_t br_depth) \
F(BrOnStruct, 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(BrOnNonData, const Value& object, Value* value_on_fallthrough, \
F(BrOnNonStruct, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
F(BrOnNonI31, const Value& object, Value* value_on_fallthrough, \
uint32_t br_depth) \
@ -2045,10 +2046,10 @@ class WasmDecoder : public Decoder {
return length + array_imm.length + data_imm.length;
}
case kExprBrOnArray:
case kExprBrOnData:
case kExprBrOnStruct:
case kExprBrOnI31:
case kExprBrOnNonArray:
case kExprBrOnNonData:
case kExprBrOnNonStruct:
case kExprBrOnNonI31: {
BranchDepthImmediate<validate> imm(decoder, pc + length);
if (io) io->BranchDepth(imm);
@ -2081,10 +2082,10 @@ class WasmDecoder : public Decoder {
case kExprI31GetS:
case kExprI31GetU:
case kExprRefAsArray:
case kExprRefAsData:
case kExprRefAsStruct:
case kExprRefAsI31:
case kExprRefIsArray:
case kExprRefIsData:
case kExprRefIsStruct:
case kExprRefIsI31:
case kExprExternInternalize:
case kExprExternExternalize:
@ -4816,9 +4817,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Value obj = Peek(1);
Value value = CreateValue(kWasmI32);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmDataRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmStructRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmArrayRef, this->module_) ||
obj.type.is_bottom())) {
PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)");
PopTypeError(0, obj,
"subtype of (ref null func), (ref null struct) or (ref "
"null array)");
return 0;
}
if (current_code_reachable_and_ok_) {
@ -4862,9 +4866,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
opcode_length += imm.length;
Value obj = Peek(0);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmDataRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmStructRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmArrayRef, this->module_) ||
obj.type.is_bottom())) {
PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)");
PopTypeError(0, obj,
"subtype of (ref null func), (ref null struct) or (ref "
"null array)");
return 0;
}
Value value = CreateValue(ValueType::RefMaybeNull(
@ -4886,9 +4893,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(rtt);
Value obj = Peek(1);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmDataRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmStructRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmArrayRef, this->module_) ||
obj.type.is_bottom())) {
PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)");
PopTypeError(0, obj,
"subtype of (ref null func), (ref null struct) or (ref "
"null array)");
return 0;
}
// If either value is bottom, we emit the most specific type possible.
@ -4943,9 +4953,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
// anyway.
Value obj = Peek(0);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmDataRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmStructRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmArrayRef, this->module_) ||
obj.type.is_bottom())) {
PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)");
PopTypeError(0, obj,
"subtype of (ref null func), (ref null struct) or (ref "
"null array)");
return 0;
}
Control* c = control_at(branch_depth.depth);
@ -5010,9 +5023,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
CALL_INTERFACE_IF_OK_AND_REACHABLE(RttCanon, imm.index, &rtt);
Value obj = Peek(0);
if (!VALIDATE(IsSubtypeOf(obj.type, kWasmFuncRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmDataRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmStructRef, this->module_) ||
IsSubtypeOf(obj.type, kWasmArrayRef, this->module_) ||
obj.type.is_bottom())) {
PopTypeError(0, obj, "subtype of (ref null func) or (ref null data)");
PopTypeError(0, obj,
"subtype of (ref null func), (ref null struct) or (ref "
"null array)");
return 0;
}
Control* c = control_at(branch_depth.depth);
@ -5092,7 +5108,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(result); \
return opcode_length; \
}
ABSTRACT_TYPE_CHECK(Data)
ABSTRACT_TYPE_CHECK(Struct)
ABSTRACT_TYPE_CHECK(I31)
ABSTRACT_TYPE_CHECK(Array)
#undef ABSTRACT_TYPE_CHECK
@ -5126,12 +5142,12 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(result); \
return opcode_length; \
}
ABSTRACT_TYPE_CAST(Data)
ABSTRACT_TYPE_CAST(Struct)
ABSTRACT_TYPE_CAST(I31)
ABSTRACT_TYPE_CAST(Array)
#undef ABSTRACT_TYPE_CAST
case kExprBrOnData:
case kExprBrOnStruct:
case kExprBrOnArray:
case kExprBrOnI31: {
NON_CONST_ONLY
@ -5157,7 +5173,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Value obj = Peek(0, 0, kWasmAnyRef);
Drop(obj);
HeapType::Representation heap_type =
opcode == kExprBrOnData ? HeapType::kData
opcode == kExprBrOnStruct ? HeapType::kStruct
: opcode == kExprBrOnArray ? HeapType::kArray
: HeapType::kI31;
Value result_on_branch = CreateValue(ValueType::Ref(heap_type));
@ -5168,8 +5184,9 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
// {result_on_branch} which was passed-by-value to {Push}.
Value* value_on_branch = stack_value(1);
if (V8_LIKELY(current_code_reachable_and_ok_)) {
if (opcode == kExprBrOnData) {
CALL_INTERFACE(BrOnData, obj, value_on_branch, branch_depth.depth);
if (opcode == kExprBrOnStruct) {
CALL_INTERFACE(BrOnStruct, obj, value_on_branch,
branch_depth.depth);
} else if (opcode == kExprBrOnArray) {
CALL_INTERFACE(BrOnArray, obj, value_on_branch, branch_depth.depth);
} else {
@ -5181,7 +5198,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(obj); // Restore stack state on fallthrough.
return opcode_length + branch_depth.length;
}
case kExprBrOnNonData:
case kExprBrOnNonStruct:
case kExprBrOnNonArray:
case kExprBrOnNonI31: {
NON_CONST_ONLY
@ -5202,14 +5219,14 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Value obj = Peek(0, 0, kWasmAnyRef);
HeapType::Representation heap_type =
opcode == kExprBrOnNonData ? HeapType::kData
opcode == kExprBrOnNonStruct ? HeapType::kStruct
: opcode == kExprBrOnNonArray ? HeapType::kArray
: HeapType::kI31;
Value value_on_fallthrough = CreateValue(ValueType::Ref(heap_type));
if (V8_LIKELY(current_code_reachable_and_ok_)) {
if (opcode == kExprBrOnNonData) {
CALL_INTERFACE(BrOnNonData, obj, &value_on_fallthrough,
if (opcode == kExprBrOnNonStruct) {
CALL_INTERFACE(BrOnNonStruct, obj, &value_on_fallthrough,
branch_depth.depth);
} else if (opcode == kExprBrOnNonArray) {
CALL_INTERFACE(BrOnNonArray, obj, &value_on_fallthrough,

View File

@ -1314,30 +1314,30 @@ class WasmGraphBuildingInterface {
null_succeeds));
}
void RefIsData(FullDecoder* decoder, const Value& object, Value* result) {
void RefIsStruct(FullDecoder* decoder, const Value& object, Value* result) {
bool null_succeeds = false;
SetAndTypeNode(result,
builder_->RefIsData(object.node, object.type.is_nullable(),
null_succeeds));
builder_->RefIsStruct(object.node, object.type.is_nullable(),
null_succeeds));
}
void RefAsData(FullDecoder* decoder, const Value& object, Value* result) {
TFNode* cast_object = builder_->RefAsData(
void RefAsStruct(FullDecoder* decoder, const Value& object, Value* result) {
TFNode* cast_object = builder_->RefAsStruct(
object.node, object.type.is_nullable(), decoder->position());
TFNode* rename = builder_->TypeGuard(cast_object, result->type);
SetAndTypeNode(result, rename);
}
void BrOnData(FullDecoder* decoder, const Value& object,
Value* value_on_branch, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>(
void BrOnStruct(FullDecoder* decoder, const Value& object,
Value* value_on_branch, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnStruct>(
decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
true);
}
void BrOnNonData(FullDecoder* decoder, const Value& object,
Value* value_on_fallthrough, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>(
void BrOnNonStruct(FullDecoder* decoder, const Value& object,
Value* value_on_fallthrough, uint32_t br_depth) {
BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnStruct>(
decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
br_depth, false);
}

View File

@ -62,7 +62,7 @@ class HeapType {
kFunc = kV8MaxWasmTypes, // shorthand: c
kEq, // shorthand: q
kI31, // shorthand: j
kData, // shorthand: o
kStruct, // shorthand: o
kArray, // shorthand: g
kAny, //
kExtern, // shorthand: a.
@ -90,8 +90,8 @@ class HeapType {
return HeapType(kAny);
case ValueTypeCode::kExternRefCode:
return HeapType(kExtern);
case ValueTypeCode::kDataRefCode:
return HeapType(kData);
case ValueTypeCode::kStructRefCode:
return HeapType(kStruct);
case ValueTypeCode::kArrayRefCode:
return HeapType(kArray);
case ValueTypeCode::kStringRefCode:
@ -156,8 +156,8 @@ class HeapType {
return std::string("eq");
case kI31:
return std::string("i31");
case kData:
return std::string("data");
case kStruct:
return std::string("struct");
case kArray:
return std::string("array");
case kExtern:
@ -195,8 +195,8 @@ class HeapType {
return mask | kEqRefCode;
case kI31:
return mask | kI31RefCode;
case kData:
return mask | kDataRefCode;
case kStruct:
return mask | kStructRefCode;
case kArray:
return mask | kArrayRefCode;
case kExtern:
@ -550,8 +550,8 @@ class ValueType {
return kAnyRefCode;
case HeapType::kI31:
return kI31RefCode;
case HeapType::kData:
return kDataRefCode;
case HeapType::kStruct:
return kStructRefCode;
case HeapType::kArray:
return kArrayRefCode;
case HeapType::kString:
@ -702,7 +702,7 @@ constexpr ValueType kWasmAnyRef = ValueType::RefNull(HeapType::kAny);
constexpr ValueType kWasmExternRef = ValueType::RefNull(HeapType::kExtern);
constexpr ValueType kWasmEqRef = ValueType::RefNull(HeapType::kEq);
constexpr ValueType kWasmI31Ref = ValueType::RefNull(HeapType::kI31);
constexpr ValueType kWasmDataRef = ValueType::RefNull(HeapType::kData);
constexpr ValueType kWasmStructRef = ValueType::RefNull(HeapType::kStruct);
constexpr ValueType kWasmArrayRef = ValueType::RefNull(HeapType::kArray);
constexpr ValueType kWasmStringRef = ValueType::RefNull(HeapType::kString);
constexpr ValueType kWasmStringViewWtf8 =

View File

@ -48,7 +48,7 @@ enum ValueTypeCode : uint8_t {
kRefNullCode = 0x6c,
kRefCode = 0x6b,
kI31RefCode = 0x6a,
kDataRefCode = 0x67,
kStructRefCode = 0x67,
kArrayRefCode = 0x66,
kNoneCode = 0x65,
kStringRefCode = 0x64,

View File

@ -1174,8 +1174,8 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
string->StringEquals(v8_str(isolate, "eqref"))) {
type = i::wasm::kWasmEqRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "dataref"))) {
type = i::wasm::kWasmDataRef;
string->StringEquals(v8_str(isolate, "structref"))) {
type = i::wasm::kWasmStructRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "arrayref"))) {
type = i::wasm::kWasmArrayRef;
@ -1390,8 +1390,8 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
string->StringEquals(v8_str(isolate, "anyref"))) {
*type = i::wasm::kWasmAnyRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "dataref"))) {
*type = i::wasm::kWasmDataRef;
string->StringEquals(v8_str(isolate, "structref"))) {
*type = i::wasm::kWasmStructRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "arrayref"))) {
*type = i::wasm::kWasmArrayRef;
@ -1747,7 +1747,7 @@ void EncodeExceptionValues(v8::Isolate* isolate,
case i::wasm::HeapType::kAny:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kI31:
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kStruct:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kString:
case i::wasm::HeapType::kStringViewWtf8:
@ -2263,7 +2263,7 @@ void WasmObjectToJSReturnValue(v8::ReturnValue<v8::Value>& return_value,
return;
case i::wasm::HeapType::kBottom:
UNREACHABLE();
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kStruct:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kAny: {
@ -2572,7 +2572,7 @@ void WebAssemblyExceptionGetArg(
case i::wasm::HeapType::kAny:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kI31:
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kStruct:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kString:
case i::wasm::HeapType::kStringViewWtf8:
@ -2636,7 +2636,7 @@ void WebAssemblyExceptionGetArg(
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kI31:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kStruct:
case i::wasm::HeapType::kString:
case i::wasm::HeapType::kStringViewWtf8:
case i::wasm::HeapType::kStringViewWtf16:

View File

@ -325,7 +325,7 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
case wasm::HeapType::kStringViewWtf16:
case wasm::HeapType::kStringViewIter:
case wasm::HeapType::kEq:
case wasm::HeapType::kData:
case wasm::HeapType::kStruct:
case wasm::HeapType::kArray:
case wasm::HeapType::kAny:
case wasm::HeapType::kI31:
@ -373,7 +373,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
case wasm::HeapType::kString:
case wasm::HeapType::kEq:
case wasm::HeapType::kI31:
case wasm::HeapType::kData:
case wasm::HeapType::kStruct:
case wasm::HeapType::kArray:
case wasm::HeapType::kAny:
return entry;
@ -2291,15 +2291,16 @@ MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
*error_message = "null is not allowed for (ref any)";
return {};
}
case HeapType::kData: {
case HeapType::kStruct: {
if (v8_flags.wasm_gc_js_interop
? value->IsWasmStruct() || value->IsWasmArray()
? value->IsWasmStruct() ||
(value->IsWasmArray() &&
v8_flags.wasm_gc_structref_as_dataref)
: TryUnpackObjectWrapper(isolate, value)) {
return value;
}
*error_message =
"dataref object must be null (if nullable) or a wasm "
"struct/array";
"structref object must be null (if nullable) or a wasm struct";
return {};
}
case HeapType::kArray: {

View File

@ -714,16 +714,16 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(BrOnCast, 0xfb46, _, "br_on_cast") \
V(BrOnCastFail, 0xfb47, _, "br_on_cast_fail") \
V(RefCastNop, 0xfb4c, _, "ref.cast_nop") \
V(RefIsData, 0xfb51, _, "ref.is_data") \
V(RefIsStruct, 0xfb51, _, "ref.is_struct") \
V(RefIsI31, 0xfb52, _, "ref.is_i31") \
V(RefIsArray, 0xfb53, _, "ref.is_array") \
V(RefAsData, 0xfb59, _, "ref.as_data") \
V(RefAsStruct, 0xfb59, _, "ref.as_struct") \
V(RefAsI31, 0xfb5a, _, "ref.as_i31") \
V(RefAsArray, 0xfb5b, _, "ref.as_array") \
V(BrOnData, 0xfb61, _, "br_on_data") \
V(BrOnStruct, 0xfb61, _, "br_on_struct") \
V(BrOnI31, 0xfb62, _, "br_on_i31") \
V(BrOnArray, 0xfb66, _, "br_on_array") \
V(BrOnNonData, 0xfb64, _, "br_on_non_data") \
V(BrOnNonStruct, 0xfb64, _, "br_on_non_struct") \
V(BrOnNonI31, 0xfb65, _, "br_on_non_i31") \
V(BrOnNonArray, 0xfb67, _, "br_on_non_array") \
V(ExternInternalize, 0xfb70, _, "extern.internalize") \

View File

@ -4,6 +4,7 @@
#include "src/wasm/wasm-subtyping.h"
#include "src/base/v8-fallthrough.h"
#include "src/wasm/canonical-types.h"
#include "src/wasm/wasm-module.h"
@ -104,7 +105,7 @@ HeapType::Representation NullSentinelImpl(HeapType type,
case HeapType::kI31:
case HeapType::kNone:
case HeapType::kEq:
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kArray:
case HeapType::kAny:
case HeapType::kString:
@ -211,12 +212,17 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl(
case HeapType::kExtern:
return super_heap == HeapType::kExtern;
case HeapType::kI31:
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kArray:
if (v8_flags.wasm_gc_structref_as_dataref &&
sub_heap.representation() == HeapType::kArray) {
// TODO(7748): Remove temporary workaround for backwards compatibility.
return super_heap == HeapType::kArray ||
super_heap == HeapType::kStruct || super_heap == HeapType::kEq ||
super_heap == HeapType::kAny;
}
return super_heap == sub_heap || super_heap == HeapType::kEq ||
super_heap == HeapType::kAny;
case HeapType::kArray:
return super_heap == HeapType::kArray || super_heap == HeapType::kData ||
super_heap == HeapType::kEq || super_heap == HeapType::kAny;
case HeapType::kString:
// stringref is a subtype of anyref under wasm-gc.
return sub_heap == super_heap ||
@ -256,8 +262,12 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl(
switch (super_heap.representation()) {
case HeapType::kFunc:
return sub_module->has_signature(sub_index);
case HeapType::kStruct:
if (!v8_flags.wasm_gc_structref_as_dataref) {
return sub_module->has_struct(sub_index);
}
V8_FALLTHROUGH;
case HeapType::kEq:
case HeapType::kData:
case HeapType::kAny:
return !sub_module->has_signature(sub_index);
case HeapType::kArray:
@ -345,14 +355,25 @@ HeapType::Representation CommonAncestor(uint32_t type_index1,
DCHECK_EQ(kind2, kind1);
return HeapType::kFunc;
case TypeDefinition::kStruct:
DCHECK_NE(kind2, TypeDefinition::kFunction);
return HeapType::kData;
if (v8_flags.wasm_gc_structref_as_dataref) {
DCHECK_NE(kind2, TypeDefinition::kFunction);
return HeapType::kStruct;
}
switch (kind2) {
case TypeDefinition::kFunction:
UNREACHABLE();
case TypeDefinition::kStruct:
return HeapType::kStruct;
case TypeDefinition::kArray:
return HeapType::kEq;
}
case TypeDefinition::kArray:
switch (kind2) {
case TypeDefinition::kFunction:
UNREACHABLE();
case TypeDefinition::kStruct:
return HeapType::kData;
return v8_flags.wasm_gc_structref_as_dataref ? HeapType::kStruct
: HeapType::kEq;
case TypeDefinition::kArray:
return HeapType::kArray;
}
@ -380,7 +401,7 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
case HeapType::kNone:
return HeapType::kI31;
case HeapType::kEq:
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kArray:
return HeapType::kEq;
case HeapType::kAny:
@ -394,12 +415,14 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
return module2->has_signature(heap2.ref_index()) ? HeapType::kBottom
: HeapType::kEq;
}
case HeapType::kData:
case HeapType::kStruct:
switch (heap2.representation()) {
case HeapType::kData:
case HeapType::kArray:
case HeapType::kStruct:
case HeapType::kNone:
return HeapType::kData;
return HeapType::kStruct;
case HeapType::kArray:
return v8_flags.wasm_gc_structref_as_dataref ? HeapType::kStruct
: HeapType::kEq;
case HeapType::kI31:
case HeapType::kEq:
return HeapType::kEq;
@ -412,15 +435,17 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
UNREACHABLE();
default:
return module2->has_signature(heap2.ref_index()) ? HeapType::kBottom
: HeapType::kData;
: module2->has_struct(heap2.ref_index()) ? HeapType::kStruct
: v8_flags.wasm_gc_structref_as_dataref ? HeapType::kStruct
: HeapType::kEq;
}
case HeapType::kArray:
switch (heap2.representation()) {
case HeapType::kArray:
case HeapType::kNone:
return HeapType::kArray;
case HeapType::kData:
return HeapType::kData;
case HeapType::kStruct:
return HeapType::kEq;
case HeapType::kI31:
case HeapType::kEq:
return HeapType::kEq;
@ -432,9 +457,12 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
case HeapType::kNoFunc:
UNREACHABLE();
default:
return module2->has_array(heap2.ref_index()) ? HeapType::kArray
: module2->has_struct(heap2.ref_index()) ? HeapType::kData
: HeapType::kBottom;
return module2->has_array(heap2.ref_index()) ? HeapType::kArray
: module2->has_struct(heap2.ref_index())
? (v8_flags.wasm_gc_structref_as_dataref
? HeapType::kStruct
: HeapType::kEq)
: HeapType::kBottom;
}
case HeapType::kAny:
return HeapType::kAny;
@ -446,7 +474,7 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
switch (heap2.representation()) {
case HeapType::kArray:
case HeapType::kNone:
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kI31:
case HeapType::kEq:
case HeapType::kAny:

View File

@ -571,7 +571,7 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
const byte other_type_index = tester.DefineStruct({F(kWasmF32, true)});
const byte kTestStructStatic = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmDataRef},
tester.sigs.i_v(), {kWasmI32, kWasmStructRef},
{WASM_BLOCK_R(
ValueType::RefNull(type_index), WASM_LOCAL_SET(0, WASM_I32V(111)),
// Pipe a struct through a local so it's statically typed
@ -593,7 +593,7 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
kExprI32Add, kExprEnd});
const byte kTestNull = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmDataRef},
tester.sigs.i_v(), {kWasmI32, kWasmStructRef},
{WASM_BLOCK_R(
ValueType::RefNull(type_index), WASM_LOCAL_SET(0, WASM_I32V(111)),
WASM_LOCAL_GET(1), // Put a nullref onto the value stack.
@ -604,7 +604,7 @@ WASM_COMPILED_EXEC_TEST(BrOnCast) {
WASM_DROP, WASM_LOCAL_GET(0), kExprEnd});
const byte kTypedAfterBranch = tester.DefineFunction(
tester.sigs.i_v(), {kWasmI32, kWasmDataRef},
tester.sigs.i_v(), {kWasmI32, kWasmStructRef},
{WASM_LOCAL_SET(1, WASM_STRUCT_NEW(type_index, WASM_I32V(42))),
WASM_BLOCK_I(
// The inner block should take the early branch with a struct
@ -645,7 +645,7 @@ WASM_COMPILED_EXEC_TEST(BrOnCastFail) {
#define FUNCTION_BODY(value) \
WASM_LOCAL_SET(0, WASM_SEQ(value)), \
WASM_BLOCK( \
WASM_BLOCK_R(kWasmDataRef, WASM_LOCAL_GET(0), \
WASM_BLOCK_R(kWasmStructRef, WASM_LOCAL_GET(0), \
WASM_BR_ON_CAST_FAIL(0, type0), \
WASM_GC_OP(kExprStructGet), type0, 0, kExprReturn), \
kExprBrOnNull, 0, WASM_GC_OP(kExprRefCast), type1, \
@ -653,16 +653,17 @@ WASM_COMPILED_EXEC_TEST(BrOnCastFail) {
WASM_I32V(null_value), kExprEnd
const byte kBranchTaken = tester.DefineFunction(
tester.sigs.i_v(), {kWasmDataRef},
tester.sigs.i_v(), {kWasmStructRef},
{FUNCTION_BODY(
WASM_STRUCT_NEW(type1, WASM_I64V(10), WASM_I32V(field1_value)))});
const byte kBranchNotTaken = tester.DefineFunction(
tester.sigs.i_v(), {kWasmDataRef},
tester.sigs.i_v(), {kWasmStructRef},
{FUNCTION_BODY(WASM_STRUCT_NEW(type0, WASM_I32V(field0_value)))});
const byte kNull = tester.DefineFunction(
tester.sigs.i_v(), {kWasmDataRef}, {FUNCTION_BODY(WASM_REF_NULL(type0))});
const byte kNull =
tester.DefineFunction(tester.sigs.i_v(), {kWasmStructRef},
{FUNCTION_BODY(WASM_REF_NULL(type0))});
const byte kUnrelatedTypes = tester.DefineFunction(
tester.sigs.i_v(), {ValueType::RefNull(type1)},
@ -671,11 +672,11 @@ WASM_COMPILED_EXEC_TEST(BrOnCastFail) {
#undef FUNCTION_BODY
const byte kBranchTakenStatic = tester.DefineFunction(
tester.sigs.i_v(), {kWasmDataRef},
tester.sigs.i_v(), {kWasmStructRef},
{WASM_LOCAL_SET(
0, WASM_STRUCT_NEW(type1, WASM_I64V(10), WASM_I32V(field1_value))),
WASM_BLOCK(
WASM_BLOCK_R(kWasmDataRef, WASM_LOCAL_GET(0),
WASM_BLOCK_R(kWasmStructRef, WASM_LOCAL_GET(0),
WASM_BR_ON_CAST_FAIL(0, type0),
WASM_GC_OP(kExprStructGet), type0, 0, kExprReturn),
kExprBrOnNull, 0, WASM_GC_OP(kExprRefCast), type1,
@ -1559,7 +1560,7 @@ WASM_COMPILED_EXEC_TEST(CallAbstractNullTypeImplicitConversion) {
{kWasmFuncRef, kNoFuncCode},
{kWasmEqRef, kNoneCode},
{kWasmI31Ref.AsNullable(), kNoneCode},
{kWasmDataRef.AsNullable(), kNoneCode},
{kWasmStructRef.AsNullable(), kNoneCode},
{kWasmArrayRef.AsNullable(), kNoneCode},
{kWasmAnyRef, kNoneCode},
{kWasmExternRef, kNoExternCode},
@ -1602,14 +1603,15 @@ WASM_COMPILED_EXEC_TEST(CastNullRef) {
tester.sigs.i_v(), {},
{WASM_REF_IS_NULL(WASM_REF_AS_ARRAY(WASM_REF_NULL(kNoneCode))),
kExprEnd});
byte to_data = tester.DefineFunction(
byte to_struct = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_IS_NULL(WASM_REF_AS_DATA(WASM_REF_NULL(kNoneCode))), kExprEnd});
{WASM_REF_IS_NULL(WASM_REF_AS_STRUCT(WASM_REF_NULL(kNoneCode))),
kExprEnd});
byte to_i31 = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_IS_NULL(WASM_REF_AS_I31(WASM_REF_NULL(kNoneCode))), kExprEnd});
byte struct_idx = tester.DefineStruct({F(wasm::kWasmI32, true)});
byte to_struct = tester.DefineFunction(
byte to_struct_idx = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_IS_NULL(WASM_REF_CAST(WASM_REF_NULL(kNoneCode), struct_idx)),
kExprEnd});
@ -1617,10 +1619,10 @@ WASM_COMPILED_EXEC_TEST(CastNullRef) {
// Generic casts trap on null.
tester.CheckHasThrown(to_non_null);
tester.CheckHasThrown(to_array);
tester.CheckHasThrown(to_data);
tester.CheckHasThrown(to_struct);
tester.CheckHasThrown(to_i31);
// Static ref.cast succeeds.
tester.CheckResult(to_struct, 1);
tester.CheckResult(to_struct_idx, 1);
}
WASM_COMPILED_EXEC_TEST(CallReftypeParameters) {
@ -1673,9 +1675,9 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
tester.AddGlobal(ValueType::RefNull(sig_index), false,
WasmInitExpr::RefFuncConst(function_index));
byte kDataCheckNull = tester.DefineFunction(
byte kStructCheckNull = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_IS_DATA(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
{WASM_REF_IS_STRUCT(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
byte kArrayCheckNull = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_REF_IS_ARRAY(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
@ -1683,9 +1685,9 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
tester.sigs.i_v(), {},
{WASM_REF_IS_I31(WASM_REF_NULL(kAnyRefCode)), kExprEnd});
byte kDataCastNull =
byte kStructCastNull =
tester.DefineFunction(tester.sigs.i_v(), {},
{WASM_REF_AS_DATA(WASM_REF_NULL(kAnyRefCode)),
{WASM_REF_AS_STRUCT(WASM_REF_NULL(kAnyRefCode)),
WASM_DROP, WASM_I32V(1), kExprEnd});
byte kArrayCastNull =
tester.DefineFunction(tester.sigs.i_v(), {},
@ -1701,9 +1703,9 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
{WASM_LOCAL_SET(0, WASM_SEQ(value)), \
WASM_REF_IS_##type(WASM_LOCAL_GET(0)), kExprEnd})
byte kDataCheckSuccess =
TYPE_CHECK(DATA, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kDataCheckFailure = TYPE_CHECK(DATA, WASM_I31_NEW(WASM_I32V(42)));
byte kStructCheckSuccess =
TYPE_CHECK(STRUCT, WASM_STRUCT_NEW_DEFAULT(struct_index));
byte kStructCheckFailure = TYPE_CHECK(STRUCT, WASM_I31_NEW(WASM_I32V(42)));
byte kArrayCheckSuccess =
TYPE_CHECK(ARRAY, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kArrayCheckFailure =
@ -1719,12 +1721,12 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
WASM_REF_AS_##type(WASM_LOCAL_GET(0)), WASM_DROP, \
WASM_I32V(1), kExprEnd})
byte kDataCastSuccess =
TYPE_CAST(DATA, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kDataCastFailure = TYPE_CAST(DATA, WASM_I31_NEW(WASM_I32V(42)));
byte kStructCastSuccess =
TYPE_CAST(STRUCT, WASM_STRUCT_NEW_DEFAULT(struct_index));
byte kStructCastFailure = TYPE_CAST(STRUCT, WASM_I31_NEW(WASM_I32V(42)));
byte kArrayCastSuccess =
TYPE_CAST(DATA, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kArrayCastFailure = TYPE_CAST(DATA, WASM_I31_NEW(WASM_I32V(42)));
TYPE_CAST(ARRAY, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kArrayCastFailure = TYPE_CAST(ARRAY, WASM_I31_NEW(WASM_I32V(42)));
byte kI31CastSuccess = TYPE_CAST(I31, WASM_I31_NEW(WASM_I32V(42)));
byte kI31CastFailure =
TYPE_CAST(I31, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
@ -1741,9 +1743,9 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
WASM_RETURN(WASM_I32V(0)))), \
kExprEnd})
byte kBrOnDataTaken =
BR_ON(DATA, Data, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kBrOnDataNotTaken = BR_ON(DATA, Data, WASM_REF_NULL(kNoneCode));
byte kBrOnStructTaken =
BR_ON(STRUCT, Struct, WASM_STRUCT_NEW_DEFAULT(struct_index));
byte kBrOnStructNotTaken = BR_ON(STRUCT, Struct, WASM_REF_NULL(kNoneCode));
byte kBrOnArrayTaken =
BR_ON(ARRAY, Array, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kBrOnArrayNotTaken = BR_ON(ARRAY, Array, WASM_I31_NEW(WASM_I32V(42)));
@ -1763,9 +1765,10 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
WASM_RETURN(WASM_I32V(1)))), \
kExprEnd})
byte kBrOnNonDataNotTaken =
BR_ON_NON(DATA, Data, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kBrOnNonDataTaken = BR_ON_NON(DATA, Data, WASM_REF_NULL(kNoneCode));
byte kBrOnNonStructNotTaken =
BR_ON_NON(STRUCT, Struct, WASM_STRUCT_NEW_DEFAULT(struct_index));
byte kBrOnNonStructTaken =
BR_ON_NON(STRUCT, Struct, WASM_REF_NULL(kNoneCode));
byte kBrOnNonArrayNotTaken = BR_ON_NON(
ARRAY, Array, WASM_ARRAY_NEW_DEFAULT(array_index, WASM_I32V(10)));
byte kBrOnNonArrayTaken =
@ -1777,39 +1780,39 @@ WASM_COMPILED_EXEC_TEST(AbstractTypeChecks) {
tester.CompileModule();
tester.CheckResult(kDataCheckNull, 0);
tester.CheckResult(kStructCheckNull, 0);
tester.CheckResult(kArrayCheckNull, 0);
tester.CheckResult(kI31CheckNull, 0);
tester.CheckHasThrown(kDataCastNull);
tester.CheckHasThrown(kStructCastNull);
tester.CheckHasThrown(kArrayCastNull);
tester.CheckHasThrown(kI31CastNull);
tester.CheckResult(kDataCheckSuccess, 1);
tester.CheckResult(kStructCheckSuccess, 1);
tester.CheckResult(kArrayCheckSuccess, 1);
tester.CheckResult(kI31CheckSuccess, 1);
tester.CheckResult(kDataCheckFailure, 0);
tester.CheckResult(kStructCheckFailure, 0);
tester.CheckResult(kArrayCheckFailure, 0);
tester.CheckResult(kI31CheckFailure, 0);
tester.CheckResult(kDataCastSuccess, 1);
tester.CheckResult(kStructCastSuccess, 1);
tester.CheckResult(kArrayCastSuccess, 1);
tester.CheckResult(kI31CastSuccess, 1);
tester.CheckHasThrown(kDataCastFailure);
tester.CheckHasThrown(kStructCastFailure);
tester.CheckHasThrown(kArrayCastFailure);
tester.CheckHasThrown(kI31CastFailure);
tester.CheckResult(kBrOnDataTaken, 1);
tester.CheckResult(kBrOnDataNotTaken, 0);
tester.CheckResult(kBrOnStructTaken, 1);
tester.CheckResult(kBrOnStructNotTaken, 0);
tester.CheckResult(kBrOnArrayTaken, 1);
tester.CheckResult(kBrOnArrayNotTaken, 0);
tester.CheckResult(kBrOnI31Taken, 1);
tester.CheckResult(kBrOnI31NotTaken, 0);
tester.CheckResult(kBrOnNonDataTaken, 0);
tester.CheckResult(kBrOnNonDataNotTaken, 1);
tester.CheckResult(kBrOnNonStructTaken, 0);
tester.CheckResult(kBrOnNonStructNotTaken, 1);
tester.CheckResult(kBrOnNonArrayTaken, 0);
tester.CheckResult(kBrOnNonArrayNotTaken, 1);
tester.CheckResult(kBrOnNonI31Taken, 0);
@ -1824,7 +1827,7 @@ WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
const byte SubType = tester.DefineStruct(
{F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)}, SuperType);
const byte ListType = tester.DefineArray(kWasmDataRef, true);
const byte ListType = tester.DefineArray(kWasmStructRef, true);
const byte List =
tester.AddGlobal(ValueType::RefNull(ListType), true,
@ -2014,9 +2017,9 @@ WASM_COMPILED_EXEC_TEST(JsAccess) {
WasmGCTester tester(execution_tier);
const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
ValueType kRefType = ref(type_index);
ValueType kSupertypeToI[] = {kWasmI32, kWasmDataRef};
ValueType kSupertypeToI[] = {kWasmI32, kWasmStructRef};
FunctionSig sig_t_v(1, 0, &kRefType);
FunctionSig sig_super_v(1, 0, &kWasmDataRef);
FunctionSig sig_super_v(1, 0, &kWasmStructRef);
FunctionSig sig_i_super(1, 1, kSupertypeToI);
tester.DefineExportedFunction(

View File

@ -539,21 +539,21 @@ inline uint16_t ExtractPrefixedOpcodeBytes(WasmOpcode opcode) {
#define WASM_GC_INTERNALIZE(extern) extern, WASM_GC_OP(kExprExternInternalize)
#define WASM_GC_EXTERNALIZE(ref) ref, WASM_GC_OP(kExprExternExternalize)
#define WASM_REF_IS_DATA(ref) ref, WASM_GC_OP(kExprRefIsData)
#define WASM_REF_IS_STRUCT(ref) ref, WASM_GC_OP(kExprRefIsStruct)
#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_DATA(ref) ref, WASM_GC_OP(kExprRefAsData)
#define WASM_REF_AS_STRUCT(ref) ref, WASM_GC_OP(kExprRefAsStruct)
#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_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_STRUCT(depth) \
WASM_GC_OP(kExprBrOnStruct), static_cast<byte>(depth)
#define WASM_BR_ON_I31(depth) WASM_GC_OP(kExprBrOnI31), 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_STRUCT(depth) \
WASM_GC_OP(kExprBrOnNonStruct), static_cast<byte>(depth)
#define WASM_BR_ON_NON_I31(depth) \
WASM_GC_OP(kExprBrOnNonI31), static_cast<byte>(depth)

View File

@ -131,7 +131,7 @@ ValueType GetValueTypeHelper(DataRange* data, bool liftoff_as_reference,
kWasmNullExternRef, kWasmNullFuncRef});
}
if (include_generics == kIncludeGenerics) {
types.insert(types.end(), {kWasmDataRef, kWasmAnyRef, kWasmEqRef});
types.insert(types.end(), {kWasmStructRef, kWasmAnyRef, kWasmEqRef});
}
// The last index of user-defined types allowed is different based on the
@ -2111,8 +2111,10 @@ void WasmGenerator::GenerateRef(HeapType type, DataRange* data,
}
random = data->get<uint8_t>() % (num_data_types + emit_i31ref);
}
if (random < num_data_types) {
GenerateRef(HeapType(HeapType::kData), data, nullability);
if (random < num_structs_) {
GenerateRef(HeapType(HeapType::kStruct), data, nullability);
} else if (random < num_data_types) {
GenerateRef(HeapType(HeapType::kArray), data, nullability);
} else {
GenerateRef(HeapType(HeapType::kI31), data, nullability);
}
@ -2132,18 +2134,18 @@ void WasmGenerator::GenerateRef(HeapType type, DataRange* data,
GenerateRef(HeapType(random), data, nullability);
return;
}
case HeapType::kData: {
case HeapType::kStruct: {
DCHECK(liftoff_as_reference_);
constexpr uint8_t fallback_to_dataref = 2;
uint8_t random = data->get<uint8_t>() %
(num_arrays_ + num_structs_ + fallback_to_dataref);
uint8_t random =
data->get<uint8_t>() % (num_structs_ + fallback_to_dataref);
// Try generating one of the alternatives
// and continue to the rest of the methods in case it fails.
if (random >= num_arrays_ + num_structs_) {
if (random >= num_structs_) {
if (GenerateOneOf(alternatives_other, type, data, nullability)) {
return;
}
random = data->get<uint8_t>() % (num_arrays_ + num_structs_);
random = data->get<uint8_t>() % num_structs_;
}
GenerateRef(HeapType(random), data, nullability);
return;
@ -2384,7 +2386,7 @@ WasmInitExpr GenerateInitExpr(Zone* zone, WasmModuleBuilder* builder,
}
case kRef: {
switch (type.heap_type().representation()) {
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kAny:
case HeapType::kEq: {
// We materialize all these types with a struct because they are all

View File

@ -231,8 +231,8 @@ std::string HeapTypeToJSByteEncoding(HeapType heap_type) {
return "kEqRefCode";
case HeapType::kI31:
return "kI31RefCode";
case HeapType::kData:
return "kDataRefCode";
case HeapType::kStruct:
return "kStructRefCode";
case HeapType::kArray:
return "kArrayRefCode";
case HeapType::kAny:
@ -260,8 +260,8 @@ std::string HeapTypeToConstantName(HeapType heap_type) {
return "kWasmEqRef";
case HeapType::kI31:
return "kWasmI31Ref";
case HeapType::kData:
return "kWasmDataRef";
case HeapType::kStruct:
return "kWasmStructRef";
case HeapType::kArray:
return "kWasmArrayRef";
case HeapType::kExtern:
@ -309,7 +309,7 @@ std::string ValueTypeToConstantName(ValueType type) {
return "kWasmAnyRef";
case HeapType::kBottom:
UNREACHABLE();
case HeapType::kData:
case HeapType::kStruct:
case HeapType::kArray:
case HeapType::kI31:
default:

View File

@ -9,12 +9,12 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
var sig_index = builder.addType({params: [kWasmDataRef], results: [kWasmI32]});
var sig_index = builder.addType({params: [kWasmStructRef], results: [kWasmI32]});
var sub1 = builder.addStruct([makeField(kWasmI32, true)]);
var sub2 = builder.addStruct([makeField(kWasmI32, false)]);
builder.addFunction('producer', makeSig([], [kWasmDataRef]))
builder.addFunction('producer', makeSig([], [kWasmStructRef]))
.addBody([
kExprI32Const, 10,
kGCPrefix, kExprStructNew, sub1])

View File

@ -10,7 +10,7 @@ let builder = new WasmModuleBuilder();
builder.addFunction('repro', kSig_v_v)
.exportFunc()
.addLocals(wasmRefNullType(kWasmDataRef), 1)
.addLocals(wasmRefNullType(kWasmStructRef), 1)
.addBody([
kExprI32Const, 0,
kExprIf, kWasmVoid,

View File

@ -9,7 +9,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
var sig_index = builder.addType(
{params: [wasmRefType(kWasmDataRef)], results: []});
{params: [wasmRefType(kWasmStructRef)], results: []});
builder.addFunction('main', sig_index).addBody([]).exportFunc();

View File

@ -123,7 +123,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
.addBody([
kExprLocalGet, 0, // offset in table
kExprTableGet, table,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type_index,
kExprLocalGet, 1, // index in the array
kGCPrefix, kExprArrayGet, array_type_index,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc
// Flags: --experimental-wasm-gc --no-wasm-gc-structref-as-dataref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
@ -43,7 +43,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
["Array", array],
["I31", kI31RefCode],
["AnyArray", kArrayRefCode],
["Data", kDataRefCode],
["Struct", kStructRefCode],
["Eq", kEqRefCode],
// 'ref.test any' is semantically the same as '!ref.is_null' here.
["Any", kAnyRefCode],
@ -108,14 +108,14 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals([0, 0], wasm.refTestAnyArray(1));
assertEquals([0, 0], wasm.refTestAnyArray({'JavaScript': 'Object'}));
assertEquals([0, 1], wasm.refTestData(null));
assertEquals([0, 0], wasm.refTestData(undefined));
assertEquals([1, 1], wasm.refTestData(wasm.createStructSuper()));
assertEquals([1, 1], wasm.refTestData(wasm.createStructSub()));
assertEquals([1, 1], wasm.refTestData(wasm.createArray()));
assertEquals([0, 0], wasm.refTestData(wasm.createFuncRef()));
assertEquals([0, 0], wasm.refTestData(1));
assertEquals([0, 0], wasm.refTestData({'JavaScript': 'Object'}));
assertEquals([0, 1], wasm.refTestStruct(null));
assertEquals([0, 0], wasm.refTestStruct(undefined));
assertEquals([1, 1], wasm.refTestStruct(wasm.createStructSuper()));
assertEquals([1, 1], wasm.refTestStruct(wasm.createStructSub()));
assertEquals([0, 0], wasm.refTestStruct(wasm.createArray()));
assertEquals([0, 0], wasm.refTestStruct(wasm.createFuncRef()));
assertEquals([0, 0], wasm.refTestStruct(1));
assertEquals([0, 0], wasm.refTestStruct({'JavaScript': 'Object'}));
assertEquals([0, 1], wasm.refTestEq(null));
assertEquals([0, 0], wasm.refTestEq(undefined));

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc --experimental-wasm-type-reflection
// Flags: --experimental-wasm-gc --experimental-wasm-type-reflection --no-wasm-gc-structref-as-dataref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
@ -110,7 +110,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
let types = {
any: kWasmAnyRef,
eq: kWasmEqRef,
data: kWasmDataRef,
struct: kWasmStructRef,
anyArray: kWasmArrayRef,
array: wasmRefNullType(array),
structSuper: wasmRefNullType(structSuper),
@ -137,7 +137,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
values: ['nullref', 'i31ref', 'structSuper', 'structSub', 'array'],
targets: {
eq: ['i31ref', 'structSuper', 'structSub', 'array'],
data: ['structSuper', 'structSub', 'array'],
struct: ['structSuper', 'structSub'],
anyArray: ['array'],
array: ['array'],
structSuper: ['structSuper', 'structSub'],
@ -149,7 +149,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
values: ['nullref', 'i31ref', 'structSuper', 'structSub', 'array'],
targets: {
eq: ['i31ref', 'structSuper', 'structSub', 'array'],
data: ['structSuper', 'structSub', 'array'],
struct: ['structSuper', 'structSub'],
anyArray: ['array'],
array: ['array'],
structSuper: ['structSuper', 'structSub'],
@ -157,11 +157,11 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
}
},
{
source: 'data',
values: ['nullref', 'structSuper', 'structSub', 'array'],
source: 'struct',
values: ['nullref', 'structSuper', 'structSub'],
targets: {
eq: ['structSuper', 'structSub', 'array'],
data: ['structSuper', 'structSub', 'array'],
eq: ['structSuper', 'structSub'],
struct: ['structSuper', 'structSub'],
anyArray: ['array'],
array: ['array'],
structSuper: ['structSuper', 'structSub'],
@ -173,7 +173,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
values: ['nullref', 'array'],
targets: {
eq: ['array'],
data: ['array'],
struct: [],
anyArray: ['array'],
array: ['array'],
structSuper: [],
@ -185,7 +185,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
values: ['nullref', 'structSuper', 'structSub'],
targets: {
eq: ['structSuper', 'structSub'],
data: ['structSuper', 'structSub'],
struct: ['structSuper', 'structSub'],
anyArray: [],
array: [],
structSuper: ['structSuper', 'structSub'],

View File

@ -20,7 +20,7 @@ builder.addFunction('getHelloArray', makeSig([], [kWasmArrayRef]))
builder.addFunction('getChar', makeSig([kWasmArrayRef, kWasmI32], [kWasmI32]))
.addBody([
kExprLocalGet, 0, kGCPrefix, kExprRefAsData, kGCPrefix,
kExprLocalGet, 0, kGCPrefix, kExprRefAsArray, kGCPrefix,
kExprRefCast, i16Array, kExprLocalGet, 1, kGCPrefix, kExprArrayGetS,
i16Array
])

View File

@ -11,7 +11,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
let struct = builder.addStruct([makeField(kWasmI32, true)]);
builder.addFunction("main", kSig_i_i)
.addLocals(wasmRefNullType(kWasmDataRef), 1)
.addLocals(wasmRefNullType(kWasmStructRef), 1)
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStructNew, struct,

View File

@ -16,7 +16,7 @@ builder.addFunction('readStruct', makeSig([kWasmExternRef], [kWasmI32]))
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprExternInternalize, // --
kGCPrefix, kExprRefAsData, // --
kGCPrefix, kExprRefAsStruct, // --
kGCPrefix, kExprRefCast, struct_type, // --
kGCPrefix, kExprStructGet, struct_type, 0, // --
]);

View File

@ -70,7 +70,7 @@ for (const wasm_obj of [struct, array]) {
testThrowsRepeated(
() => new WebAssembly.Tag({parameters: [wasm_obj]}), TypeError);
let tag = new WebAssembly.Tag({parameters: ['dataref']});
let tag = new WebAssembly.Tag({parameters: ['structref']});
testThrowsRepeated(() => new WebAssembly.Exception(wasm_obj), TypeError);
testThrowsRepeated(() => new WebAssembly.Exception(tag, wasm_obj), TypeError);
repeated(() => new WebAssembly.Exception(tag, [wasm_obj]));

View File

@ -551,7 +551,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("main", makeSig([kWasmExternRef], [kWasmI32]))
.addBody([kExprLocalGet, 0, kGCPrefix, kExprExternInternalize,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct_a,
kExprCallFunction, callee.index])
.exportFunc();

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
// Flags: --experimental-wasm-gc --experimental-wasm-stringref
// Flags: --no-wasm-gc-structref-as-dataref
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
// Test type checks when creating a global with a value imported from a global
@ -301,7 +302,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0,
])
@ -309,7 +310,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type,
kExprI32Const, 0,
kGCPrefix, kExprArrayGet, array_type,
@ -369,7 +370,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0,
])
@ -377,7 +378,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type,
kExprI32Const, 0,
kGCPrefix, kExprArrayGet, array_type,
@ -414,34 +415,25 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(() => eqref_global.value = "string", TypeError);
})();
(function TestDataRefGlobalFromJS() {
(function TestStructRefGlobalFromJS() {
print(arguments.callee.name);
let dataref_global = new WebAssembly.Global(
{ value: "dataref", mutable: true }, null);
assertNull(dataref_global.value);
let structref_global = new WebAssembly.Global(
{ value: "structref", mutable: true }, null);
assertNull(structref_global.value);
let builder = new WasmModuleBuilder();
builder.addImportedGlobal("imports", "dataref_global", kWasmDataRef, true);
builder.addImportedGlobal("imports", "structref_global", kWasmStructRef, true);
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let array_type = builder.addArray(kWasmI32);
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0,
])
.exportFunc();
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefCast, array_type,
kExprI32Const, 0,
kGCPrefix, kExprArrayGet, array_type,
])
.exportFunc();
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
.addBody([
kExprLocalGet, 0,
@ -455,18 +447,17 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kGCPrefix, kExprExternExternalize])
.exportFunc();
let instance = builder.instantiate({imports : {dataref_global}});
let instance = builder.instantiate({imports : {structref_global}});
let wasm = instance.exports;
dataref_global.value = wasm.create_struct(42);
structref_global.value = wasm.create_struct(42);
assertEquals(42, wasm.get_struct_val());
dataref_global.value = wasm.create_array(43);
assertEquals(43, wasm.get_array_val());
dataref_global.value = null;
assertEquals(null, dataref_global.value);
structref_global.value = null;
assertEquals(null, structref_global.value);
assertThrows(() => dataref_global.value = undefined, TypeError);
assertThrows(() => dataref_global.value = "string", TypeError);
assertThrows(() => structref_global.value = undefined, TypeError);
assertThrows(() => structref_global.value = "string", TypeError);
assertThrows(() => structref_global.value = wasm.create_array(1), TypeError);
})();
(function TestArrayRefGlobalFromJS() {
@ -483,7 +474,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
.addBody([
kExprGlobalGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type,
kExprI32Const, 0,
kGCPrefix, kExprArrayGet, array_type,

View File

@ -162,7 +162,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kGCPrefix, kExprStructGet, composite_struct_index, 0])
.exportFunc();
builder.addFunction("field_2_default", makeSig([], [kWasmDataRef]))
builder.addFunction("field_2_default", makeSig([], [kWasmStructRef]))
.addBody([
kExprGlobalGet, global_default.index,
kGCPrefix, kExprStructGet, composite_struct_index, 1])
@ -245,7 +245,7 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
kGCPrefix, kExprStructGet, struct_index, 0])
.exportFunc();
builder.addFunction("element1", makeSig([], [kWasmDataRef]))
builder.addFunction("element1", makeSig([], [kWasmStructRef]))
.addBody([
kExprGlobalGet, global.index,
kExprI32Const, 1,

View File

@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc --experimental-wasm-stringref --wasm-gc-js-interop
// Flags: --experimental-wasm-gc --experimental-wasm-stringref
// Flags: --wasm-gc-js-interop --no-wasm-gc-structref-as-dataref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
let tableTypes = {
"anyref": kWasmAnyRef,
"eqref": kWasmEqRef,
"dataref": kWasmDataRef,
"structref": kWasmStructRef,
"arrayref": kWasmArrayRef,
};
@ -74,7 +75,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
builder.addFunction("tableGetStructVal", getValSig)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct,
kGCPrefix, kExprStructGet, struct, 0,
])
@ -82,7 +83,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
builder.addFunction("tableGetArrayVal", getValSig)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array,
kExprI32Const, 0,
kGCPrefix, kExprArrayGet, array,
@ -106,21 +107,10 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
])
.exportFunc();
let blockSig = builder.addType(makeSig([kWasmAnyRef], [kWasmEqRef]));
let castExternToEqRef = [
kGCPrefix, kExprExternInternalize,
kExprBlock, blockSig,
kGCPrefix, kExprBrOnI31, 0,
kGCPrefix, kExprBrOnData, 0,
// non-data, non-i31
kExprUnreachable, // conversion failure
kExprEnd,
];
builder.addFunction("createNull", creatorSig)
.addBody([kExprRefNull, kNullRefCode])
.exportFunc();
let i31Sig = typeName != "dataref" && typeName != "arrayref"
let i31Sig = typeName != "structref" && typeName != "arrayref"
? creatorSig : creatorAnySig;
builder.addFunction("createI31", i31Sig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprI31New])
@ -129,7 +119,8 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
builder.addFunction("createStruct", structSig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprStructNew, struct])
.exportFunc();
builder.addFunction("createArray", creatorSig)
let arraySig = typeName != "structref" ? creatorSig : creatorAnySig;
builder.addFunction("createArray", arraySig)
.addBody([
kExprI32Const, 12,
kGCPrefix, kExprArrayNewFixed, array, 1
@ -159,7 +150,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals(null, wasm.tableGet(1));
assertEquals(null, table.get(1));
// Set i31.
if (typeName != "dataref" && typeName != "arrayref") {
if (typeName != "structref" && typeName != "arrayref") {
table.set(2, wasm.exported(wasm.createI31));
assertSame(table.get(2), wasm.tableGet(2));
wasm.tableSet(3, wasm.createI31);
@ -177,13 +168,15 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertNotSame(table.get(4), table.get(5));
}
// Set array.
table.set(6, wasm.exported(wasm.createArray));
assertSame(table.get(6), wasm.tableGet(6));
assertEquals(12, wasm.tableGetArrayVal(6));
wasm.tableSet(7, wasm.createArray);
assertSame(table.get(7), wasm.tableGet(7));
assertEquals(12, wasm.tableGetArrayVal(7));
assertNotSame(table.get(6), table.get(7));
if (typeName != "structref") {
table.set(6, wasm.exported(wasm.createArray));
assertSame(table.get(6), wasm.tableGet(6));
assertEquals(12, wasm.tableGetArrayVal(6));
wasm.tableSet(7, wasm.createArray);
assertSame(table.get(7), wasm.tableGet(7));
assertEquals(12, wasm.tableGetArrayVal(7));
assertNotSame(table.get(6), table.get(7));
}
// Set stringref.
if (typeName == "anyref") {
@ -217,7 +210,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
let invalidValues = {
"anyref": [],
"eqref": [],
"dataref": ["I31"],
"structref": ["I31", "Array"],
"arrayref": ["I31", "Struct"],
};
for (let invalidType of invalidValues[typeName]) {

View File

@ -186,7 +186,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
builder.addFunction("struct_getter", kSig_i_v)
.addBody([
kExprI32Const, 2, kExprTableGet, 0,
kGCPrefix, kExprRefAsData, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprRefAsStruct, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();
@ -250,7 +250,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
builder.addFunction("struct_getter", kSig_i_i)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprRefAsData, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprRefAsStruct, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();

View File

@ -14,16 +14,16 @@ let identical_struct_index = builder.addStruct([makeField(kWasmI32, true)]);
let distinct_struct_index = builder.addStruct([makeField(kWasmI64, true)]);
let struct_init = builder.addFunction("struct_init",
makeSig([], [kWasmDataRef]))
makeSig([], [kWasmStructRef]))
.addBody([kGCPrefix, kExprStructNewDefault, struct_index])
.exportFunc();
let test_pass = builder.addFunction("test_pass",
makeSig([kWasmDataRef], [kWasmI32]))
makeSig([kWasmStructRef], [kWasmI32]))
.addBody([kExprLocalGet, 0,
kGCPrefix, kExprRefTestDeprecated, identical_struct_index])
.exportFunc();
let test_fail = builder.addFunction("test_fail",
makeSig([kWasmDataRef], [kWasmI32]))
makeSig([kWasmStructRef], [kWasmI32]))
.addBody([kExprLocalGet, 0,
kGCPrefix, kExprRefTestDeprecated, distinct_struct_index])
.exportFunc();

View File

@ -188,7 +188,7 @@ function instantiate(buffer, ffi) {
print(arguments.callee.name);
// These are all positive type indices (e.g. kI31RefCode and not kWasmI31Ref)
// and should be treated as such.
let indices = [kI31RefCode, kDataRefCode, 200, 400];
let indices = [kI31RefCode, kStructRefCode, 200, 400];
let kMaxIndex = 400;
let builder = new WasmModuleBuilder();
for (let i = 0; i <= kMaxIndex; i++) {

View File

@ -43,7 +43,7 @@ let instance = (() => {
kExprBlock, kWasmVoid,
kExprLocalGet, 0,
kExprBrOnNull, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct,
kGCPrefix, kExprStructGet, struct, 0, // value
kExprI32Const, 0, // isNull
@ -64,7 +64,7 @@ let instance = (() => {
kExprLocalGet, 0,
kGCPrefix, kExprExternInternalize,
kExprBrOnNull, 0,
kGCPrefix, kExprRefAsData,
kGCPrefix, kExprRefAsStruct,
kGCPrefix, kExprRefCast, struct,
kGCPrefix, kExprStructGet, struct, 0, // value
kExprI32Const, 0, // isNull

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc
// Flags: --experimental-wasm-gc --no-wasm-gc-structref-as-dataref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
@ -16,11 +16,11 @@ let instance = (() => {
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add])
.exportAs('inc');
builder.addFunction('struct_producer', makeSig([], [kWasmDataRef]))
builder.addFunction('struct_producer', makeSig([], [kWasmStructRef]))
.addBody([kGCPrefix, kExprStructNewDefault, struct])
.exportFunc();
builder.addFunction('array_producer', makeSig([], [kWasmDataRef]))
builder.addFunction('array_producer', makeSig([], [kWasmArrayRef]))
.addBody([
kExprI32Const, 10,
kGCPrefix, kExprArrayNewDefault, array
@ -36,12 +36,11 @@ let instance = (() => {
.exportFunc();
let test_types = {
struct: kWasmDataRef,
array: kWasmDataRef,
struct: kWasmStructRef,
array: kWasmArrayRef,
raw_struct: struct,
raw_array: array,
typed_func: sig,
data: kWasmDataRef,
eq: kWasmEqRef,
func: kWasmFuncRef,
any: kWasmAnyRef,
@ -67,15 +66,18 @@ let instance = (() => {
// Wasm-exposed null is the same as JS null.
assertEquals(instance.exports.struct_null(), null);
// We can roundtrip a struct as dataref.
instance.exports.data_id(instance.exports.struct_producer());
// We can roundtrip an array as dataref.
instance.exports.data_id(instance.exports.array_producer());
// We can roundtrip null as dataref.
instance.exports.data_id(instance.exports.data_null());
// We cannot roundtrip an i31 as dataref.
// We can roundtrip a struct as structref.
instance.exports.struct_id(instance.exports.struct_producer());
// We cannot roundtrip an array as structref.
assertThrows(
() => instance.exports.data_id(instance.exports.i31_as_eq_producer()),
() => instance.exports.struct_id(instance.exports.array_producer()),
TypeError,
'type incompatibility when transforming from/to JS');
// We can roundtrip null as structref.
instance.exports.struct_id(instance.exports.struct_null());
// We cannot roundtrip an i31 as structref.
assertThrows(
() => instance.exports.struct_id(instance.exports.i31_as_eq_producer()),
TypeError,
'type incompatibility when transforming from/to JS');
@ -86,7 +88,7 @@ instance.exports.eq_id(instance.exports.array_producer());
// We can roundtrip an i31 as eqref.
instance.exports.eq_id(instance.exports.i31_as_eq_producer());
// We can roundtrip any null as eqref.
instance.exports.eq_id(instance.exports.data_null());
instance.exports.eq_id(instance.exports.struct_null());
instance.exports.eq_id(instance.exports.eq_null());
instance.exports.eq_id(instance.exports.func_null());
// We cannot roundtrip a func as eqref.

View File

@ -125,7 +125,7 @@ let kWasmEqRef = -0x13;
let kWasmI31Ref = -0x16;
let kWasmNullExternRef = -0x17;
let kWasmNullFuncRef = -0x18;
let kWasmDataRef = -0x19;
let kWasmStructRef = -0x19;
let kWasmArrayRef = -0x1a;
let kWasmNullRef = -0x1b;
let kWasmStringRef = -0x1c;
@ -143,7 +143,7 @@ let kEqRefCode = kWasmEqRef & kLeb128Mask;
let kI31RefCode = kWasmI31Ref & kLeb128Mask;
let kNullExternRefCode = kWasmNullExternRef & kLeb128Mask;
let kNullFuncRefCode = kWasmNullFuncRef & kLeb128Mask;
let kDataRefCode = kWasmDataRef & kLeb128Mask;
let kStructRefCode = kWasmStructRef & kLeb128Mask;
let kArrayRefCode = kWasmArrayRef & kLeb128Mask;
let kNullRefCode = kWasmNullRef & kLeb128Mask;
let kStringRefCode = kWasmStringRef & kLeb128Mask;
@ -517,13 +517,13 @@ let kExprRefCastNop = 0x4c;
let kExprRefIsData = 0x51;
let kExprRefIsI31 = 0x52;
let kExprRefIsArray = 0x53;
let kExprRefAsData = 0x59;
let kExprRefAsStruct = 0x59;
let kExprRefAsI31 = 0x5a;
let kExprRefAsArray = 0x5b;
let kExprBrOnData = 0x61;
let kExprBrOnStruct = 0x61;
let kExprBrOnI31 = 0x62;
let kExprBrOnArray = 0x66;
let kExprBrOnNonData = 0x64;
let kExprBrOnNonStruct = 0x64;
let kExprBrOnNonI31 = 0x65;
let kExprBrOnNonArray = 0x67;
let kExprExternInternalize = 0x70;

View File

@ -1173,8 +1173,8 @@ TEST_F(FunctionBodyDecoderTest, UnreachableRefTypes) {
ExpectValidates(FunctionSig::Build(zone(), {struct_type}, {}),
{WASM_UNREACHABLE, WASM_GC_OP(kExprRefCast), struct_index});
ExpectValidates(FunctionSig::Build(zone(), {kWasmDataRef}, {}),
{WASM_UNREACHABLE, WASM_GC_OP(kExprRefAsData)});
ExpectValidates(FunctionSig::Build(zone(), {kWasmStructRef}, {}),
{WASM_UNREACHABLE, WASM_GC_OP(kExprRefAsStruct)});
ExpectValidates(FunctionSig::Build(zone(), {}, {struct_type_null}),
{WASM_UNREACHABLE, WASM_LOCAL_GET(0), kExprBrOnNull, 0,
@ -4311,8 +4311,8 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
std::tuple<HeapType::Representation, HeapType::Representation, bool, bool>
tests[] = {
std::make_tuple(HeapType::kData, array_heap, true, true),
std::make_tuple(HeapType::kData, super_struct_heap, true, true),
std::make_tuple(HeapType::kArray, array_heap, true, true),
std::make_tuple(HeapType::kStruct, super_struct_heap, true, true),
std::make_tuple(HeapType::kFunc, func_heap_1, true, true),
std::make_tuple(func_heap_1, func_heap_1, true, true),
std::make_tuple(func_heap_1, func_heap_2, true, true),
@ -4350,8 +4350,8 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
WASM_HEAP_TYPE(to_heap))});
} else {
std::string error_message =
"[0] expected subtype of (ref null func) or (ref null data), found "
"local.get of type " +
"[0] expected subtype of (ref null func), (ref null struct) or (ref "
"null array), found local.get of type " +
test_reps[1].name();
ExpectFailure(&test_sig,
{WASM_REF_TEST_DEPRECATED(WASM_LOCAL_GET(0),
@ -4381,8 +4381,8 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
ExpectFailure(sigs.v_v(),
{WASM_REF_TEST_DEPRECATED(WASM_I32V(1), array_heap), kExprDrop},
kAppendEnd,
"ref.test[0] expected subtype of (ref null func) or "
"(ref null data), found i32.const of type i32");
"ref.test[0] expected subtype of (ref null func), (ref null "
"struct) or (ref null array), found i32.const of type i32");
ExpectFailure(sigs.v_v(),
{WASM_REF_TEST(WASM_I32V(1), array_heap), kExprDrop},
kAppendEnd,
@ -4391,8 +4391,8 @@ TEST_F(FunctionBodyDecoderTest, RefTestCast) {
ExpectFailure(sigs.v_v(),
{WASM_REF_CAST(WASM_I32V(1), array_heap), kExprDrop},
kAppendEnd,
"ref.cast[0] expected subtype of (ref null func) or "
"(ref null data), found i32.const of type i32");
"ref.cast[0] expected subtype of (ref null func), (ref null "
"struct) or (ref null array), found i32.const of type i32");
}
TEST_F(FunctionBodyDecoderTest, BrOnCastOrCastFail) {
@ -4437,17 +4437,18 @@ TEST_F(FunctionBodyDecoderTest, BrOnCastOrCastFail) {
kAppendEnd, "type error in branch[0] (expected i32, got (ref null 0))");
// Argument type error.
ExpectFailure(FunctionSig::Build(this->zone(), {subtype}, {kWasmExternRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_CAST(0, sub_struct),
WASM_GC_OP(kExprRefCast), sub_struct},
kAppendEnd,
"br_on_cast[0] expected subtype of (ref null func) or "
"(ref null data), found local.get of type externref");
ExpectFailure(FunctionSig::Build(this->zone(), {supertype}, {kWasmExternRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_CAST_FAIL(0, sub_struct)},
kAppendEnd,
"br_on_cast_fail[0] expected subtype of (ref null func) "
"or (ref null data), found local.get of type externref");
ExpectFailure(
FunctionSig::Build(this->zone(), {subtype}, {kWasmExternRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_CAST(0, sub_struct),
WASM_GC_OP(kExprRefCast), sub_struct},
kAppendEnd,
"br_on_cast[0] expected subtype of (ref null func), (ref null struct) or "
"(ref null array), found local.get of type externref");
ExpectFailure(
FunctionSig::Build(this->zone(), {supertype}, {kWasmExternRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_CAST_FAIL(0, sub_struct)}, kAppendEnd,
"br_on_cast_fail[0] expected subtype of (ref null func), (ref null "
"struct) or (ref null array), found local.get of type externref");
}
TEST_F(FunctionBodyDecoderTest, BrOnAbstractType) {
@ -4458,11 +4459,11 @@ TEST_F(FunctionBodyDecoderTest, BrOnAbstractType) {
ValueType kNonNullableFunc = ValueType::Ref(HeapType::kFunc);
ExpectValidates(
FunctionSig::Build(this->zone(), {kWasmDataRef}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_DATA(0), WASM_GC_OP(kExprRefAsData)});
FunctionSig::Build(this->zone(), {kWasmStructRef}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_STRUCT(0), WASM_GC_OP(kExprRefAsStruct)});
ExpectValidates(
FunctionSig::Build(this->zone(), {kWasmAnyRef}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_NON_DATA(0)});
{WASM_LOCAL_GET(0), WASM_BR_ON_NON_STRUCT(0)});
ExpectValidates(
FunctionSig::Build(this->zone(), {kWasmI31Ref}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_I31(0), WASM_GC_OP(kExprRefAsI31)});
@ -4472,20 +4473,21 @@ TEST_F(FunctionBodyDecoderTest, BrOnAbstractType) {
// Wrong branch type.
ExpectFailure(FunctionSig::Build(this->zone(), {}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_DATA(0), WASM_UNREACHABLE},
{WASM_LOCAL_GET(0), WASM_BR_ON_STRUCT(0), WASM_UNREACHABLE},
kAppendEnd,
"br_on_data must target a branch of arity at least 1");
"br_on_struct must target a branch of arity at least 1");
ExpectFailure(
FunctionSig::Build(this->zone(), {kNonNullableFunc}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_NON_DATA(0)}, kAppendEnd,
{WASM_LOCAL_GET(0), WASM_BR_ON_NON_STRUCT(0)}, kAppendEnd,
"type error in branch[0] (expected (ref func), got anyref)");
// Wrong fallthrough type.
ExpectFailure(FunctionSig::Build(this->zone(), {kWasmDataRef}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_DATA(0)}, kAppendEnd,
"type error in fallthru[0] (expected dataref, got anyref)");
ExpectFailure(
FunctionSig::Build(this->zone(), {kWasmStructRef}, {kWasmAnyRef}),
{WASM_LOCAL_GET(0), WASM_BR_ON_STRUCT(0)}, kAppendEnd,
"type error in fallthru[0] (expected structref, got anyref)");
ExpectFailure(FunctionSig::Build(this->zone(), {kWasmAnyRef}, {kWasmAnyRef}),
{WASM_BLOCK_I(WASM_LOCAL_GET(0), WASM_BR_ON_NON_DATA(0))},
{WASM_BLOCK_I(WASM_LOCAL_GET(0), WASM_BR_ON_NON_STRUCT(0))},
kAppendEnd,
"type error in branch[0] (expected i32, got anyref)");

View File

@ -193,7 +193,7 @@ struct ValueTypePair {
{kAnyRefCode, kWasmAnyRef}, // --
{kEqRefCode, kWasmEqRef}, // --
{kI31RefCode, kWasmI31Ref}, // --
{kDataRefCode, kWasmDataRef}, // --
{kStructRefCode, kWasmStructRef}, // --
{kArrayRefCode, kWasmArrayRef}, // --
{kNoneCode, kWasmNullRef}, // --
{kStringRefCode, kWasmStringRef}, // --

View File

@ -64,6 +64,7 @@ void DefineSignature(WasmModule* module,
TEST_F(WasmSubtypingTest, Subtyping) {
FLAG_SCOPE(experimental_wasm_gc);
FLAG_VALUE_SCOPE(wasm_gc_structref_as_dataref, false);
v8::internal::AccountingAllocator allocator;
WasmModule module1_(std::make_unique<Zone>(&allocator, ZONE_NAME));
WasmModule module2_(std::make_unique<Zone>(&allocator, ZONE_NAME));
@ -130,7 +131,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
kWasmS128};
constexpr ValueType ref_types[] = {
kWasmFuncRef, kWasmEqRef, // --
kWasmDataRef, kWasmArrayRef, // --
kWasmStructRef, kWasmArrayRef, // --
kWasmI31Ref, kWasmAnyRef, // --
kWasmExternRef, kWasmNullExternRef, // --
kWasmNullRef, kWasmNullFuncRef, // --
@ -201,17 +202,15 @@ TEST_F(WasmSubtypingTest, Subtyping) {
ref_type == kWasmStringViewWtf8 ||
ref_type == kWasmStringViewWtf16;
SCOPED_TRACE("ref_type: " + ref_type.name());
// Concrete reference types, i31ref and dataref are subtypes of eqref,
// externref/funcref/anyref/functions are not.
// Concrete reference types, i31ref, structref and arrayref are subtypes
// of eqref, externref/funcref/anyref/functions are not.
SUBTYPE_IFF(ref_type, kWasmEqRef,
ref_type != kWasmAnyRef && !is_any_func && !is_extern &&
!is_string_view && ref_type != kWasmStringRef);
// Struct/array types are subtypes of dataref.
SUBTYPE_IFF(ref_type, kWasmDataRef,
ref_type == kWasmDataRef || ref_type == kWasmArrayRef ||
ref_type == kWasmNullRef || ref_type == ref(0) ||
ref_type == ref(2) || ref_type == refNull(0) ||
ref_type == refNull(2));
// Struct types are subtypes of structref.
SUBTYPE_IFF(ref_type, kWasmStructRef,
ref_type == kWasmStructRef || ref_type == kWasmNullRef ||
ref_type == ref(0) || ref_type == refNull(0));
// Array types are subtypes of arrayref.
SUBTYPE_IFF(ref_type, kWasmArrayRef,
ref_type == kWasmArrayRef || ref_type == ref(2) ||
@ -379,33 +378,32 @@ TEST_F(WasmSubtypingTest, Subtyping) {
}
// Abstract types vs abstract types.
UNION(kWasmEqRef, kWasmDataRef, kWasmEqRef);
UNION(kWasmEqRef, kWasmStructRef, kWasmEqRef);
UNION(kWasmEqRef, kWasmI31Ref, kWasmEqRef);
UNION(kWasmEqRef, kWasmArrayRef, kWasmEqRef);
UNION(kWasmEqRef, kWasmNullRef, kWasmEqRef);
UNION(kWasmDataRef, kWasmI31Ref, kWasmEqRef);
UNION(kWasmDataRef, kWasmArrayRef, kWasmDataRef);
UNION(kWasmDataRef, kWasmNullRef, kWasmDataRef.AsNullable());
UNION(kWasmStructRef, kWasmI31Ref, kWasmEqRef);
UNION(kWasmStructRef, kWasmArrayRef, kWasmEqRef);
UNION(kWasmStructRef, kWasmNullRef, kWasmStructRef.AsNullable());
UNION(kWasmI31Ref.AsNonNull(), kWasmArrayRef.AsNonNull(),
kWasmEqRef.AsNonNull());
UNION(kWasmI31Ref, kWasmNullRef, kWasmI31Ref.AsNullable());
UNION(kWasmArrayRef, kWasmNullRef, kWasmArrayRef.AsNullable());
UNION(kWasmDataRef.AsNonNull(), kWasmI31Ref.AsNonNull(),
UNION(kWasmStructRef.AsNonNull(), kWasmI31Ref.AsNonNull(),
kWasmEqRef.AsNonNull());
UNION(kWasmDataRef, kWasmArrayRef, kWasmDataRef);
UNION(kWasmI31Ref.AsNonNull(), kWasmArrayRef, kWasmEqRef);
UNION(kWasmAnyRef, kWasmNullRef, kWasmAnyRef);
UNION(kWasmExternRef, kWasmNullExternRef, kWasmExternRef);
UNION(kWasmFuncRef, kWasmNullFuncRef, kWasmFuncRef);
INTERSECTION(kWasmExternRef, kWasmEqRef, kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmDataRef, kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmStructRef, kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmI31Ref.AsNonNull(), kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmArrayRef, kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmNullRef, kWasmBottom);
INTERSECTION(kWasmExternRef, kWasmFuncRef, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmEqRef, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmDataRef, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmStructRef, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmI31Ref, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmArrayRef, kWasmBottom);
INTERSECTION(kWasmNullExternRef, kWasmNullRef, kWasmBottom);
@ -413,13 +411,13 @@ TEST_F(WasmSubtypingTest, Subtyping) {
INTERSECTION(kWasmNullExternRef, kWasmExternRef.AsNonNull(), kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmEqRef, kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmDataRef, kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmStructRef, kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmI31Ref.AsNonNull(), kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmArrayRef, kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmNullRef, kWasmBottom);
INTERSECTION(kWasmFuncRef, kWasmNullExternRef, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmEqRef, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmDataRef, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmStructRef, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmI31Ref, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmArrayRef, kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmNullRef, kWasmBottom);
@ -427,14 +425,14 @@ TEST_F(WasmSubtypingTest, Subtyping) {
INTERSECTION(kWasmNullFuncRef, kWasmFuncRef.AsNonNull(), kWasmBottom);
INTERSECTION(kWasmNullFuncRef, kWasmNullExternRef, kWasmBottom);
INTERSECTION(kWasmEqRef, kWasmDataRef, kWasmDataRef);
INTERSECTION(kWasmEqRef, kWasmStructRef, kWasmStructRef);
INTERSECTION(kWasmEqRef, kWasmI31Ref, kWasmI31Ref);
INTERSECTION(kWasmEqRef, kWasmArrayRef, kWasmArrayRef);
INTERSECTION(kWasmEqRef, kWasmNullRef, kWasmNullRef);
INTERSECTION(kWasmEqRef, kWasmFuncRef, kWasmBottom);
INTERSECTION(kWasmDataRef, kWasmI31Ref, kWasmNullRef);
INTERSECTION(kWasmDataRef, kWasmArrayRef, kWasmArrayRef);
INTERSECTION(kWasmDataRef, kWasmNullRef, kWasmNullRef);
INTERSECTION(kWasmStructRef, kWasmI31Ref, kWasmNullRef);
INTERSECTION(kWasmStructRef, kWasmArrayRef, kWasmNullRef);
INTERSECTION(kWasmStructRef, kWasmNullRef, kWasmNullRef);
INTERSECTION(kWasmI31Ref, kWasmArrayRef, kWasmNullRef);
INTERSECTION(kWasmI31Ref.AsNonNull(), kWasmNullRef, kWasmBottom);
INTERSECTION(kWasmArrayRef.AsNonNull(), kWasmNullRef, kWasmBottom);
@ -464,11 +462,11 @@ TEST_F(WasmSubtypingTest, Subtyping) {
INTERSECTION(kWasmEqRef, array_type, array_type);
INTERSECTION(kWasmEqRef, function_type, kWasmBottom);
UNION(kWasmDataRef, struct_type, kWasmDataRef);
UNION(kWasmDataRef, array_type, kWasmDataRef);
INTERSECTION(kWasmDataRef, struct_type, struct_type);
INTERSECTION(kWasmDataRef, array_type, array_type);
INTERSECTION(kWasmDataRef, function_type, kWasmBottom);
UNION(kWasmStructRef, struct_type, kWasmStructRef);
UNION(kWasmStructRef, array_type, kWasmEqRef);
INTERSECTION(kWasmStructRef, struct_type, struct_type);
INTERSECTION(kWasmStructRef, array_type, kWasmBottom);
INTERSECTION(kWasmStructRef, function_type, kWasmBottom);
UNION(kWasmI31Ref, struct_type, kWasmEqRef);
UNION(kWasmI31Ref, array_type, kWasmEqRef);
@ -476,7 +474,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
INTERSECTION(kWasmI31Ref, array_type, kWasmBottom);
INTERSECTION(kWasmI31Ref, function_type, kWasmBottom);
UNION(kWasmArrayRef, struct_type, kWasmDataRef);
UNION(kWasmArrayRef, struct_type, kWasmEqRef);
UNION(kWasmArrayRef, array_type, kWasmArrayRef);
INTERSECTION(kWasmArrayRef, struct_type, kWasmBottom);
INTERSECTION(kWasmArrayRef, array_type, array_type);
@ -490,7 +488,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
INTERSECTION(kWasmNullRef, function_type, kWasmBottom);
// Indexed types of different kinds.
UNION(struct_type, array_type, kWasmDataRef.AsNonNull());
UNION(struct_type, array_type, kWasmEqRef.AsNonNull());
INTERSECTION(struct_type, array_type, kWasmBottom);
INTERSECTION(struct_type, function_type, kWasmBottom);
INTERSECTION(array_type, function_type, kWasmBottom);
@ -498,8 +496,9 @@ TEST_F(WasmSubtypingTest, Subtyping) {
// Nullable vs. non-nullable.
UNION(struct_type, struct_type.AsNullable(), struct_type.AsNullable());
INTERSECTION(struct_type, struct_type.AsNullable(), struct_type);
UNION(kWasmDataRef, kWasmDataRef.AsNullable(), kWasmDataRef.AsNullable());
INTERSECTION(kWasmDataRef, kWasmDataRef.AsNullable(), kWasmDataRef);
UNION(kWasmStructRef, kWasmStructRef.AsNullable(),
kWasmStructRef.AsNullable());
INTERSECTION(kWasmStructRef, kWasmStructRef.AsNullable(), kWasmStructRef);
// Concrete types of the same kind.
// Subtyping relation.
@ -512,7 +511,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
// No common ancestor.
UNION(ref(6), refNull(2), kWasmArrayRef.AsNullable());
INTERSECTION(ref(6), refNull(2), kWasmBottom);
UNION(ref(0), ref(17), kWasmDataRef.AsNonNull());
UNION(ref(0), ref(17), kWasmStructRef.AsNonNull());
INTERSECTION(ref(0), ref(17), kWasmBottom);
UNION(ref(10), refNull(11), kWasmFuncRef);
INTERSECTION(ref(10), refNull(11), kWasmBottom);