diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/literal.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 34 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 26 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 6 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 11 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 18 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 15 |
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() { |