diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/literal.cpp | 125 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 26 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 44 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 6 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 62 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 17 |
7 files changed, 191 insertions, 91 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 3f635ca19..ec8642865 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -29,37 +29,52 @@ namespace wasm { template<int N> using LaneArray = std::array<Literal, N>; +Literal::Literal(Type type) : type(type) { + assert(type != Type::unreachable && (!type.isRef() || type.isNullable())); + if (type.isException()) { + new (&exn) std::unique_ptr<ExceptionPackage>(); + } else { + memset(&v128, 0, 16); + } +} + Literal::Literal(const uint8_t init[16]) : type(Type::v128) { memcpy(&v128, init, 16); } Literal::Literal(const Literal& other) : type(other.type) { - TODO_SINGLE_COMPOUND(type); - switch (type.getBasic()) { - case Type::i32: - case Type::f32: - i32 = other.i32; - break; - case Type::i64: - case Type::f64: - i64 = other.i64; - break; - case Type::v128: - memcpy(&v128, other.v128, 16); - break; - case Type::funcref: - func = other.func; - break; - case Type::exnref: - // Avoid calling the destructor on an uninitialized value + if (type.isException()) { + // Avoid calling the destructor on an uninitialized value + if (other.exn != nullptr) { new (&exn) auto(std::make_unique<ExceptionPackage>(*other.exn)); - break; - case Type::none: - case Type::nullref: - break; - case Type::externref: - case Type::unreachable: - WASM_UNREACHABLE("unexpected type"); + } else { + new (&exn) std::unique_ptr<ExceptionPackage>(); + } + } else if (type.isFunction()) { + func = other.func; + } else { + TODO_SINGLE_COMPOUND(type); + switch (type.getBasic()) { + case Type::i32: + case Type::f32: + i32 = other.i32; + break; + case Type::i64: + case Type::f64: + i64 = other.i64; + break; + case Type::v128: + memcpy(&v128, other.v128, 16); + break; + case Type::none: + break; + case Type::externref: + break; // null + case Type::funcref: + case Type::exnref: + case Type::unreachable: + WASM_UNREACHABLE("unexpected type"); + } } } @@ -116,7 +131,7 @@ Literals Literal::makeZero(Type type) { Literal Literal::makeSingleZero(Type type) { assert(type.isSingle()); if (type.isRef()) { - return makeNullref(); + return makeNull(type); } else { return makeFromInt32(0, type); } @@ -130,8 +145,8 @@ std::array<uint8_t, 16> Literal::getv128() const { } ExceptionPackage Literal::getExceptionPackage() const { - assert(type == Type::exnref); - return *exn.get(); + assert(type.isException() && exn != nullptr); + return *exn; } Literal Literal::castToF32() { @@ -199,11 +214,17 @@ void Literal::getBits(uint8_t (&buf)[16]) const { case Type::v128: memcpy(buf, &v128, sizeof(v128)); break; + // TODO: investigate changing bits returned for reference types. currently, + // `null` values and even non-`null` functions return all zeroes, but only + // to avoid introducing a functional change. case Type::funcref: - case Type::nullref: break; case Type::externref: case Type::exnref: + if (isNull()) { + break; + } + // falls through case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -211,22 +232,22 @@ void Literal::getBits(uint8_t (&buf)[16]) const { } bool Literal::operator==(const Literal& other) const { - if (type.isRef() && other.type.isRef()) { - if (type == Type::nullref && other.type == Type::nullref) { - return true; - } - if (type == Type::funcref && other.type == Type::funcref && - func == other.func) { - return true; - } - return false; - } if (type != other.type) { return false; } if (type == Type::none) { return true; } + if (isNull() || other.isNull()) { + return isNull() == other.isNull(); + } + if (type.isFunction()) { + return func == other.func; + } + if (type.isException()) { + assert(exn != nullptr && other.exn != nullptr); + return *exn == *other.exn; + } uint8_t bits[16], other_bits[16]; getBits(bits); other.getBits(other_bits); @@ -350,15 +371,23 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { literal.printVec128(o, literal.getv128()); break; case Type::funcref: - o << "funcref(" << literal.getFunc() << ")"; - break; - case Type::nullref: - o << "nullref"; + if (literal.isNull()) { + o << "funcref(null)"; + } else { + o << "funcref(" << literal.getFunc() << ")"; + } break; case Type::exnref: - o << "exnref(" << literal.getExceptionPackage() << ")"; + if (literal.isNull()) { + o << "exnref(null)"; + } else { + o << "exnref(" << literal.getExceptionPackage() << ")"; + } break; case Type::externref: + assert(literal.isNull() && "TODO: non-null externref values"); + o << "externref(null)"; + break; case Type::unreachable: WASM_UNREACHABLE("invalid type"); } @@ -582,7 +611,6 @@ Literal Literal::eqz() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -604,7 +632,6 @@ Literal Literal::neg() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -626,7 +653,6 @@ Literal Literal::abs() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -731,7 +757,6 @@ Literal Literal::add(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -753,7 +778,6 @@ Literal Literal::sub(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -846,7 +870,6 @@ Literal Literal::mul(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1100,7 +1123,6 @@ Literal Literal::eq(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1122,7 +1144,6 @@ Literal Literal::ne(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index ae10687fb..b78d6b86b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1136,8 +1136,6 @@ Type WasmBinaryBuilder::getType() { return Type::funcref; case BinaryConsts::EncodedType::externref: return Type::externref; - case BinaryConsts::EncodedType::nullref: - return Type::nullref; case BinaryConsts::EncodedType::exnref: return Type::exnref; default: @@ -1146,6 +1144,28 @@ Type WasmBinaryBuilder::getType() { WASM_UNREACHABLE("unexpeced type"); } +HeapType WasmBinaryBuilder::getHeapType() { + int type = getS32LEB(); // TODO: Actually encoded as s33 + // Single heap types are negative; heap type indices are non-negative + if (type >= 0) { + if (size_t(type) >= signatures.size()) { + throwError("invalid signature index: " + std::to_string(type)); + } + return HeapType(signatures[type]); + } + switch (type) { + case BinaryConsts::EncodedHeapType::func: + return HeapType::FuncKind; + case BinaryConsts::EncodedHeapType::extern_: + return HeapType::ExternKind; + case BinaryConsts::EncodedHeapType::exn: + return HeapType::ExnKind; + default: + throwError("invalid wasm heap type: " + std::to_string(type)); + } + WASM_UNREACHABLE("unexpeced type"); +} + Type WasmBinaryBuilder::getConcreteType() { auto type = getType(); if (!type.isConcrete()) { @@ -4689,7 +4709,7 @@ void WasmBinaryBuilder::visitDrop(Drop* curr) { void WasmBinaryBuilder::visitRefNull(RefNull* curr) { BYN_TRACE("zz node: RefNull\n"); - curr->finalize(); + curr->finalize(getHeapType()); } void WasmBinaryBuilder::visitRefIsNull(RefIsNull* curr) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 931cd1bf0..0e4202a24 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -869,9 +869,6 @@ Type SExpressionWasmBuilder::stringToType(const char* str, if (strncmp(str, "externref", 9) == 0 && (prefix || str[9] == 0)) { return Type::externref; } - if (strncmp(str, "nullref", 7) == 0 && (prefix || str[7] == 0)) { - return Type::nullref; - } if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) { return Type::exnref; } @@ -881,6 +878,41 @@ Type SExpressionWasmBuilder::stringToType(const char* str, throw ParseException(std::string("invalid wasm type: ") + str); } +HeapType SExpressionWasmBuilder::stringToHeapType(const char* str, + bool prefix) { + if (str[0] == 'a') { + if (str[1] == 'n' && str[2] == 'y' && (prefix || str[3] == 0)) { + return HeapType::AnyKind; + } + } + if (str[0] == 'e') { + if (str[1] == 'q' && (prefix || str[2] == 0)) { + return HeapType::EqKind; + } + if (str[1] == 'x') { + if (str[2] == 'n' && (prefix || str[3] == 0)) { + return HeapType::ExnKind; + } + if (str[2] == 't' && str[3] == 'e' && str[4] == 'r' && str[5] == 'n' && + (prefix || str[6] == 0)) { + return HeapType::ExternKind; + } + } + } + if (str[0] == 'i') { + if (str[1] == '3' && str[2] == '1' && (prefix || str[3] == 0)) { + return HeapType::I31Kind; + } + } + if (str[0] == 'f') { + if (str[1] == 'u' && str[2] == 'n' && str[3] == 'c' && + (prefix || str[4] == 0)) { + return HeapType::FuncKind; + } + } + throw ParseException(std::string("invalid wasm heap type: ") + str); +} + Type SExpressionWasmBuilder::elementToType(Element& s) { if (s.isStr()) { return stringToType(s.str(), false, false); @@ -1779,8 +1811,12 @@ Expression* SExpressionWasmBuilder::makeReturn(Element& s) { } Expression* SExpressionWasmBuilder::makeRefNull(Element& s) { + if (s.size() != 2) { + throw ParseException("invalid heap type reference", s.line, s.col); + } + auto heapType = stringToHeapType(s[1]->str()); auto ret = allocator.alloc<RefNull>(); - ret->finalize(); + ret->finalize(heapType); return ret; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 88f90378c..aee5079c2 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -190,7 +190,6 @@ void BinaryInstWriter::visitLoad(Load* curr) { return; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("unexpected type"); @@ -292,7 +291,6 @@ void BinaryInstWriter::visitStore(Store* curr) { break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -695,7 +693,6 @@ void BinaryInstWriter::visitConst(Const* curr) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1686,7 +1683,8 @@ void BinaryInstWriter::visitHost(Host* curr) { } void BinaryInstWriter::visitRefNull(RefNull* curr) { - o << int8_t(BinaryConsts::RefNull); + o << int8_t(BinaryConsts::RefNull) + << binaryHeapType(curr->type.getHeapType()); } void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index e46cb5886..729cc88f5 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -260,7 +260,6 @@ std::unordered_map<TypeInfo, uintptr_t> indices = { // * `(ref null any) == anyref` // * `(ref null eq) == eqref` // * `(ref i31) == i31ref` - {TypeInfo({Type::nullref}), Type::nullref}, // TODO (removed) {TypeInfo({Type::exnref}), Type::exnref}, {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref}, }; @@ -347,6 +346,24 @@ bool Type::isRef() const { } } +bool Type::isFunction() const { + if (isBasic()) { + return id == funcref; + } else { + auto* info = getTypeInfo(*this); + return info->isRef() && info->ref.heapType.isSignature(); + } +} + +bool Type::isException() const { + if (isBasic()) { + return id == exnref; + } else { + auto* info = getTypeInfo(*this); + return info->isRef() && info->ref.heapType.isException(); + } +} + bool Type::isNullable() const { if (isBasic()) { return id >= funcref && id <= exnref; @@ -389,7 +406,6 @@ unsigned Type::getByteSize() const { return 16; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -432,7 +448,6 @@ FeatureSet Type::getFeatures() const { return FeatureSet::SIMD; case Type::funcref: case Type::externref: - case Type::nullref: return FeatureSet::ReferenceTypes; case Type::exnref: return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling; @@ -451,6 +466,25 @@ FeatureSet Type::getFeatures() const { return getSingleFeatures(*this); } +HeapType Type::getHeapType() const { + if (isRef()) { + if (isCompound()) { + return getTypeInfo(*this)->ref.heapType; + } + switch (getBasic()) { + case funcref: + return HeapType::FuncKind; + case externref: + return HeapType::ExternKind; + case exnref: + return HeapType::ExnKind; + default: + break; + } + } + WASM_UNREACHABLE("unexpected type"); +} + Type Type::get(unsigned byteSize, bool float_) { if (byteSize < 4) { return Type::i32; @@ -468,13 +502,10 @@ Type Type::get(unsigned byteSize, bool float_) { } bool Type::isSubType(Type left, Type right) { + // TODO (GC): subtyping, currently checks for equality only if (left == right) { return true; } - if (left.isRef() && right.isRef() && - (right == Type::externref || left == Type::nullref)) { - return true; - } if (left.isTuple() && right.isTuple()) { if (left.size() != right.size()) { return false; @@ -513,16 +544,7 @@ Type Type::getLeastUpperBound(Type a, Type b) { } return Type(types); } - if (!a.isRef() || !b.isRef()) { - return Type::none; - } - if (a == Type::nullref) { - return b; - } - if (b == Type::nullref) { - return a; - } - return Type::externref; + return Type::none; } Type::Iterator Type::end() const { @@ -554,8 +576,7 @@ const Type& Type::operator[](size_t index) const { } } -HeapType::HeapType(const HeapType& other) { - kind = other.kind; +HeapType::HeapType(const HeapType& other) : kind(other.kind) { switch (kind) { case FuncKind: case ExternKind: @@ -708,9 +729,6 @@ std::ostream& operator<<(std::ostream& os, Type type) { case Type::externref: os << "externref"; break; - case Type::nullref: - os << "nullref"; - break; case Type::exnref: os << "exnref"; break; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 3e1a057ce..b236f9120 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1264,7 +1264,6 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("unexpected type"); @@ -2074,7 +2073,6 @@ void FunctionValidator::validateAlignment( break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("invalid type"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 387ea577f..fe7c1b229 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -209,10 +209,10 @@ const char* getExpressionName(Expression* curr) { Literal getSingleLiteralFromConstExpression(Expression* curr) { if (auto* c = curr->dynCast<Const>()) { return c->value; - } else if (curr->is<RefNull>()) { - return Literal::makeNullref(); + } else if (auto* n = curr->dynCast<RefNull>()) { + return Literal::makeNull(n->type); } else if (auto* r = curr->dynCast<RefFunc>()) { - return Literal::makeFuncref(r->func); + return Literal::makeFunc(r->func); } else { WASM_UNREACHABLE("Not a constant expression"); } @@ -896,7 +896,16 @@ void Host::finalize() { } } -void RefNull::finalize() { type = Type::nullref; } +void RefNull::finalize(HeapType heapType) { type = Type(heapType, true); } + +void RefNull::finalize(Type type_) { + assert(type_ == Type::unreachable || type_.isNullable()); + type = type_; +} + +void RefNull::finalize() { + assert(type == Type::unreachable || type.isNullable()); +} void RefIsNull::finalize() { if (value->type == Type::unreachable) { |