Skip to content

Commit eb23cef

Browse files
manoskoukCommit Bot
authored andcommitted
[wasm-gc] Implement ref.eq
Changes: - Implement subtyping for eqref. - (Driveby) Declare more functions as constexpr in ValueType. - Make minor changes needed to handle ref.eq. - Write an elementary test. Bug: v8:7748 Change-Id: I11d54227798ce56de70f3a6f83305b2f80b2f57f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2193715 Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#67752}
1 parent b5939c7 commit eb23cef

5 files changed

Lines changed: 72 additions & 30 deletions

File tree

src/compiler/wasm-compiler.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,8 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
660660
break;
661661
case wasm::kExprF64Mod:
662662
return BuildF64Mod(left, right);
663+
case wasm::kExprRefEq:
664+
return gasm_->TaggedEqual(left, right);
663665
case wasm::kExprI32AsmjsDivS:
664666
return BuildI32AsmjsDivS(left, right);
665667
case wasm::kExprI32AsmjsDivU:

src/wasm/function-body-decoder-impl.h

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,18 @@ struct WasmException;
4141
return true; \
4242
}())
4343

44-
#define RET_ON_PROTOTYPE_OPCODE(feat) \
44+
#define CHECK_PROTOTYPE_OPCODE_GEN(feat, opt_break) \
4545
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
4646
if (!this->enabled_.has_##feat()) { \
4747
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
48+
opt_break \
4849
} else { \
4950
this->detected_->Add(kFeature_##feat); \
5051
}
5152

52-
#define CHECK_PROTOTYPE_OPCODE(feat) \
53-
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
54-
if (!this->enabled_.has_##feat()) { \
55-
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
56-
break; \
57-
} else { \
58-
this->detected_->Add(kFeature_##feat); \
59-
}
53+
#define CHECK_PROTOTYPE_OPCODE(feat) CHECK_PROTOTYPE_OPCODE_GEN(feat, break;)
54+
55+
#define RET_ON_PROTOTYPE_OPCODE(feat) CHECK_PROTOTYPE_OPCODE_GEN(feat, )
6056

6157
#define OPCODE_ERROR(opcode, message) \
6258
(this->errorf(this->pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), \
@@ -3524,10 +3520,11 @@ class WasmFullDecoder : public WasmDecoder<validate> {
35243520
}
35253521

35263522
void BuildSimplePrototypeOperator(WasmOpcode opcode) {
3527-
if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
3523+
if (opcode == kExprRefIsNull) {
35283524
RET_ON_PROTOTYPE_OPCODE(anyref);
3525+
} else if (opcode == kExprRefEq) {
3526+
RET_ON_PROTOTYPE_OPCODE(gc);
35293527
}
3530-
// TODO(7748): Add RefEq support here.
35313528
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
35323529
BuildSimpleOperator(opcode, sig);
35333530
}
@@ -3598,6 +3595,8 @@ class EmptyInterface {
35983595
#undef TRACE_INST_FORMAT
35993596
#undef VALIDATE
36003597
#undef CHECK_PROTOTYPE_OPCODE
3598+
#undef RET_ON_PROTOTYPE_OPCODE
3599+
#undef CHECK_PROTOTYPE_OPCODE_GEN
36013600
#undef OPCODE_ERROR
36023601

36033602
} // namespace wasm

src/wasm/value-type.h

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ class Simd128;
2525
// For every two types connected by a line, the top type is a
2626
// (direct) subtype of the bottom type.
2727
//
28-
// AnyRef
29-
// / | \
28+
// AnyRef
29+
// / \
30+
// / EqRef
31+
// / / \
3032
// FuncRef ExnRef OptRef(S)
3133
// \ | / \
3234
// I32 I64 F32 F64 NullRef Ref(S)
@@ -38,7 +40,7 @@ class Simd128;
3840
// - "ref" types per https://github.com/WebAssembly/function-references
3941
// - "optref"/"eqref" per https://github.com/WebAssembly/gc
4042
//
41-
// TODO(7748): Extend this with eqref, struct and function subtyping.
43+
// TODO(7748): Extend this with struct and function subtyping.
4244
// Keep up to date with funcref vs. anyref subtyping.
4345
#define FOREACH_VALUE_TYPE(V) \
4446
V(Stmt, -1, Void, None, 'v', "<stmt>") \
@@ -71,11 +73,15 @@ class ValueType {
7173
constexpr ValueType() : bit_field_(KindField::encode(kStmt)) {}
7274
explicit constexpr ValueType(Kind kind)
7375
: bit_field_(KindField::encode(kind)) {
76+
#if V8_HAS_CXX14_CONSTEXPR
7477
DCHECK(!has_immediate());
78+
#endif
7579
}
7680
constexpr ValueType(Kind kind, uint32_t ref_index)
7781
: bit_field_(KindField::encode(kind) | RefIndexField::encode(ref_index)) {
82+
#if V8_HAS_CXX14_CONSTEXPR
7883
DCHECK(has_immediate());
84+
#endif
7985
}
8086

8187
constexpr Kind kind() const { return KindField::decode(bit_field_); }
@@ -110,27 +116,25 @@ class ValueType {
110116
return bit_field_ != other.bit_field_;
111117
}
112118

113-
// TODO(7748): Extend this with eqref, struct and function subtyping.
119+
// TODO(7748): Extend this with struct and function subtyping.
114120
// Keep up to date with funcref vs. anyref subtyping.
115-
bool IsSubTypeOf(ValueType other) const {
116-
return (*this == other) ||
117-
(kind() == kNullRef &&
118-
(other.kind() == kAnyRef || other.kind() == kFuncRef ||
119-
other.kind() == kExnRef || other.kind() == kOptRef)) ||
120-
(other.kind() == kAnyRef &&
121-
(kind() == kFuncRef || kind() == kExnRef || kind() == kOptRef ||
122-
kind() == kRef)) ||
121+
constexpr bool IsSubTypeOf(ValueType other) const {
122+
return (*this == other) || (other.kind() == kAnyRef && IsReferenceType()) ||
123+
(kind() == kNullRef && other.kind() != kRef &&
124+
other.IsReferenceType()) ||
125+
(other.kind() == kEqRef &&
126+
(kind() == kExnRef || kind() == kOptRef || kind() == kRef)) ||
123127
(kind() == kRef && other.kind() == kOptRef &&
124128
ref_index() == other.ref_index());
125129
}
126130

127-
bool IsReferenceType() const {
131+
constexpr bool IsReferenceType() const {
128132
return kind() == kAnyRef || kind() == kFuncRef || kind() == kNullRef ||
129133
kind() == kExnRef || kind() == kRef || kind() == kOptRef ||
130134
kind() == kEqRef;
131135
}
132136

133-
// TODO(7748): Extend this with eqref, struct and function subtyping.
137+
// TODO(7748): Extend this with struct and function subtyping.
134138
// Keep up to date with funcref vs. anyref subtyping.
135139
static ValueType CommonSubType(ValueType a, ValueType b) {
136140
if (a == b) return a;
@@ -143,12 +147,14 @@ class ValueType {
143147
// {a} and {b} are not each other's subtype.
144148
// If one of them is not nullable, their greatest subtype is bottom,
145149
// otherwise null.
146-
return (a.kind() == kRef || b.kind() == kRef) ? ValueType(kBottom)
147-
: ValueType(kNullRef);
150+
if (a.kind() == kRef || b.kind() == kRef) return ValueType(kBottom);
151+
return ValueType(kNullRef);
148152
}
149153

150-
ValueTypeCode value_type_code() const {
154+
constexpr ValueTypeCode value_type_code() const {
155+
#if V8_HAS_CXX14_CONSTEXPR
151156
DCHECK_NE(kBottom, kind());
157+
#endif
152158

153159
constexpr ValueTypeCode kValueTypeCode[] = {
154160
#define TYPE_CODE(kind, log2Size, code, ...) kLocal##code,
@@ -159,8 +165,10 @@ class ValueType {
159165
return kValueTypeCode[kind()];
160166
}
161167

162-
MachineType machine_type() const {
168+
constexpr MachineType machine_type() const {
169+
#if V8_HAS_CXX14_CONSTEXPR
163170
DCHECK_NE(kBottom, kind());
171+
#endif
164172

165173
constexpr MachineType kMachineType[] = {
166174
#define MACH_TYPE(kind, log2Size, code, machineType, ...) \
@@ -172,7 +180,7 @@ class ValueType {
172180
return kMachineType[kind()];
173181
}
174182

175-
MachineRepresentation machine_representation() {
183+
constexpr MachineRepresentation machine_representation() const {
176184
return machine_type().representation();
177185
}
178186

test/cctest/wasm/test-gc.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,35 @@ WASM_EXEC_TEST(BasicStruct) {
129129
kExprEnd};
130130
m->EmitCode(m_code, sizeof(m_code));
131131

132+
// Test ref.eq
133+
WasmFunctionBuilder* n = builder->AddFunction(sigs.i_v());
134+
uint32_t n_local_index = n->AddLocal(kOptRefType);
135+
n->builder()->AddExport(CStrVector("n"), n);
136+
byte n_code[] = {
137+
WASM_SET_LOCAL(n_local_index,
138+
WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_I32V(66))),
139+
WASM_I32_ADD(
140+
WASM_I32_SHL(
141+
WASM_REF_EQ( // true
142+
WASM_GET_LOCAL(n_local_index), WASM_GET_LOCAL(n_local_index)),
143+
WASM_I32V(0)),
144+
WASM_I32_ADD(
145+
WASM_I32_SHL(WASM_REF_EQ( // false
146+
WASM_GET_LOCAL(n_local_index),
147+
WASM_STRUCT_NEW(type_index, WASM_I32V(55),
148+
WASM_I32V(66))),
149+
WASM_I32V(1)),
150+
WASM_I32_ADD(
151+
WASM_I32_SHL( // false
152+
WASM_REF_EQ(WASM_GET_LOCAL(n_local_index), WASM_REF_NULL),
153+
WASM_I32V(2)),
154+
WASM_I32_SHL(WASM_REF_EQ( // true
155+
WASM_REF_NULL, WASM_REF_NULL),
156+
WASM_I32V(3))))),
157+
kExprEnd};
158+
n->EmitCode(n_code, sizeof(n_code));
159+
// Result: 0b1001
160+
132161
ZoneBuffer buffer(&zone);
133162
builder->WriteTo(&buffer);
134163

@@ -168,6 +197,9 @@ WASM_EXEC_TEST(BasicStruct) {
168197

169198
CHECK_EQ(52, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
170199
"m", 0, nullptr));
200+
201+
CHECK_EQ(0b1001, testing::CallWasmFunctionForTesting(
202+
isolate, instance, &thrower, "n", 0, nullptr));
171203
}
172204

173205
WASM_EXEC_TEST(BasicArray) {

test/common/wasm/wasm-macro-gen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
436436
#define WASM_REF_FUNC(val) kExprRefFunc, val
437437
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull
438438
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
439+
#define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
439440

440441
#define WASM_ARRAY_NEW(index, default_value, length) \
441442
default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index)

0 commit comments

Comments
 (0)