summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/literal.cpp125
-rw-r--r--src/wasm/wasm-binary.cpp26
-rw-r--r--src/wasm/wasm-s-parser.cpp44
-rw-r--r--src/wasm/wasm-stack.cpp6
-rw-r--r--src/wasm/wasm-type.cpp62
-rw-r--r--src/wasm/wasm-validator.cpp2
-rw-r--r--src/wasm/wasm.cpp17
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) {