Commit bcd8bf90 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Introduce separate constructors for ref and (ref null)

Most often, the {ValueType::Ref} constructor was called with a
constant nullability. To make things more convenient, this CL renames
{Ref} to {RefMaybeNull}, and introduces {Ref} and {RefNull}
constructors with fixed nullability.

Bug: v8:7748
Change-Id: I664ff184ca936cc752e152c3c67546d79aa24390
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3732936Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81494}
parent f6bf7cdb
......@@ -128,9 +128,8 @@ Reduction WasmGCOperatorReducer::ReduceIf(Node* node, bool condition) {
if (object_type.type.is_bottom()) return NoChange();
Node* rtt = NodeProperties::GetValueInput(condition_node, 1);
wasm::ValueType rtt_type = wasm::ValueType::Ref(
NodeProperties::GetType(rtt).AsWasm().type.ref_index(),
wasm::kNullable);
wasm::ValueType rtt_type = wasm::ValueType::RefNull(
NodeProperties::GetType(rtt).AsWasm().type.ref_index());
// TODO(manoskouk): Think about {module_} below if we have cross-module
// inlining.
......@@ -271,8 +270,7 @@ Reduction WasmGCOperatorReducer::ReduceWasmTypeCast(Node* node) {
TrapId::kTrapIllegalCast);
// TODO(manoskouk): Improve the type when we have nullref.
Node* null_node = SetType(
gasm_.Null(),
wasm::ValueType::Ref(rtt_type.type.ref_index(), wasm::kNullable));
gasm_.Null(), wasm::ValueType::RefNull(rtt_type.type.ref_index()));
ReplaceWithValue(node, null_node, gasm_.effect(), gasm_.control());
node->Kill();
return Replace(null_node);
......@@ -290,8 +288,7 @@ Reduction WasmGCOperatorReducer::ReduceWasmTypeCast(Node* node) {
// inlining.
wasm::TypeInModule new_type = wasm::Intersection(
object_type,
{wasm::ValueType::Ref(rtt_type.type.ref_index(), wasm::kNullable),
module_});
{wasm::ValueType::RefNull(rtt_type.type.ref_index()), module_});
return UpdateNodeAndAliasesTypes(node, GetState(control), node, new_type,
false);
......
......@@ -91,7 +91,7 @@ Reduction WasmTyper::Reduce(Node* node) {
NodeProperties::GetType(NodeProperties::GetValueInput(node, 1))
.AsWasm();
wasm::ValueType to_type =
wasm::ValueType::Ref(rtt_type.type.ref_index(), wasm::kNullable);
wasm::ValueType::RefNull(rtt_type.type.ref_index());
computed_type = wasm::Intersection(object_type.type, to_type,
object_type.module, rtt_type.module);
if (object_type.type.is_nullable() && computed_type.type.is_bottom()) {
......
......@@ -3394,8 +3394,8 @@ class LiftoffCompiler {
ValueType type =
index < static_cast<int>(__ num_locals())
? decoder->local_type(index)
: exception ? ValueType::Ref(HeapType::kAny, kNonNullable)
: decoder->stack_value(decoder_stack_index--)->type;
: exception ? ValueType::Ref(HeapType::kAny)
: decoder->stack_value(decoder_stack_index--)->type;
DCHECK(CheckCompatibleStackSlotTypes(slot.kind(), type.kind()));
value.type = type;
switch (slot.loc()) {
......
......@@ -92,8 +92,7 @@ void ConstantExpressionInterface::RefFunc(FullDecoder* decoder,
return;
}
if (!generate_value()) return;
ValueType type = ValueType::Ref(module_->functions[function_index].sig_index,
kNonNullable);
ValueType type = ValueType::Ref(module_->functions[function_index].sig_index);
Handle<WasmInternalFunction> internal =
WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate_, instance_,
function_index);
......@@ -131,7 +130,7 @@ void ConstantExpressionInterface::StructNewWithRtt(
WasmValue(isolate_->factory()->NewWasmStruct(
imm.struct_type, field_values.data(),
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index), kNonNullable));
ValueType::Ref(HeapType(imm.index)));
}
void ConstantExpressionInterface::StringConst(
......@@ -192,7 +191,7 @@ void ConstantExpressionInterface::StructNewDefault(
WasmValue(isolate_->factory()->NewWasmStruct(
imm.struct_type, field_values.data(),
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index), kNonNullable));
ValueType::Ref(HeapType(imm.index)));
}
void ConstantExpressionInterface::ArrayNewFixed(
......@@ -205,7 +204,7 @@ void ConstantExpressionInterface::ArrayNewFixed(
WasmValue(isolate_->factory()->NewWasmArrayFromElements(
imm.array_type, element_values,
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index), kNonNullable));
ValueType::Ref(HeapType(imm.index)));
}
void ConstantExpressionInterface::ArrayNewSegment(
......@@ -222,8 +221,7 @@ void ConstantExpressionInterface::ArrayNewSegment(
return;
}
ValueType element_type = array_imm.array_type->element_type();
ValueType result_type =
ValueType::Ref(HeapType(array_imm.index), kNonNullable);
ValueType result_type = ValueType::Ref(HeapType(array_imm.index));
if (element_type.is_numeric()) {
const WasmDataSegment& data_segment =
module_->data_segments[segment_imm.index];
......
......@@ -36,7 +36,7 @@ ValueOrError EvaluateConstantExpression(Zone* zone, ConstantExpression expr,
return WasmValue(expr.i32_value());
case ConstantExpression::kRefNull:
return WasmValue(isolate->factory()->null_value(),
ValueType::Ref(expr.repr(), kNullable));
ValueType::RefNull(expr.repr()));
case ConstantExpression::kRefFunc: {
uint32_t index = expr.index();
Handle<Object> value =
......
This diff is collapsed.
......@@ -1969,8 +1969,7 @@ class ModuleDecoderImpl : public Decoder {
}
ValueType type =
enabled_features_.has_typed_funcref()
? ValueType::Ref(module_->functions[index].sig_index,
kNonNullable)
? ValueType::Ref(module_->functions[index].sig_index)
: kWasmFuncRef;
TYPE_CHECK(type)
module_->functions[index].declared = true;
......@@ -1984,7 +1983,7 @@ class ModuleDecoderImpl : public Decoder {
this, pc() + 1, &length, module_.get(), enabled_features_);
if (V8_UNLIKELY(failed())) return {};
if (V8_LIKELY(lookahead(1 + length, kExprEnd))) {
TYPE_CHECK(ValueType::Ref(type, kNullable))
TYPE_CHECK(ValueType::RefNull(type))
consume_bytes(length + 2);
return ConstantExpression::RefNull(type.representation());
}
......@@ -2276,7 +2275,7 @@ class ModuleDecoderImpl : public Decoder {
if (failed()) return index;
DCHECK_NOT_NULL(func);
DCHECK_EQ(index, func->func_index);
ValueType entry_type = ValueType::Ref(func->sig_index, kNonNullable);
ValueType entry_type = ValueType::Ref(func->sig_index);
if (V8_UNLIKELY(!IsSubtypeOf(entry_type, expected, module_.get()))) {
errorf(initial_pc,
"Invalid type in element entry: expected %s, got %s instead.",
......
......@@ -330,14 +330,32 @@ class ValueType {
DCHECK(kind == kBottom || kind <= kI16);
return ValueType(KindField::encode(kind));
}
static constexpr ValueType Ref(uint32_t heap_type, Nullability nullability) {
static constexpr ValueType Ref(uint32_t heap_type) {
DCHECK(HeapType(heap_type).is_valid());
return ValueType(KindField::encode(kRef) |
HeapTypeField::encode(heap_type));
}
static constexpr ValueType Ref(HeapType heap_type) {
return Ref(heap_type.representation());
}
static constexpr ValueType RefNull(uint32_t heap_type) {
DCHECK(HeapType(heap_type).is_valid());
return ValueType(KindField::encode(kRefNull) |
HeapTypeField::encode(heap_type));
}
static constexpr ValueType RefNull(HeapType heap_type) {
return RefNull(heap_type.representation());
}
static constexpr ValueType RefMaybeNull(uint32_t heap_type,
Nullability nullability) {
DCHECK(HeapType(heap_type).is_valid());
return ValueType(
KindField::encode(nullability == kNullable ? kRefNull : kRef) |
HeapTypeField::encode(heap_type));
}
static constexpr ValueType Ref(HeapType heap_type, Nullability nullability) {
return Ref(heap_type.representation(), nullability);
static constexpr ValueType RefMaybeNull(HeapType heap_type,
Nullability nullability) {
return RefMaybeNull(heap_type.representation(), nullability);
}
static constexpr ValueType Rtt(uint32_t type_index) {
......@@ -391,12 +409,12 @@ class ValueType {
// If {this} is (ref null $t), returns (ref $t). Otherwise, returns {this}.
constexpr ValueType AsNonNull() const {
return is_nullable() ? Ref(heap_type(), kNonNullable) : *this;
return is_nullable() ? Ref(heap_type()) : *this;
}
// If {this} is (ref $t), returns (ref null $t). Otherwise, returns {this}.
constexpr ValueType AsNullable() const {
return is_non_nullable() ? Ref(heap_type(), kNullable) : *this;
return is_non_nullable() ? RefNull(heap_type()) : *this;
}
/***************************** Field Accessors ******************************/
......@@ -468,7 +486,7 @@ class ValueType {
case MachineRepresentation::kFloat64:
return Primitive(kF64);
case MachineRepresentation::kTaggedPointer:
return Ref(HeapType::kAny, kNullable);
return RefNull(HeapType::kAny);
case MachineRepresentation::kSimd128:
return Primitive(kS128);
default:
......@@ -650,29 +668,25 @@ constexpr ValueType kWasmI16 = ValueType::Primitive(kI16);
constexpr ValueType kWasmVoid = ValueType::Primitive(kVoid);
constexpr ValueType kWasmBottom = ValueType::Primitive(kBottom);
// Established reference-type and wasm-gc proposal shorthands.
constexpr ValueType kWasmFuncRef = ValueType::Ref(HeapType::kFunc, kNullable);
constexpr ValueType kWasmAnyRef = ValueType::Ref(HeapType::kAny, kNullable);
constexpr ValueType kWasmEqRef = ValueType::Ref(HeapType::kEq, kNullable);
constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31, kNonNullable);
constexpr ValueType kWasmDataRef =
ValueType::Ref(HeapType::kData, kNonNullable);
constexpr ValueType kWasmArrayRef =
ValueType::Ref(HeapType::kArray, kNonNullable);
constexpr ValueType kWasmStringRef =
ValueType::Ref(HeapType::kString, kNullable);
constexpr ValueType kWasmFuncRef = ValueType::RefNull(HeapType::kFunc);
constexpr ValueType kWasmAnyRef = ValueType::RefNull(HeapType::kAny);
constexpr ValueType kWasmEqRef = ValueType::RefNull(HeapType::kEq);
constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31);
constexpr ValueType kWasmDataRef = ValueType::Ref(HeapType::kData);
constexpr ValueType kWasmArrayRef = ValueType::Ref(HeapType::kArray);
constexpr ValueType kWasmStringRef = ValueType::RefNull(HeapType::kString);
constexpr ValueType kWasmStringViewWtf8 =
ValueType::Ref(HeapType::kStringViewWtf8, kNullable);
ValueType::RefNull(HeapType::kStringViewWtf8);
constexpr ValueType kWasmStringViewWtf16 =
ValueType::Ref(HeapType::kStringViewWtf16, kNullable);
ValueType::RefNull(HeapType::kStringViewWtf16);
constexpr ValueType kWasmStringViewIter =
ValueType::Ref(HeapType::kStringViewIter, kNullable);
ValueType::RefNull(HeapType::kStringViewIter);
// Constants used by the generic js-to-wasm wrapper.
constexpr int kWasmValueKindBitsMask = (1u << ValueType::kKindBits) - 1;
// This is used in wasm.tq.
constexpr ValueType kWasmAnyNonNullableRef =
ValueType::Ref(HeapType::kAny, kNonNullable);
constexpr ValueType kWasmAnyNonNullableRef = ValueType::Ref(HeapType::kAny);
#define FOREACH_WASMVALUE_CTYPES(V) \
V(kI32, int32_t) \
......
......@@ -34,23 +34,23 @@ ValueType WasmInitExpr::type(const WasmModule* module,
uint32_t heap_type = enabled_features.has_typed_funcref()
? module->functions[immediate().index].sig_index
: HeapType::kFunc;
return ValueType::Ref(heap_type, kNonNullable);
return ValueType::Ref(heap_type);
}
case kRefNullConst:
return ValueType::Ref(immediate().heap_type, kNullable);
return ValueType::RefNull(immediate().heap_type);
case kStructNewWithRtt:
case kStructNew:
case kStructNewDefaultWithRtt:
case kStructNewDefault:
case kArrayNewFixed:
case kArrayNewFixedStatic:
return ValueType::Ref(immediate().index, kNonNullable);
return ValueType::Ref(immediate().index);
case kI31New:
return kWasmI31Ref.AsNonNull();
case kRttCanon:
return ValueType::Rtt(immediate().heap_type);
case kStringConst:
return ValueType::Ref(HeapType::kString, kNonNullable);
return ValueType::Ref(HeapType::kString);
}
}
......
......@@ -2366,8 +2366,7 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
const WasmModule* exporting_module = function.instance().module();
ValueType real_type = ValueType::Ref(
exporting_module->functions[function.function_index()]
.sig_index,
kNonNullable);
.sig_index);
if (!IsSubtypeOf(real_type, expected, exporting_module, module)) {
*error_message =
"assigned exported function has to be a subtype of the "
......
......@@ -394,20 +394,21 @@ V8_EXPORT_PRIVATE TypeInModule Union(ValueType type1, ValueType type2,
HeapType heap1 = type1.heap_type();
HeapType heap2 = type2.heap_type();
if (heap1 == heap2 && module1 == module2) {
return {ValueType::Ref(heap1, nullability), module1};
return {ValueType::RefMaybeNull(heap1, nullability), module1};
}
if (heap1.is_generic()) {
return {ValueType::Ref(CommonAncestorWithGeneric(heap1, heap2, module2),
nullability),
return {ValueType::RefMaybeNull(
CommonAncestorWithGeneric(heap1, heap2, module2), nullability),
module1};
} else if (heap2.is_generic()) {
return {ValueType::Ref(CommonAncestorWithGeneric(heap2, heap1, module1),
nullability),
return {ValueType::RefMaybeNull(
CommonAncestorWithGeneric(heap2, heap1, module1), nullability),
module1};
} else {
return {ValueType::Ref(CommonAncestor(heap1.ref_index(), heap2.ref_index(),
module1, module2),
nullability),
return {ValueType::RefMaybeNull(
CommonAncestor(heap1.ref_index(), heap2.ref_index(), module1,
module2),
nullability),
module1};
}
}
......@@ -423,11 +424,13 @@ TypeInModule Intersection(ValueType type1, ValueType type2,
Nullability nullability =
type1.is_nullable() && type2.is_nullable() ? kNullable : kNonNullable;
return IsHeapSubtypeOf(type1.heap_type(), type2.heap_type(), module1, module2)
? TypeInModule{ValueType::Ref(type1.heap_type(), nullability),
? TypeInModule{ValueType::RefMaybeNull(type1.heap_type(),
nullability),
module1}
: IsHeapSubtypeOf(type2.heap_type(), type1.heap_type(), module2,
module1)
? TypeInModule{ValueType::Ref(type2.heap_type(), nullability),
? TypeInModule{ValueType::RefMaybeNull(type2.heap_type(),
nullability),
module2}
: TypeInModule{kWasmBottom, module1};
}
......
This diff is collapsed.
......@@ -437,7 +437,7 @@ TEST(Liftoff_debug_side_table_catch_all) {
LiftoffCompileEnvironment env;
TestSignatures sigs;
int ex = env.builder()->AddException(sigs.v_v());
ValueType exception_type = ValueType::Ref(HeapType::kAny, kNonNullable);
ValueType exception_type = ValueType::Ref(HeapType::kAny);
auto debug_side_table = env.GenerateDebugSideTable(
{}, {kWasmI32},
{WASM_TRY_CATCH_ALL_T(kWasmI32, WASM_STMTS(WASM_I32V(0), WASM_THROW(ex)),
......@@ -462,7 +462,7 @@ TEST(Liftoff_debug_side_table_catch_all) {
TEST(Regress1199526) {
EXPERIMENTAL_FLAG_SCOPE(eh);
LiftoffCompileEnvironment env;
ValueType exception_type = ValueType::Ref(HeapType::kAny, kNonNullable);
ValueType exception_type = ValueType::Ref(HeapType::kAny);
auto debug_side_table = env.GenerateDebugSideTable(
{}, {},
{kExprTry, kVoidCode, kExprCallFunction, 0, kExprCatchAll, kExprLoop,
......
......@@ -3673,7 +3673,7 @@ WASM_EXEC_TEST(IndirectNullTyped) {
FunctionSig sig(1, 0, &kWasmI32);
byte sig_index = r.builder().AddSignature(&sig);
r.builder().AddIndirectFunctionTable(nullptr, 1,
ValueType::Ref(sig_index, kNullable));
ValueType::RefNull(sig_index));
BUILD(r, WASM_CALL_INDIRECT(sig_index, WASM_I32V(0)));
......
......@@ -3520,7 +3520,7 @@ class WasmInterpreterInternals {
WasmFeatures::All(), &decoder, code->at(pc + 1), module());
len = 1 + imm.length;
Push(WasmValue(isolate_->factory()->null_value(),
ValueType::Ref(imm.type, kNullable)));
ValueType::RefNull(imm.type)));
break;
}
case kExprRefFunc: {
......
......@@ -144,15 +144,17 @@ ValueType GetValueTypeHelper(DataRange* data, bool liftoff_as_reference,
// Conceptually, user-defined types are added to the end of the list. Pick a
// random one among them.
uint32_t id = data->get<uint8_t>() % (types.size() + num_user_defined_types);
Nullability nullability = nullable ? kNullable : kNonNullable;
if (id >= types.size()) {
// Return user-defined type.
return ValueType::Ref(id - static_cast<uint32_t>(types.size()),
nullable ? kNullable : kNonNullable);
return ValueType::RefMaybeNull(id - static_cast<uint32_t>(types.size()),
nullability);
}
// If returning a reference type, fix its nullability according to {nullable}.
if (types[id].is_reference()) {
return ValueType::Ref(types[id].heap_type(),
nullable ? kNullable : kNonNullable);
return ValueType::RefMaybeNull(types[id].heap_type(), nullability);
}
// Otherwise, just return the picked type.
return types[id];
......@@ -934,7 +936,7 @@ class WasmGenerator {
}
bool table_get(HeapType type, DataRange* data, Nullability nullable) {
ValueType needed_type = ValueType::Ref(type, nullable);
ValueType needed_type = ValueType::RefMaybeNull(type, nullable);
int table_count = builder_->builder()->NumTables();
ZoneVector<uint32_t> table(builder_->builder()->zone());
for (int i = 0; i < table_count; i++) {
......@@ -1024,7 +1026,7 @@ class WasmGenerator {
}
}
bool array_get_ref(HeapType type, DataRange* data, Nullability nullable) {
ValueType needed_type = ValueType::Ref(type, nullable);
ValueType needed_type = ValueType::RefMaybeNull(type, nullable);
return array_get_helper(needed_type, data);
}
......@@ -1120,7 +1122,7 @@ class WasmGenerator {
}
bool struct_get_ref(HeapType type, DataRange* data, Nullability nullable) {
ValueType needed_type = ValueType::Ref(type, nullable);
ValueType needed_type = ValueType::RefMaybeNull(type, nullable);
return struct_get_helper(needed_type, data);
}
......
......@@ -2210,7 +2210,7 @@ TEST_F(WasmModuleVerifyTest, TypedFunctionTable) {
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(ValueType::Ref(0, kNullable), result.value()->tables[0].type);
EXPECT_EQ(ValueType::RefNull(0), result.value()->tables[0].type);
}
TEST_F(WasmModuleVerifyTest, NullableTableIllegalInitializer) {
......@@ -2277,7 +2277,7 @@ TEST_F(WasmModuleVerifyTest, NonNullableTable) {
SECTION(Code, ENTRY_COUNT(1), NOP_BODY)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(ValueType::Ref(0, kNonNullable), result.value()->tables[0].type);
EXPECT_EQ(ValueType::Ref(0), result.value()->tables[0].type);
}
TEST_F(WasmModuleVerifyTest, NonNullableTableNoInitializer) {
......
......@@ -16,11 +16,9 @@ namespace subtyping_unittest {
class WasmSubtypingTest : public TestWithPlatform {};
using FieldInit = std::pair<ValueType, bool>;
constexpr ValueType ref(uint32_t index) {
return ValueType::Ref(index, kNonNullable);
}
constexpr ValueType ref(uint32_t index) { return ValueType::Ref(index); }
constexpr ValueType refNull(uint32_t index) {
return ValueType::Ref(index, kNullable);
return ValueType::RefNull(index);
}
FieldInit mut(ValueType type) { return FieldInit(type, true); }
......@@ -153,14 +151,12 @@ TEST_F(WasmSubtypingTest, Subtyping) {
#define NOT_VALID_SUBTYPE(type1, type2) \
EXPECT_FALSE(ValidSubtypeDefinition(type1.ref_index(), type2.ref_index(), \
module1, module));
#define IDENTICAL(index1, index2) \
EXPECT_TRUE(EquivalentTypes(ValueType::Ref(index1, kNullable), \
ValueType::Ref(index2, kNullable), module1, \
module));
#define DISTINCT(index1, index2) \
EXPECT_FALSE(EquivalentTypes(ValueType::Ref(index1, kNullable), \
ValueType::Ref(index2, kNullable), module1, \
module));
#define IDENTICAL(index1, index2) \
EXPECT_TRUE(EquivalentTypes(ValueType::RefNull(index1), \
ValueType::RefNull(index2), module1, module));
#define DISTINCT(index1, index2) \
EXPECT_FALSE(EquivalentTypes(ValueType::RefNull(index1), \
ValueType::RefNull(index2), module1, module));
// Union always expresses the result in terms of module1.
#define UNION(type1, type2, type_result) \
EXPECT_EQ(Union(type1, type2, module1, module), \
......
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