Commit 698f8cac authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Implement cross-module subtyping

Additional changes:
- Add tests.
- Rename some subtyping functions.

Bug: v8:7748
Change-Id: I3635e93ea6bbab1942f927a8e414afc8efd31f69
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2389983
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69784}
parent 914b2317
......@@ -218,16 +218,7 @@ std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
}
WasmModule::WasmModule(std::unique_ptr<Zone> signature_zone)
: signature_zone(std::move(signature_zone)),
subtyping_cache(this->signature_zone.get() == nullptr
? nullptr
: new ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>(
this->signature_zone.get())),
type_equivalence_cache(
this->signature_zone.get() == nullptr
? nullptr
: new ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>(
this->signature_zone.get())) {}
: signature_zone(std::move(signature_zone)) {}
bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
// TODO(wasm): Once wasm has its own CSP policy, we should introduce a
......
......@@ -15,7 +15,6 @@
#include "src/wasm/struct-types.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/zone/zone-containers.h"
namespace v8 {
......@@ -334,28 +333,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
bool has_array(uint32_t index) const {
return index < types.size() && type_kinds[index] == kWasmArrayTypeCode;
}
base::RecursiveMutex* type_cache_mutex() const { return &type_cache_mutex_; }
bool is_cached_subtype(uint32_t subtype, uint32_t supertype) const {
return subtyping_cache->count(std::make_pair(subtype, supertype)) == 1;
}
void cache_subtype(uint32_t subtype, uint32_t supertype) const {
subtyping_cache->emplace(subtype, supertype);
}
void uncache_subtype(uint32_t subtype, uint32_t supertype) const {
subtyping_cache->erase(std::make_pair(subtype, supertype));
}
bool is_cached_equivalent_type(uint32_t type1, uint32_t type2) const {
if (type1 > type2) std::swap(type1, type2);
return type_equivalence_cache->count(std::make_pair(type1, type2)) == 1;
}
void cache_type_equivalence(uint32_t type1, uint32_t type2) const {
if (type1 > type2) std::swap(type1, type2);
type_equivalence_cache->emplace(type1, type2);
}
void uncache_type_equivalence(uint32_t type1, uint32_t type2) const {
if (type1 > type2) std::swap(type1, type2);
type_equivalence_cache->erase(std::make_pair(type1, type2));
}
std::vector<WasmFunction> functions;
std::vector<WasmDataSegment> data_segments;
......@@ -378,17 +355,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
private:
// Cache for discovered subtyping pairs.
std::unique_ptr<ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>>
subtyping_cache;
// Cache for discovered equivalent type pairs.
// Indexes are stored in increasing order.
std::unique_ptr<ZoneUnorderedSet<std::pair<uint32_t, uint32_t>>>
type_equivalence_cache;
// The above two caches are used from background compile jobs, so they
// must be protected from concurrent modifications:
mutable base::RecursiveMutex type_cache_mutex_;
DISALLOW_COPY_AND_ASSIGN(WasmModule);
};
......
This diff is collapsed.
......@@ -12,19 +12,32 @@ namespace internal {
namespace wasm {
struct WasmModule;
V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(ValueType subtype,
ValueType supertype,
const WasmModule* module);
V8_NOINLINE V8_EXPORT_PRIVATE bool IsSubtypeOfImpl(
ValueType subtype, ValueType supertype, const WasmModule* sub_module,
const WasmModule* super_module);
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2,
const WasmModule* module1,
const WasmModule* module2);
// The subtyping between value types is described by the following rules:
// - All types are a supertype of bottom.
// - All reference types, except funcref, are subtypes of eqref.
// - optref(ht1) <: optref(ht2) iff ht1 <: ht2.
// - ref(ht1) <: ref/optref(ht2) iff ht1 <: ht2.
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype,
const WasmModule* sub_module,
const WasmModule* super_module) {
if (subtype == supertype && sub_module == super_module) return true;
return IsSubtypeOfImpl(subtype, supertype, sub_module, super_module);
}
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype,
const WasmModule* module) {
// If the types are trivially identical, exit early.
if (V8_LIKELY(subtype == supertype)) return true;
return IsSubtypeOfImpl(subtype, supertype, module);
return IsSubtypeOfImpl(subtype, supertype, module, module);
}
ValueType CommonSubtype(ValueType a, ValueType b, const WasmModule* module);
......
......@@ -35,20 +35,25 @@ void DefineArray(WasmModule* module, FieldInit element_type) {
TEST_F(WasmSubtypingTest, Subtyping) {
v8::internal::AccountingAllocator allocator;
WasmModule module_(std::make_unique<Zone>(&allocator, ZONE_NAME));
WasmModule* module = &module_;
/* 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))});
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))});
}
ValueType numeric_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
kWasmS128};
......@@ -56,65 +61,87 @@ TEST_F(WasmSubtypingTest, Subtyping) {
kWasmEqRef, kWasmI31Ref, optRef(0),
ref(0), optRef(2), ref(2)};
// Value types are unrelated, except if they are equal.
for (ValueType subtype : numeric_types) {
for (ValueType supertype : numeric_types) {
CHECK_EQ(IsSubtypeOf(subtype, supertype, module), subtype == supertype);
// 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);
}
}
}
// 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, module));
CHECK(!IsSubtypeOf(ref_type, value_type, module));
// 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));
}
}
}
for (ValueType ref_type : ref_types) {
// Concrete reference types and i31ref are subtypes of eqref,
// exnref/externref/funcref are not.
CHECK_EQ(IsSubtypeOf(ref_type, kWasmEqRef, module),
ref_type != kWasmFuncRef && ref_type != kWasmExternRef &&
ref_type != kWasmExnRef);
// Each reference type is a subtype of itself.
CHECK(IsSubtypeOf(ref_type, ref_type, module));
}
for (ValueType ref_type : ref_types) {
// Concrete reference types and i31ref are subtypes of eqref,
// exnref/externref/funcref are not.
CHECK_EQ(IsSubtypeOf(ref_type, kWasmEqRef, module1, module),
ref_type != kWasmFuncRef && ref_type != kWasmExternRef &&
ref_type != kWasmExnRef);
// Each reference type is a subtype of itself.
CHECK(IsSubtypeOf(ref_type, ref_type, module1, module));
}
// The rest of ref. types are unrelated.
for (ValueType type_1 :
{kWasmExternRef, kWasmFuncRef, kWasmExnRef, kWasmI31Ref}) {
for (ValueType type_2 :
// The rest of ref. types are unrelated.
for (ValueType type_1 :
{kWasmExternRef, kWasmFuncRef, kWasmExnRef, kWasmI31Ref}) {
CHECK_EQ(IsSubtypeOf(type_1, type_2, module), type_1 == type_2);
for (ValueType type_2 :
{kWasmExternRef, kWasmFuncRef, kWasmExnRef, kWasmI31Ref}) {
CHECK_EQ(IsSubtypeOf(type_1, type_2, module1, module),
type_1 == type_2);
}
}
}
// Unrelated refs are unrelated.
CHECK(!IsSubtypeOf(ref(0), ref(2), module));
CHECK(!IsSubtypeOf(optRef(3), optRef(1), module));
// ref is a subtype of optref for the same struct/array.
CHECK(IsSubtypeOf(ref(0), optRef(0), module));
CHECK(IsSubtypeOf(ref(2), optRef(2), module));
// optref is not a subtype of ref for the same struct/array.
CHECK(!IsSubtypeOf(optRef(0), ref(0), module));
CHECK(!IsSubtypeOf(optRef(2), ref(2), module));
// ref is a subtype of optref if the same is true for the underlying
// structs/arrays.
CHECK(IsSubtypeOf(ref(3), optRef(2), module));
// Prefix subtyping for structs.
CHECK(IsSubtypeOf(optRef(4), optRef(0), module));
// Mutable fields are invariant.
CHECK(!IsSubtypeOf(ref(0), ref(5), module));
// Immutable fields are covariant.
CHECK(IsSubtypeOf(ref(1), ref(0), module));
// Prefix subtyping + immutable field covariance for structs.
CHECK(IsSubtypeOf(optRef(4), optRef(1), module));
// No subtyping between mutable/immutable fields.
CHECK(!IsSubtypeOf(ref(7), ref(6), module));
CHECK(!IsSubtypeOf(ref(6), ref(7), module));
// Recursive types.
CHECK(IsSubtypeOf(ref(9), ref(8), module));
// 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));
CHECK(IsSubtypeOf(ValueType::Rtt(HeapType::kExn, 3),
ValueType::Rtt(HeapType::kExn, 3), module1, module2));
// 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));
// Rtts of subtypes are not related.
CHECK(!IsSubtypeOf(ValueType::Rtt(1, 1), ValueType::Rtt(0, 1), module1,
module));
}
}
} // namespace subtyping_unittest
......
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