2020-06-05 07:27:10 +00:00
|
|
|
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/wasm/wasm-subtyping.h"
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
|
|
|
namespace subtyping_unittest {
|
|
|
|
|
2020-07-02 17:52:17 +00:00
|
|
|
class WasmSubtypingTest : public ::testing::Test {};
|
2020-06-05 07:27:10 +00:00
|
|
|
using FieldInit = std::pair<ValueType, bool>;
|
|
|
|
|
2020-07-02 11:18:47 +00:00
|
|
|
ValueType ref(uint32_t index) { return ValueType::Ref(index, kNonNullable); }
|
|
|
|
ValueType optRef(uint32_t index) { return ValueType::Ref(index, kNullable); }
|
2020-06-05 07:27:10 +00:00
|
|
|
|
|
|
|
FieldInit mut(ValueType type) { return FieldInit(type, true); }
|
|
|
|
FieldInit immut(ValueType type) { return FieldInit(type, false); }
|
|
|
|
|
|
|
|
void DefineStruct(WasmModule* module, std::initializer_list<FieldInit> fields) {
|
|
|
|
StructType::Builder builder(module->signature_zone.get(),
|
|
|
|
static_cast<uint32_t>(fields.size()));
|
|
|
|
for (FieldInit field : fields) {
|
|
|
|
builder.AddField(field.first, field.second);
|
|
|
|
}
|
|
|
|
return module->add_struct_type(builder.Build());
|
|
|
|
}
|
|
|
|
|
|
|
|
void DefineArray(WasmModule* module, FieldInit element_type) {
|
2020-07-09 11:51:58 +00:00
|
|
|
module->add_array_type(module->signature_zone->New<ArrayType>(
|
2020-06-05 07:27:10 +00:00
|
|
|
element_type.first, element_type.second));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(WasmSubtypingTest, Subtyping) {
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
2020-09-09 14:26:39 +00:00
|
|
|
WasmModule module1_(std::make_unique<Zone>(&allocator, ZONE_NAME));
|
|
|
|
WasmModule module2_(std::make_unique<Zone>(&allocator, ZONE_NAME));
|
|
|
|
|
|
|
|
WasmModule* module1 = &module1_;
|
|
|
|
WasmModule* module2 = &module2_;
|
|
|
|
|
|
|
|
// Set up two identical modules.
|
|
|
|
for (WasmModule* module : {module1, module2}) {
|
|
|
|
/* 0 */ DefineStruct(module, {mut(ref(2)), immut(optRef(2))});
|
|
|
|
/* 1 */ DefineStruct(module, {mut(ref(2)), immut(ref(2))});
|
|
|
|
/* 2 */ DefineArray(module, immut(ref(0)));
|
|
|
|
/* 3 */ DefineArray(module, immut(ref(1)));
|
|
|
|
/* 4 */ DefineStruct(module, {mut(ref(2)), immut(ref(3)), immut(kWasmF64)});
|
|
|
|
/* 5 */ DefineStruct(module, {mut(optRef(2)), immut(ref(2))});
|
|
|
|
/* 6 */ DefineArray(module, mut(kWasmI32));
|
|
|
|
/* 7 */ DefineArray(module, immut(kWasmI32));
|
|
|
|
/* 8 */ DefineStruct(module, {mut(kWasmI32), immut(optRef(8))});
|
|
|
|
/* 9 */ DefineStruct(module, {mut(kWasmI32), immut(optRef(8))});
|
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
|
2020-07-07 04:01:50 +00:00
|
|
|
ValueType numeric_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
|
|
|
|
kWasmS128};
|
2021-01-15 15:30:01 +00:00
|
|
|
ValueType ref_types[] = {kWasmExternRef, kWasmFuncRef, kWasmEqRef,
|
|
|
|
kWasmI31Ref, kWasmAnyRef, optRef(0),
|
|
|
|
ref(0), optRef(2), ref(2)};
|
2020-06-05 07:27:10 +00:00
|
|
|
|
2020-09-09 14:26:39 +00:00
|
|
|
// Type judgements across modules should work the same as within one module.
|
|
|
|
for (WasmModule* module : {module1, module2}) {
|
|
|
|
// Value types are unrelated, except if they are equal.
|
|
|
|
for (ValueType subtype : numeric_types) {
|
|
|
|
for (ValueType supertype : numeric_types) {
|
|
|
|
CHECK_EQ(IsSubtypeOf(subtype, supertype, module1, module),
|
|
|
|
subtype == supertype);
|
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 14:26:39 +00:00
|
|
|
// Value types are unrelated with reference types.
|
|
|
|
for (ValueType value_type : numeric_types) {
|
|
|
|
for (ValueType ref_type : ref_types) {
|
|
|
|
CHECK(!IsSubtypeOf(value_type, ref_type, module1, module));
|
|
|
|
CHECK(!IsSubtypeOf(ref_type, value_type, module1, module));
|
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 14:26:39 +00:00
|
|
|
for (ValueType ref_type : ref_types) {
|
|
|
|
// Concrete reference types and i31ref are subtypes of eqref,
|
2021-01-15 15:30:01 +00:00
|
|
|
// externref/funcref/anyref are not.
|
2020-09-09 14:26:39 +00:00
|
|
|
CHECK_EQ(IsSubtypeOf(ref_type, kWasmEqRef, module1, module),
|
|
|
|
ref_type != kWasmFuncRef && ref_type != kWasmExternRef &&
|
2021-01-15 15:30:01 +00:00
|
|
|
ref_type != kWasmAnyRef);
|
2020-09-09 14:26:39 +00:00
|
|
|
// Each reference type is a subtype of itself.
|
|
|
|
CHECK(IsSubtypeOf(ref_type, ref_type, module1, module));
|
2020-11-19 14:51:14 +00:00
|
|
|
// Each reference type is a subtype of anyref.
|
|
|
|
CHECK(IsSubtypeOf(ref_type, kWasmAnyRef, module1, module));
|
|
|
|
// Only anyref is a subtype of anyref.
|
|
|
|
CHECK_EQ(IsSubtypeOf(kWasmAnyRef, ref_type, module1, module),
|
|
|
|
ref_type == kWasmAnyRef);
|
2020-09-09 14:26:39 +00:00
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
|
2020-09-09 14:26:39 +00:00
|
|
|
// The rest of ref. types are unrelated.
|
2021-01-15 15:30:01 +00:00
|
|
|
for (ValueType type_1 : {kWasmExternRef, kWasmFuncRef, kWasmI31Ref}) {
|
|
|
|
for (ValueType type_2 : {kWasmExternRef, kWasmFuncRef, kWasmI31Ref}) {
|
2020-09-09 14:26:39 +00:00
|
|
|
CHECK_EQ(IsSubtypeOf(type_1, type_2, module1, module),
|
|
|
|
type_1 == type_2);
|
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 14:26:39 +00:00
|
|
|
// Unrelated refs are unrelated.
|
|
|
|
CHECK(!IsSubtypeOf(ref(0), ref(2), module1, module));
|
|
|
|
CHECK(!IsSubtypeOf(optRef(3), optRef(1), module1, module));
|
|
|
|
// ref is a subtype of optref for the same struct/array.
|
|
|
|
CHECK(IsSubtypeOf(ref(0), optRef(0), module1, module));
|
|
|
|
CHECK(IsSubtypeOf(ref(2), optRef(2), module1, module));
|
|
|
|
// optref is not a subtype of ref for the same struct/array.
|
|
|
|
CHECK(!IsSubtypeOf(optRef(0), ref(0), module1, module));
|
|
|
|
CHECK(!IsSubtypeOf(optRef(2), ref(2), module1, module));
|
|
|
|
// ref is a subtype of optref if the same is true for the underlying
|
|
|
|
// structs/arrays.
|
|
|
|
CHECK(IsSubtypeOf(ref(3), optRef(2), module1, module));
|
|
|
|
// Prefix subtyping for structs.
|
|
|
|
CHECK(IsSubtypeOf(optRef(4), optRef(0), module1, module));
|
|
|
|
// Mutable fields are invariant.
|
|
|
|
CHECK(!IsSubtypeOf(ref(0), ref(5), module1, module));
|
|
|
|
// Immutable fields are covariant.
|
|
|
|
CHECK(IsSubtypeOf(ref(1), ref(0), module1, module));
|
|
|
|
// Prefix subtyping + immutable field covariance for structs.
|
|
|
|
CHECK(IsSubtypeOf(optRef(4), optRef(1), module1, module));
|
|
|
|
// No subtyping between mutable/immutable fields.
|
|
|
|
CHECK(!IsSubtypeOf(ref(7), ref(6), module1, module));
|
|
|
|
CHECK(!IsSubtypeOf(ref(6), ref(7), module1, module));
|
|
|
|
// Recursive types.
|
|
|
|
CHECK(IsSubtypeOf(ref(9), ref(8), module1, module));
|
|
|
|
|
|
|
|
// Identical rtts are subtypes of each other.
|
|
|
|
CHECK(IsSubtypeOf(ValueType::Rtt(5, 3), ValueType::Rtt(5, 3), module1,
|
|
|
|
module2));
|
2021-01-27 15:13:43 +00:00
|
|
|
CHECK(IsSubtypeOf(ValueType::Rtt(5), ValueType::Rtt(5), module1, module2));
|
|
|
|
// Rtts of unrelated types are unrelated.
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 1), ValueType::Rtt(2, 1), module1,
|
|
|
|
module2));
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(1), ValueType::Rtt(2), module1, module2));
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 0), ValueType::Rtt(2), module1,
|
|
|
|
module2));
|
2020-09-09 14:26:39 +00:00
|
|
|
// Rtts of different depth are unrelated.
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(5, 1), ValueType::Rtt(5, 3), module1,
|
|
|
|
module2));
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(5, 8), ValueType::Rtt(5, 3), module1,
|
|
|
|
module2));
|
|
|
|
// Rtts of identical types are subtype-related.
|
|
|
|
CHECK(IsSubtypeOf(ValueType::Rtt(8, 1), ValueType::Rtt(9, 1), module1,
|
|
|
|
module));
|
2021-01-27 15:13:43 +00:00
|
|
|
CHECK(IsSubtypeOf(ValueType::Rtt(8), ValueType::Rtt(9), module1, module));
|
2020-09-09 14:26:39 +00:00
|
|
|
// Rtts of subtypes are not related.
|
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 1), ValueType::Rtt(0, 1), module1,
|
|
|
|
module));
|
2021-01-27 15:13:43 +00:00
|
|
|
CHECK(!IsSubtypeOf(ValueType::Rtt(1), ValueType::Rtt(0), module1, module));
|
|
|
|
// rtt(t, d) <: rtt(t)
|
|
|
|
for (uint8_t depth : {0, 1, 5}) {
|
|
|
|
CHECK(IsSubtypeOf(ValueType::Rtt(1, depth), ValueType::Rtt(1), module1,
|
|
|
|
module));
|
|
|
|
}
|
2020-09-09 14:26:39 +00:00
|
|
|
}
|
2020-06-05 07:27:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace subtyping_unittest
|
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|