diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/example/type-builder-nominal.cpp | 266 | ||||
-rw-r--r-- | test/example/type-builder-nominal.txt | 92 |
2 files changed, 358 insertions, 0 deletions
diff --git a/test/example/type-builder-nominal.cpp b/test/example/type-builder-nominal.cpp new file mode 100644 index 000000000..8da80d4bb --- /dev/null +++ b/test/example/type-builder-nominal.cpp @@ -0,0 +1,266 @@ +#include <cassert> +#include <iostream> + +#include "wasm-type.h" + +using namespace wasm; + +// Construct Signature, Struct, and Array heap types using undefined types. +void test_builder() { + std::cout << ";; Test TypeBuilder\n"; + + // (type $sig (func (param (ref $struct)) (result (ref $array) i32))) + // (type $struct (struct (field (ref null $array) (mut rtt 0 $array)))) + // (type $array (array (mut externref))) + + TypeBuilder builder; + assert(builder.size() == 0); + builder.grow(3); + assert(builder.size() == 3); + + Type refSig = builder.getTempRefType(builder[0], NonNullable); + Type refStruct = builder.getTempRefType(builder[1], NonNullable); + Type refArray = builder.getTempRefType(builder[2], NonNullable); + Type refNullArray = builder.getTempRefType(builder[2], Nullable); + Type rttArray = builder.getTempRttType(Rtt(0, builder[2])); + Type refNullExt(HeapType::ext, Nullable); + + Signature sig(refStruct, builder.getTempTupleType({refArray, Type::i32})); + Struct struct_({Field(refNullArray, Immutable), Field(rttArray, Mutable)}); + Array array(Field(refNullExt, Mutable)); + + std::cout << "Before setting heap types:\n"; + std::cout << "(ref $sig) => " << refSig << "\n"; + std::cout << "(ref $struct) => " << refStruct << "\n"; + std::cout << "(ref $array) => " << refArray << "\n"; + std::cout << "(ref null $array) => " << refNullArray << "\n"; + std::cout << "(rtt 0 $array) => " << rttArray << "\n\n"; + + builder[0] = sig; + builder[1] = struct_; + builder[2] = array; + + std::cout << "After setting heap types:\n"; + std::cout << "(ref $sig) => " << refSig << "\n"; + std::cout << "(ref $struct) => " << refStruct << "\n"; + std::cout << "(ref $array) => " << refArray << "\n"; + std::cout << "(ref null $array) => " << refNullArray << "\n"; + std::cout << "(rtt 0 $array) => " << rttArray << "\n\n"; + + std::vector<HeapType> built = builder.build(); + + Type newRefSig = Type(built[0], NonNullable); + Type newRefStruct = Type(built[1], NonNullable); + Type newRefArray = Type(built[2], NonNullable); + Type newRefNullArray = Type(built[2], Nullable); + Type newRttArray = Type(Rtt(0, built[2])); + + std::cout << "After building types:\n"; + std::cout << "(ref $sig) => " << newRefSig << "\n"; + std::cout << "(ref $struct) => " << newRefStruct << "\n"; + std::cout << "(ref $array) => " << newRefArray << "\n"; + std::cout << "(ref null $array) => " << newRefNullArray << "\n"; + std::cout << "(rtt 0 $array) => " << newRttArray << "\n\n"; +} + +// Check that the builder works when there are duplicate definitions +void test_canonicalization() { + std::cout << ";; Test canonicalization\n"; + + // (type $struct (struct (field (ref null $sig) (ref null $sig)))) + // (type $sig (func)) + HeapType sig = Signature(Type::none, Type::none); + HeapType struct_ = Struct({Field(Type(sig, Nullable), Immutable), + Field(Type(sig, Nullable), Immutable)}); + + TypeBuilder builder(4); + + Type tempSigRef1 = builder.getTempRefType(builder[2], Nullable); + Type tempSigRef2 = builder.getTempRefType(builder[3], Nullable); + + assert(tempSigRef1 != tempSigRef2); + assert(tempSigRef1 != Type(sig, Nullable)); + assert(tempSigRef2 != Type(sig, Nullable)); + + builder[0] = + Struct({Field(tempSigRef1, Immutable), Field(tempSigRef1, Immutable)}); + builder[1] = + Struct({Field(tempSigRef2, Immutable), Field(tempSigRef2, Immutable)}); + builder[2] = Signature(Type::none, Type::none); + builder[3] = Signature(Type::none, Type::none); + + std::vector<HeapType> built = builder.build(); + + assert(built[0] != struct_); + assert(built[1] != struct_); + assert(built[0] != built[1]); + assert(built[2] != sig); + assert(built[3] != sig); + assert(built[2] != built[3]); +} + +// Check that signatures created with TypeBuilders are properly recorded as +// canonical. +void test_signatures(bool warm) { + std::cout << ";; Test canonical signatures\n"; + + TypeBuilder builder(2); + Type tempRef = builder.getTempRefType(builder[0], Nullable); + builder[0] = Signature(Type::anyref, Type::i31ref); + builder[1] = Signature(tempRef, tempRef); + std::vector<HeapType> built = builder.build(); + + HeapType small = HeapType(Signature(Type::anyref, Type::i31ref)); + HeapType big = + HeapType(Signature(Type(Signature(Type::anyref, Type::i31ref), Nullable), + Type(Signature(Type::anyref, Type::i31ref), Nullable))); + if (warm) { + assert(built[0] != small); + assert(built[1] != big); + } else { + assert(built[0] == small); + assert(built[1] == big); + } +} + +void test_recursive() { + std::cout << ";; Test recursive types\n"; + + { + // Trivial recursion + std::vector<HeapType> built; + { + TypeBuilder builder(1); + Type temp = builder.getTempRefType(builder[0], Nullable); + builder[0] = Signature(Type::none, temp); + built = builder.build(); + } + std::cout << built[0] << "\n\n"; + assert(built[0] == built[0].getSignature().results.getHeapType()); + assert(Type(built[0], Nullable) == built[0].getSignature().results); + } + + { + // Mutual recursion + std::vector<HeapType> built; + { + TypeBuilder builder(2); + Type temp0 = builder.getTempRefType(builder[0], Nullable); + Type temp1 = builder.getTempRefType(builder[1], Nullable); + builder[0] = Signature(Type::none, temp1); + builder[1] = Signature(Type::none, temp0); + built = builder.build(); + } + std::cout << built[0] << "\n"; + std::cout << built[1] << "\n\n"; + assert(built[0].getSignature().results.getHeapType() == built[1]); + assert(built[1].getSignature().results.getHeapType() == built[0]); + assert(built[0] != built[1]); + } + + { + // A longer chain of recursion + std::vector<HeapType> built; + { + TypeBuilder builder(5); + Type temp0 = builder.getTempRefType(builder[0], Nullable); + Type temp1 = builder.getTempRefType(builder[1], Nullable); + Type temp2 = builder.getTempRefType(builder[2], Nullable); + Type temp3 = builder.getTempRefType(builder[3], Nullable); + Type temp4 = builder.getTempRefType(builder[4], Nullable); + builder[0] = Signature(Type::none, temp1); + builder[1] = Signature(Type::none, temp2); + builder[2] = Signature(Type::none, temp3); + builder[3] = Signature(Type::none, temp4); + builder[4] = Signature(Type::none, temp0); + built = builder.build(); + } + std::cout << built[0] << "\n"; + std::cout << built[1] << "\n"; + std::cout << built[2] << "\n"; + std::cout << built[3] << "\n"; + std::cout << built[4] << "\n\n"; + assert(built[0].getSignature().results.getHeapType() == built[1]); + assert(built[1].getSignature().results.getHeapType() == built[2]); + assert(built[2].getSignature().results.getHeapType() == built[3]); + assert(built[3].getSignature().results.getHeapType() == built[4]); + assert(built[4].getSignature().results.getHeapType() == built[0]); + assert(built[0] != built[1]); + assert(built[0] != built[2]); + assert(built[0] != built[3]); + assert(built[0] != built[4]); + assert(built[1] != built[2]); + assert(built[1] != built[3]); + assert(built[1] != built[4]); + assert(built[2] != built[3]); + assert(built[2] != built[4]); + assert(built[3] != built[4]); + } + + { + // Check canonicalization for non-recursive parents and children of + // recursive HeapTypes. + std::vector<HeapType> built; + { + TypeBuilder builder(6); + Type temp0 = builder.getTempRefType(builder[0], Nullable); + Type temp1 = builder.getTempRefType(builder[1], Nullable); + Type temp2 = builder.getTempRefType(builder[2], Nullable); + Type temp3 = builder.getTempRefType(builder[3], Nullable); + Type tuple0_2 = builder.getTempTupleType({temp0, temp2}); + Type tuple1_3 = builder.getTempTupleType({temp1, temp3}); + builder[0] = Signature(Type::none, tuple0_2); + builder[1] = Signature(Type::none, tuple1_3); + builder[2] = Signature(); + builder[3] = Signature(); + builder[4] = Signature(Type::none, temp0); + builder[5] = Signature(Type::none, temp1); + built = builder.build(); + } + std::cout << built[0] << "\n"; + std::cout << built[1] << "\n"; + std::cout << built[2] << "\n"; + std::cout << built[3] << "\n"; + std::cout << built[4] << "\n"; + std::cout << built[5] << "\n\n"; + assert(built[0] != built[1]); + assert(built[2] != built[3]); + assert(built[4] != built[5]); + assert(built[4].getSignature().results.getHeapType() == built[0]); + assert(built[5].getSignature().results.getHeapType() == built[1]); + assert(built[0].getSignature().results == + Type({Type(built[0], Nullable), Type(built[2], Nullable)})); + assert(built[1].getSignature().results == + Type({Type(built[1], Nullable), Type(built[3], Nullable)})); + } + + { + // Folded and unfolded + std::vector<HeapType> built; + { + TypeBuilder builder(2); + Type temp0 = builder.getTempRefType(builder[0], Nullable); + builder[0] = Signature(Type::none, temp0); + builder[1] = Signature(Type::none, temp0); + built = builder.build(); + } + std::cout << built[0] << "\n"; + std::cout << built[1] << "\n\n"; + assert(built[0].getSignature().results.getHeapType() == built[0]); + assert(built[1].getSignature().results.getHeapType() == built[0]); + assert(built[0] != built[1]); + } +} + +int main() { + wasm::setTypeSystem(TypeSystem::Nominal); + + // Run the tests twice to ensure things still work when the global stores are + // already populated. + for (size_t i = 0; i < 2; ++i) { + test_builder(); + test_canonicalization(); + test_signatures(i == 1); + test_recursive(); + } +} diff --git a/test/example/type-builder-nominal.txt b/test/example/type-builder-nominal.txt new file mode 100644 index 000000000..fd3c4cddb --- /dev/null +++ b/test/example/type-builder-nominal.txt @@ -0,0 +1,92 @@ +;; Test TypeBuilder +Before setting heap types: +(ref $sig) => (ref [T](func)) +(ref $struct) => (ref [T](func)) +(ref $array) => (ref [T](func)) +(ref null $array) => (ref null [T](func)) +(rtt 0 $array) => (rtt 0 [T](func)) + +After setting heap types: +(ref $sig) => (ref [T](func (param (ref [T](struct (field (ref null [T](array (mut externref))) (mut (rtt 0 [T](array (mut externref)))))))) (result (ref [T](array (mut externref))) i32))) +(ref $struct) => (ref [T](struct (field (ref null [T](array (mut externref))) (mut (rtt 0 [T](array (mut externref))))))) +(ref $array) => (ref [T](array (mut externref))) +(ref null $array) => (ref null [T](array (mut externref))) +(rtt 0 $array) => (rtt 0 [T](array (mut externref))) + +After building types: +(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32))) +(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref))))))) +(ref $array) => (ref (array (mut externref))) +(ref null $array) => (ref null (array (mut externref))) +(rtt 0 $array) => (rtt 0 (array (mut externref))) + +;; Test canonicalization +;; Test canonical signatures +;; Test recursive types +(func (result (ref null ...1))) + +(func (result (ref null (func (result (ref null ...3)))))) +(func (result (ref null (func (result (ref null ...3)))))) + +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) + +(func (result (ref null ...1) (ref null (func)))) +(func (result (ref null ...1) (ref null (func)))) +(func) +(func) +(func (result (ref null (func (result ...1 (ref null (func))))))) +(func (result (ref null (func (result ...1 (ref null (func))))))) + +(func (result (ref null ...1))) +(func (result (ref null (func (result ...1))))) + +;; Test TypeBuilder +Before setting heap types: +(ref $sig) => (ref [T](func)) +(ref $struct) => (ref [T](func)) +(ref $array) => (ref [T](func)) +(ref null $array) => (ref null [T](func)) +(rtt 0 $array) => (rtt 0 [T](func)) + +After setting heap types: +(ref $sig) => (ref [T](func (param (ref [T](struct (field (ref null [T](array (mut externref))) (mut (rtt 0 [T](array (mut externref)))))))) (result (ref [T](array (mut externref))) i32))) +(ref $struct) => (ref [T](struct (field (ref null [T](array (mut externref))) (mut (rtt 0 [T](array (mut externref))))))) +(ref $array) => (ref [T](array (mut externref))) +(ref null $array) => (ref null [T](array (mut externref))) +(rtt 0 $array) => (rtt 0 [T](array (mut externref))) + +After building types: +(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32))) +(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref))))))) +(ref $array) => (ref (array (mut externref))) +(ref null $array) => (ref null (array (mut externref))) +(rtt 0 $array) => (rtt 0 (array (mut externref))) + +;; Test canonicalization +;; Test canonical signatures +;; Test recursive types +(func (result (ref null ...1))) + +(func (result (ref null (func (result (ref null ...3)))))) +(func (result (ref null (func (result (ref null ...3)))))) + +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) +(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) + +(func (result (ref null ...1) (ref null (func)))) +(func (result (ref null ...1) (ref null (func)))) +(func) +(func) +(func (result (ref null (func (result ...1 (ref null (func))))))) +(func (result (ref null (func (result ...1 (ref null (func))))))) + +(func (result (ref null ...1))) +(func (result (ref null (func (result ...1))))) + |