summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/literal.cpp3
-rw-r--r--src/wasm/wasm-binary.cpp34
-rw-r--r--src/wasm/wasm-s-parser.cpp26
-rw-r--r--src/wasm/wasm-stack.cpp6
-rw-r--r--src/wasm/wasm-type.cpp11
-rw-r--r--src/wasm/wasm-validator.cpp18
-rw-r--r--src/wasm/wasm.cpp15
7 files changed, 90 insertions, 23 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index b7cf5084e..c19efa225 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -60,6 +60,9 @@ Literal::Literal(const Literal& other) : type(other.type) {
new (&gcData) std::shared_ptr<Literals>(other.gcData);
} else if (type.isFunction()) {
func = other.func;
+ } else if (type.isRtt()) {
+ // Nothing to do: Rtts help JITs optimize, but are not used in the
+ // interpreter yet, and they are opaque to the wasm itself.
} else {
TODO_SINGLE_COMPOUND(type);
switch (type.getBasic()) {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 25c1eea8c..20edab3cf 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -982,6 +982,17 @@ void WasmBinaryWriter::writeType(Type type) {
writeHeapType(type.getHeapType());
return;
}
+ if (type.isRtt()) {
+ auto rtt = type.getRtt();
+ if (rtt.hasDepth()) {
+ o << S32LEB(BinaryConsts::EncodedType::rtt_n);
+ o << U32LEB(rtt.depth);
+ } else {
+ o << S32LEB(BinaryConsts::EncodedType::rtt);
+ }
+ writeHeapType(rtt.heapType);
+ return;
+ }
int ret = 0;
TODO_SINGLE_COMPOUND(type);
switch (type.getBasic()) {
@@ -1382,6 +1393,14 @@ Type WasmBinaryBuilder::getType(int initial) {
return Type(getHeapType(), /* nullable = */ true);
case BinaryConsts::EncodedType::i31ref:
return Type::i31ref;
+ case BinaryConsts::EncodedType::rtt_n: {
+ auto depth = getU32LEB();
+ auto heapType = getHeapType();
+ return Type(Rtt(depth, heapType));
+ }
+ case BinaryConsts::EncodedType::rtt: {
+ return Type(Rtt(getHeapType()));
+ }
default:
throwError("invalid wasm type: " + std::to_string(initial));
}
@@ -5575,10 +5594,8 @@ bool WasmBinaryBuilder::maybeVisitRttCanon(Expression*& out, uint32_t code) {
if (code != BinaryConsts::RttCanon) {
return false;
}
- auto* curr = allocator.alloc<RttCanon>();
- WASM_UNREACHABLE("TODO (gc): rtt.canon");
- curr->finalize();
- out = curr;
+ auto heapType = getHeapType();
+ out = Builder(wasm).makeRttCanon(heapType);
return true;
}
@@ -5586,10 +5603,11 @@ bool WasmBinaryBuilder::maybeVisitRttSub(Expression*& out, uint32_t code) {
if (code != BinaryConsts::RttSub) {
return false;
}
- auto* curr = allocator.alloc<RttSub>();
- WASM_UNREACHABLE("TODO (gc): rtt.sub");
- curr->finalize();
- out = curr;
+ // FIXME: the binary format may also have an extra heap type and index that
+ // are not needed
+ auto heapType = getHeapType();
+ auto* parent = popNonVoidExpression();
+ out = Builder(wasm).makeRttSub(heapType, parent);
return true;
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 21104d0fe..63b6e34bd 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -50,7 +50,7 @@ int unhex(char c) {
namespace wasm {
static Name STRUCT("struct"), FIELD("field"), ARRAY("array"), I8("i8"),
- I16("i16");
+ I16("i16"), RTT("rtt");
static Address getAddress(const Element* s) { return atoll(s->c_str()); }
@@ -940,6 +940,18 @@ Type SExpressionWasmBuilder::elementToType(Element& s) {
}
return Type(parseHeapType(*s[i]), nullable);
}
+ if (elementStartsWith(s, RTT)) {
+ // It's an RTT, something like (rtt N $typename) or just (rtt $typename)
+ // if there is no depth.
+ if (s[1]->dollared()) {
+ auto heapType = parseHeapType(*s[1]);
+ return Type(Rtt(heapType));
+ } else {
+ auto depth = atoi(s[1]->str().c_str());
+ auto heapType = parseHeapType(*s[2]);
+ return Type(Rtt(depth, heapType));
+ }
+ }
// It's a tuple.
std::vector<Type> types;
for (size_t i = 0; i < s.size(); ++i) {
@@ -2102,17 +2114,13 @@ Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s) {
}
Expression* SExpressionWasmBuilder::makeRttCanon(Element& s) {
- auto ret = allocator.alloc<RttCanon>();
- WASM_UNREACHABLE("TODO (gc): rtt.canon");
- ret->finalize();
- return ret;
+ return Builder(wasm).makeRttCanon(parseHeapType(*s[1]));
}
Expression* SExpressionWasmBuilder::makeRttSub(Element& s) {
- auto ret = allocator.alloc<RttSub>();
- WASM_UNREACHABLE("TODO (gc): rtt.sub");
- ret->finalize();
- return ret;
+ auto heapType = parseHeapType(*s[1]);
+ auto parent = parseExpression(*s[2]);
+ return Builder(wasm).makeRttSub(heapType, parent);
}
Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 9d0d04b6d..cca351b6f 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1897,12 +1897,14 @@ void BinaryInstWriter::visitBrOnCast(BrOnCast* curr) {
void BinaryInstWriter::visitRttCanon(RttCanon* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttCanon);
- WASM_UNREACHABLE("TODO (gc): rtt.canon");
+ parent.writeHeapType(curr->type.getRtt().heapType);
}
void BinaryInstWriter::visitRttSub(RttSub* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttSub);
- WASM_UNREACHABLE("TODO (gc): rtt.sub");
+ // FIXME: the binary format may also have an extra heap type and index that
+ // are not needed
+ parent.writeHeapType(curr->type.getRtt().heapType);
}
void BinaryInstWriter::visitStructNew(StructNew* curr) {
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 48b37a864..013dadcf4 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -463,6 +463,8 @@ FeatureSet Type::getFeatures() const {
if (heapType.isStruct() || heapType.isArray()) {
return FeatureSet::ReferenceTypes | FeatureSet::GC;
}
+ } else if (t.isRtt()) {
+ return FeatureSet::ReferenceTypes | FeatureSet::GC;
}
TODO_SINGLE_COMPOUND(t);
switch (t.getBasic()) {
@@ -529,6 +531,15 @@ HeapType Type::getHeapType() const {
}
WASM_UNREACHABLE("Unexpected type");
}
+ if (isRtt()) {
+ return getRtt().heapType;
+ }
+ WASM_UNREACHABLE("unexpected type");
+}
+
+const Rtt& Type::getRtt() const {
+ assert(isRtt());
+ return getTypeInfo(*this)->rtt;
}
Type Type::get(unsigned byteSize, bool float_) {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index b2e208d53..c6e22899c 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2211,13 +2211,27 @@ void FunctionValidator::visitBrOnCast(BrOnCast* curr) {
void FunctionValidator::visitRttCanon(RttCanon* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "rtt.canon requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): rtt.canon");
+ shouldBeTrue(curr->type.isRtt(), curr, "rtt.canon must have RTT type");
+ auto rtt = curr->type.getRtt();
+ shouldBeEqual(rtt.depth, Index(0), curr, "rtt.canon has a depth of 0");
}
void FunctionValidator::visitRttSub(RttSub* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "rtt.sub requires gc to be enabled");
- WASM_UNREACHABLE("TODO (gc): rtt.sub");
+ shouldBeTrue(curr->type.isRtt(), curr, "rtt.sub must have RTT type");
+ if (curr->parent->type != Type::unreachable) {
+ shouldBeTrue(
+ curr->parent->type.isRtt(), curr, "rtt.sub parent must have RTT type");
+ auto parentRtt = curr->parent->type.getRtt();
+ auto rtt = curr->type.getRtt();
+ if (rtt.hasDepth() && parentRtt.hasDepth()) {
+ shouldBeEqual(rtt.depth,
+ parentRtt.depth + 1,
+ curr,
+ "rtt.canon has a depth of 1 over the parent");
+ }
+ }
}
void FunctionValidator::visitStructNew(StructNew* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index c15042721..1e8bf93ae 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1080,8 +1080,19 @@ void CallRef::finalize(Type type_) {
// TODO (gc): ref.test
// TODO (gc): ref.cast
// TODO (gc): br_on_cast
-// TODO (gc): rtt.canon
-// TODO (gc): rtt.sub
+
+void RttCanon::finalize() {
+ // Nothing to do - the type must have been set already during construction.
+}
+
+void RttSub::finalize() {
+ if (parent->type == Type::unreachable) {
+ type = Type::unreachable;
+ }
+ // Else nothing to do - the type must have been set already during
+ // construction.
+}
+
// TODO (gc): struct.new
void StructGet::finalize() {