Commit eb23cef0 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[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: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67752}
parent b5939c75
......@@ -660,6 +660,8 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
break;
case wasm::kExprF64Mod:
return BuildF64Mod(left, right);
case wasm::kExprRefEq:
return gasm_->TaggedEqual(left, right);
case wasm::kExprI32AsmjsDivS:
return BuildI32AsmjsDivS(left, right);
case wasm::kExprI32AsmjsDivU:
......
......@@ -41,22 +41,18 @@ struct WasmException;
return true; \
}())
#define RET_ON_PROTOTYPE_OPCODE(feat) \
#define CHECK_PROTOTYPE_OPCODE_GEN(feat, opt_break) \
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
if (!this->enabled_.has_##feat()) { \
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
opt_break \
} else { \
this->detected_->Add(kFeature_##feat); \
}
#define CHECK_PROTOTYPE_OPCODE(feat) \
DCHECK(!this->module_ || this->module_->origin == kWasmOrigin); \
if (!this->enabled_.has_##feat()) { \
this->error("Invalid opcode (enable with --experimental-wasm-" #feat ")"); \
break; \
} else { \
this->detected_->Add(kFeature_##feat); \
}
#define CHECK_PROTOTYPE_OPCODE(feat) CHECK_PROTOTYPE_OPCODE_GEN(feat, break;)
#define RET_ON_PROTOTYPE_OPCODE(feat) CHECK_PROTOTYPE_OPCODE_GEN(feat, )
#define OPCODE_ERROR(opcode, message) \
(this->errorf(this->pc_, "%s: %s", WasmOpcodes::OpcodeName(opcode), \
......@@ -3524,10 +3520,11 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
void BuildSimplePrototypeOperator(WasmOpcode opcode) {
if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
if (opcode == kExprRefIsNull) {
RET_ON_PROTOTYPE_OPCODE(anyref);
} else if (opcode == kExprRefEq) {
RET_ON_PROTOTYPE_OPCODE(gc);
}
// TODO(7748): Add RefEq support here.
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
BuildSimpleOperator(opcode, sig);
}
......@@ -3598,6 +3595,8 @@ class EmptyInterface {
#undef TRACE_INST_FORMAT
#undef VALIDATE
#undef CHECK_PROTOTYPE_OPCODE
#undef RET_ON_PROTOTYPE_OPCODE
#undef CHECK_PROTOTYPE_OPCODE_GEN
#undef OPCODE_ERROR
} // namespace wasm
......
......@@ -26,7 +26,9 @@ class Simd128;
// (direct) subtype of the bottom type.
//
// AnyRef
// / | \
// / \
// / EqRef
// / / \
// FuncRef ExnRef OptRef(S)
// \ | / \
// I32 I64 F32 F64 NullRef Ref(S)
......@@ -38,7 +40,7 @@ class Simd128;
// - "ref" types per https://github.com/WebAssembly/function-references
// - "optref"/"eqref" per https://github.com/WebAssembly/gc
//
// TODO(7748): Extend this with eqref, struct and function subtyping.
// TODO(7748): Extend this with struct and function subtyping.
// Keep up to date with funcref vs. anyref subtyping.
#define FOREACH_VALUE_TYPE(V) \
V(Stmt, -1, Void, None, 'v', "<stmt>") \
......@@ -71,11 +73,15 @@ class ValueType {
constexpr ValueType() : bit_field_(KindField::encode(kStmt)) {}
explicit constexpr ValueType(Kind kind)
: bit_field_(KindField::encode(kind)) {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK(!has_immediate());
#endif
}
constexpr ValueType(Kind kind, uint32_t ref_index)
: bit_field_(KindField::encode(kind) | RefIndexField::encode(ref_index)) {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK(has_immediate());
#endif
}
constexpr Kind kind() const { return KindField::decode(bit_field_); }
......@@ -110,27 +116,25 @@ class ValueType {
return bit_field_ != other.bit_field_;
}
// TODO(7748): Extend this with eqref, struct and function subtyping.
// TODO(7748): Extend this with struct and function subtyping.
// Keep up to date with funcref vs. anyref subtyping.
bool IsSubTypeOf(ValueType other) const {
return (*this == other) ||
(kind() == kNullRef &&
(other.kind() == kAnyRef || other.kind() == kFuncRef ||
other.kind() == kExnRef || other.kind() == kOptRef)) ||
(other.kind() == kAnyRef &&
(kind() == kFuncRef || kind() == kExnRef || kind() == kOptRef ||
kind() == kRef)) ||
constexpr bool IsSubTypeOf(ValueType other) const {
return (*this == other) || (other.kind() == kAnyRef && IsReferenceType()) ||
(kind() == kNullRef && other.kind() != kRef &&
other.IsReferenceType()) ||
(other.kind() == kEqRef &&
(kind() == kExnRef || kind() == kOptRef || kind() == kRef)) ||
(kind() == kRef && other.kind() == kOptRef &&
ref_index() == other.ref_index());
}
bool IsReferenceType() const {
constexpr bool IsReferenceType() const {
return kind() == kAnyRef || kind() == kFuncRef || kind() == kNullRef ||
kind() == kExnRef || kind() == kRef || kind() == kOptRef ||
kind() == kEqRef;
}
// TODO(7748): Extend this with eqref, struct and function subtyping.
// TODO(7748): Extend this with struct and function subtyping.
// Keep up to date with funcref vs. anyref subtyping.
static ValueType CommonSubType(ValueType a, ValueType b) {
if (a == b) return a;
......@@ -143,12 +147,14 @@ class ValueType {
// {a} and {b} are not each other's subtype.
// If one of them is not nullable, their greatest subtype is bottom,
// otherwise null.
return (a.kind() == kRef || b.kind() == kRef) ? ValueType(kBottom)
: ValueType(kNullRef);
if (a.kind() == kRef || b.kind() == kRef) return ValueType(kBottom);
return ValueType(kNullRef);
}
ValueTypeCode value_type_code() const {
constexpr ValueTypeCode value_type_code() const {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK_NE(kBottom, kind());
#endif
constexpr ValueTypeCode kValueTypeCode[] = {
#define TYPE_CODE(kind, log2Size, code, ...) kLocal##code,
......@@ -159,8 +165,10 @@ class ValueType {
return kValueTypeCode[kind()];
}
MachineType machine_type() const {
constexpr MachineType machine_type() const {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK_NE(kBottom, kind());
#endif
constexpr MachineType kMachineType[] = {
#define MACH_TYPE(kind, log2Size, code, machineType, ...) \
......@@ -172,7 +180,7 @@ class ValueType {
return kMachineType[kind()];
}
MachineRepresentation machine_representation() {
constexpr MachineRepresentation machine_representation() const {
return machine_type().representation();
}
......
......@@ -129,6 +129,35 @@ WASM_EXEC_TEST(BasicStruct) {
kExprEnd};
m->EmitCode(m_code, sizeof(m_code));
// Test ref.eq
WasmFunctionBuilder* n = builder->AddFunction(sigs.i_v());
uint32_t n_local_index = n->AddLocal(kOptRefType);
n->builder()->AddExport(CStrVector("n"), n);
byte n_code[] = {
WASM_SET_LOCAL(n_local_index,
WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_I32V(66))),
WASM_I32_ADD(
WASM_I32_SHL(
WASM_REF_EQ( // true
WASM_GET_LOCAL(n_local_index), WASM_GET_LOCAL(n_local_index)),
WASM_I32V(0)),
WASM_I32_ADD(
WASM_I32_SHL(WASM_REF_EQ( // false
WASM_GET_LOCAL(n_local_index),
WASM_STRUCT_NEW(type_index, WASM_I32V(55),
WASM_I32V(66))),
WASM_I32V(1)),
WASM_I32_ADD(
WASM_I32_SHL( // false
WASM_REF_EQ(WASM_GET_LOCAL(n_local_index), WASM_REF_NULL),
WASM_I32V(2)),
WASM_I32_SHL(WASM_REF_EQ( // true
WASM_REF_NULL, WASM_REF_NULL),
WASM_I32V(3))))),
kExprEnd};
n->EmitCode(n_code, sizeof(n_code));
// Result: 0b1001
ZoneBuffer buffer(&zone);
builder->WriteTo(&buffer);
......@@ -168,6 +197,9 @@ WASM_EXEC_TEST(BasicStruct) {
CHECK_EQ(52, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"m", 0, nullptr));
CHECK_EQ(0b1001, testing::CallWasmFunctionForTesting(
isolate, instance, &thrower, "n", 0, nullptr));
}
WASM_EXEC_TEST(BasicArray) {
......
......@@ -436,6 +436,7 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_REF_FUNC(val) kExprRefFunc, val
#define WASM_REF_IS_NULL(val) val, kExprRefIsNull
#define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
#define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
#define WASM_ARRAY_NEW(index, default_value, length) \
default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment