Commit 289c15eb authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][liftoff] Allow reftype results, and implement ref.null

This CL is the start to implement reference types support in Liftoff.
As a first step this CL implements the ref.null instruction, and allows
reference types as return values. This allows register allocation to be
extended to support reference types, and also adds an easy way to get a
reference type value for tests. Additionally with ref.null we don't have
to worry about garbage collection because 'null' is an immovable object
and therefore does not have to be scanned by the GC.

R=thibaudm@chromium.org

Bug: v8:7581
Change-Id: I5785dcf522c0d9881e1386f2d8b5d8560a16225c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2352784
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69556}
parent b9b25d12
...@@ -1178,6 +1178,9 @@ class LiftoffCompiler { ...@@ -1178,6 +1178,9 @@ class LiftoffCompiler {
__ emit_type_conversion(kExprI64UConvertI32, dst, c_call_dst, __ emit_type_conversion(kExprI64UConvertI32, dst, c_call_dst,
nullptr); nullptr);
}); });
case kExprRefIsNull:
unsupported(decoder, kRefTypes, "ref_is_null");
return;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1581,8 +1584,16 @@ class LiftoffCompiler { ...@@ -1581,8 +1584,16 @@ class LiftoffCompiler {
__ PushRegister(kWasmF64, reg); __ PushRegister(kWasmF64, reg);
} }
void RefNull(FullDecoder* decoder, Value* result) { void RefNull(FullDecoder* decoder, ValueType type, Value*) {
unsupported(decoder, kRefTypes, "ref_null"); Register isolate_root = __ GetUnusedRegister(kGpReg, {}).gp();
// We can re-use the isolate_root register as result register.
Register result = isolate_root;
LOAD_INSTANCE_FIELD(isolate_root, IsolateRoot, kSystemPointerSize);
__ LoadTaggedPointer(result, isolate_root, no_reg,
IsolateData::root_slot_offset(RootIndex::kNullValue),
{});
__ PushRegister(type, LiftoffRegister(result));
} }
void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) { void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) {
...@@ -3622,7 +3633,10 @@ class LiftoffCompiler { ...@@ -3622,7 +3633,10 @@ class LiftoffCompiler {
const Value args[], Value returns[], CallKind call_kind) { const Value args[], Value returns[], CallKind call_kind) {
for (ValueType ret : imm.sig->returns()) { for (ValueType ret : imm.sig->returns()) {
if (!CheckSupportedType(decoder, kSupportedTypes, ret, "return")) { if (!CheckSupportedType(decoder, kSupportedTypes, ret, "return")) {
return; // TODO(7581): Remove this once reference-types are full supported.
if (!ret.is_reference_type()) {
return;
}
} }
} }
......
...@@ -64,6 +64,9 @@ static inline constexpr RegClass reg_class_for(ValueType::Kind kind) { ...@@ -64,6 +64,9 @@ static inline constexpr RegClass reg_class_for(ValueType::Kind kind) {
return kNeedI64RegPair ? kGpRegPair : kGpReg; return kNeedI64RegPair ? kGpRegPair : kGpReg;
case ValueType::kS128: case ValueType::kS128:
return kNeedS128RegPair ? kFpRegPair : kFpReg; return kNeedS128RegPair ? kFpRegPair : kFpReg;
case ValueType::kRef:
case ValueType::kOptRef:
return kGpReg;
default: default:
return kNoReg; // unsupported type return kNoReg; // unsupported type
} }
......
...@@ -875,7 +875,7 @@ struct ControlBase { ...@@ -875,7 +875,7 @@ struct ControlBase {
F(I64Const, Value* result, int64_t value) \ F(I64Const, Value* result, int64_t value) \
F(F32Const, Value* result, float value) \ F(F32Const, Value* result, float value) \
F(F64Const, Value* result, double value) \ F(F64Const, Value* result, double value) \
F(RefNull, Value* result) \ F(RefNull, ValueType type, Value* result) \
F(RefFunc, uint32_t function_index, Value* result) \ F(RefFunc, uint32_t function_index, Value* result) \
F(RefAsNonNull, const Value& arg, Value* result) \ F(RefAsNonNull, const Value& arg, Value* result) \
F(Drop, const Value& value) \ F(Drop, const Value& value) \
...@@ -2625,8 +2625,9 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2625,8 +2625,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
CHECK_PROTOTYPE_OPCODE(reftypes); CHECK_PROTOTYPE_OPCODE(reftypes);
HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1); HeapTypeImmediate<validate> imm(this->enabled_, this, this->pc_ + 1);
if (!this->Validate(this->pc_ + 1, imm)) return 0; if (!this->Validate(this->pc_ + 1, imm)) return 0;
Value* value = Push(ValueType::Ref(imm.type, kNullable)); ValueType type = ValueType::Ref(imm.type, kNullable);
CALL_INTERFACE_IF_REACHABLE(RefNull, value); Value* value = Push(type);
CALL_INTERFACE_IF_REACHABLE(RefNull, type, value);
return 1 + imm.length; return 1 + imm.length;
} }
......
...@@ -268,7 +268,7 @@ class WasmGraphBuildingInterface { ...@@ -268,7 +268,7 @@ class WasmGraphBuildingInterface {
result->node = builder_->Simd128Constant(imm.value); result->node = builder_->Simd128Constant(imm.value);
} }
void RefNull(FullDecoder* decoder, Value* result) { void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
result->node = builder_->RefNull(); result->node = builder_->RefNull();
} }
......
...@@ -1078,6 +1078,9 @@ ...@@ -1078,6 +1078,9 @@
# Tests that depend on optimization (beyond doing assertOptimized). # Tests that depend on optimization (beyond doing assertOptimized).
'regress/regress-1049982-1': [SKIP], 'regress/regress-1049982-1': [SKIP],
'regress/regress-1049982-2': [SKIP], 'regress/regress-1049982-2': [SKIP],
# Wasm serialization relies on TurboFan to be available, hence does not work
# in the 'nooptimization' variant.
'regress/wasm/regress-7785': [SKIP],
}], # variant == nooptimization }], # variant == nooptimization
############################################################################## ##############################################################################
......
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