summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parser/contexts.h7
-rw-r--r--src/parser/parsers.h23
-rw-r--r--src/shared-constants.h1
-rw-r--r--src/wasm-binary.h29
-rw-r--r--src/wasm-type-printing.h1
-rw-r--r--src/wasm-type.h26
-rw-r--r--src/wasm/wasm-binary.cpp40
-rw-r--r--src/wasm/wasm-s-parser.cpp48
-rw-r--r--src/wasm/wasm-type.cpp107
-rw-r--r--src/wasm/wasm.cpp1
10 files changed, 250 insertions, 33 deletions
diff --git a/src/parser/contexts.h b/src/parser/contexts.h
index 862d9772d..eb47dd502 100644
--- a/src/parser/contexts.h
+++ b/src/parser/contexts.h
@@ -83,6 +83,7 @@ struct NullTypeParserCtx {
using ResultsT = size_t;
using BlockTypeT = Ok;
using SignatureT = Ok;
+ using ContinuationT = Ok;
using StorageT = Ok;
using FieldT = Ok;
using FieldsT = Ok;
@@ -122,6 +123,7 @@ struct NullTypeParserCtx {
size_t getResultsSize(size_t results) { return results; }
SignatureT makeFuncType(ParamsT*, ResultsT*) { return Ok{}; }
+ ContinuationT makeContType(HeapTypeT) { return Ok{}; }
StorageT makeI8() { return Ok{}; }
StorageT makeI16() { return Ok{}; }
@@ -162,6 +164,7 @@ template<typename Ctx> struct TypeParserCtx {
using ResultsT = std::vector<Type>;
using BlockTypeT = HeapType;
using SignatureT = Signature;
+ using ContinuationT = Continuation;
using StorageT = Field;
using FieldT = Field;
using FieldsT = std::pair<std::vector<Name>, std::vector<Field>>;
@@ -216,6 +219,8 @@ template<typename Ctx> struct TypeParserCtx {
self().makeTupleType(resultTypes));
}
+ ContinuationT makeContType(HeapTypeT ft) { return Continuation(ft); }
+
StorageT makeI8() { return Field(Field::i8, Immutable); }
StorageT makeI16() { return Field(Field::i16, Immutable); }
StorageT makeStorageType(TypeT type) { return Field(type, Immutable); }
@@ -469,6 +474,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
ParseDeclsCtx(std::string_view in, Module& wasm) : in(in), wasm(wasm) {}
void addFuncType(SignatureT) {}
+ void addContType(ContinuationT) {}
void addStructType(StructT) {}
void addArrayType(ArrayT) {}
void setOpen() {}
@@ -577,6 +583,7 @@ struct ParseTypeDefsCtx : TypeParserCtx<ParseTypeDefsCtx> {
}
void addFuncType(SignatureT& type) { builder[index] = type; }
+ void addContType(ContinuationT& type) { builder[index] = type; }
void addStructType(StructT& type) {
auto& [fieldNames, str] = type;
diff --git a/src/parser/parsers.h b/src/parser/parsers.h
index 32f6709df..65fd98a24 100644
--- a/src/parser/parsers.h
+++ b/src/parser/parsers.h
@@ -391,6 +391,23 @@ MaybeResult<typename Ctx::SignatureT> functype(Ctx& ctx) {
return ctx.makeFuncType(parsedParams.getPtr(), parsedResults.getPtr());
}
+// conttype ::= '(' 'cont' x:typeidx ')' => cont x
+template<typename Ctx>
+MaybeResult<typename Ctx::ContinuationT> conttype(Ctx& ctx) {
+ if (!ctx.in.takeSExprStart("cont"sv)) {
+ return {};
+ }
+
+ auto x = typeidx(ctx);
+ CHECK_ERR(x);
+
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of cont type");
+ }
+
+ return ctx.makeContType(*x);
+}
+
// storagetype ::= valtype | packedtype
// packedtype ::= i8 | i16
template<typename Ctx> Result<typename Ctx::FieldT> storagetype(Ctx& ctx) {
@@ -1650,6 +1667,7 @@ Result<std::vector<Name>> inlineExports(ParseInput& in) {
}
// strtype ::= ft:functype => ft
+// | ct:conttype => ct
// | st:structtype => st
// | at:arraytype => at
template<typename Ctx> Result<> strtype(Ctx& ctx) {
@@ -1658,6 +1676,11 @@ template<typename Ctx> Result<> strtype(Ctx& ctx) {
ctx.addFuncType(*type);
return Ok{};
}
+ if (auto type = conttype(ctx)) {
+ CHECK_ERR(type);
+ ctx.addContType(*type);
+ return Ok{};
+ }
if (auto type = structtype(ctx)) {
CHECK_ERR(type);
ctx.addStructType(*type);
diff --git a/src/shared-constants.h b/src/shared-constants.h
index 0d2cc73ad..321ec3884 100644
--- a/src/shared-constants.h
+++ b/src/shared-constants.h
@@ -25,6 +25,7 @@ extern Name STACK_POINTER;
extern Name MODULE;
extern Name START;
extern Name FUNC;
+extern Name CONT;
extern Name PARAM;
extern Name RESULT;
extern Name MEMORY;
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index ee92fe90e..9e72b3b82 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -379,8 +379,8 @@ enum EncodedType {
i8 = -0x8, // 0x78
i16 = -0x9, // 0x77
#else
- i8 = -0x6, // 0x7a
- i16 = -0x7, // 0x79
+ i8 = -0x6, // 0x7a
+ i16 = -0x7, // 0x79
#endif
// reference types
#if STANDARD_GC_ENCODINGS
@@ -391,12 +391,12 @@ enum EncodedType {
structref = -0x15, // 0x6b
arrayref = -0x16, // 0x6a
#else
- nullexternref = -0x17, // 0x69
- nullfuncref = -0x18, // 0x68
- nullref = -0x1b, // 0x65
- i31ref = -0x16, // 0x6a
- structref = -0x19, // 0x67
- arrayref = -0x1a, // 0x66
+ nullexternref = -0x17, // 0x69
+ nullfuncref = -0x18, // 0x68
+ nullref = -0x1b, // 0x65
+ i31ref = -0x16, // 0x6a
+ structref = -0x19, // 0x67
+ arrayref = -0x1a, // 0x66
#endif
funcref = -0x10, // 0x70
externref = -0x11, // 0x6f
@@ -409,34 +409,35 @@ enum EncodedType {
nonnullable = -0x1c, // 0x64
nullable = -0x1d, // 0x63
#else
- nullable = -0x14, // 0x6c
- nonnullable = -0x15, // 0x6b
+ nullable = -0x14, // 0x6c
+ nonnullable = -0x15, // 0x6b
#endif
// string reference types
#if STANDARD_GC_ENCODINGS
stringref = -0x19, // 0x67
stringview_wtf8 = -0x1a, // 0x66
#else
- stringref = -0x1c, // 0x64
- stringview_wtf8 = -0x1d, // 0x63
+ stringref = -0x1c, // 0x64
+ stringview_wtf8 = -0x1d, // 0x63
#endif
stringview_wtf16 = -0x1e, // 0x62
stringview_iter = -0x1f, // 0x61
// type forms
Func = -0x20, // 0x60
+ Cont = -0x23, // 0x5d
Struct = -0x21, // 0x5f
Array = -0x22, // 0x5e
Sub = -0x30, // 0x50
#if STANDARD_GC_ENCODINGS
SubFinal = -0x31, // 0x4f
#else
- SubFinal = -0x32, // 0x4e
+ SubFinal = -0x32, // 0x4e
#endif
// isorecursive recursion groups
#if STANDARD_GC_ENCODINGS
Rec = -0x32, // 0x4e
#else
- Rec = -0x31, // 0x4f
+ Rec = -0x31, // 0x4f
#endif
// block_type
Empty = -0x40, // 0x40
diff --git a/src/wasm-type-printing.h b/src/wasm-type-printing.h
index 3a8740350..c7277e96d 100644
--- a/src/wasm-type-printing.h
+++ b/src/wasm-type-printing.h
@@ -53,6 +53,7 @@ template<typename Subclass> struct TypeNameGeneratorBase {
struct DefaultTypeNameGenerator
: TypeNameGeneratorBase<DefaultTypeNameGenerator> {
size_t funcCount = 0;
+ size_t contCount = 0;
size_t structCount = 0;
size_t arrayCount = 0;
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 23ceb9143..0061b9626 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -52,6 +52,7 @@ class Type;
class HeapType;
class RecGroup;
struct Signature;
+struct Continuation;
struct Field;
struct Struct;
struct Array;
@@ -345,6 +346,8 @@ public:
// this signature.
HeapType(Signature signature);
+ HeapType(Continuation cont);
+
// Create a HeapType with the given structure. In equirecursive mode, this may
// be the same as a previous HeapType created with the same contents. In
// nominal mode, this will be a fresh type distinct from all previously
@@ -358,6 +361,7 @@ public:
bool isFunction() const;
bool isData() const;
bool isSignature() const;
+ bool isContinuation() const;
bool isStruct() const;
bool isArray() const;
bool isString() const;
@@ -365,6 +369,8 @@ public:
bool isOpen() const;
Signature getSignature() const;
+ Continuation getContinuation() const;
+
const Struct& getStruct() const;
Array getArray() const;
@@ -476,6 +482,16 @@ struct Signature {
std::string toString() const;
};
+struct Continuation {
+ HeapType type;
+ Continuation(HeapType type) : type(type) {}
+ bool operator==(const Continuation& other) const {
+ return type == other.type;
+ }
+ bool operator!=(const Continuation& other) const { return !(*this == other); }
+ std::string toString() const;
+};
+
struct Field {
Type type;
enum PackedType {
@@ -570,6 +586,7 @@ struct TypeBuilder {
// Sets the heap type at index `i`. May only be called before `build`.
void setHeapType(size_t i, Signature signature);
+ void setHeapType(size_t i, Continuation continuation);
void setHeapType(size_t i, const Struct& struct_);
void setHeapType(size_t i, Struct&& struct_);
void setHeapType(size_t i, Array array);
@@ -640,6 +657,10 @@ struct TypeBuilder {
builder.setHeapType(index, signature);
return *this;
}
+ Entry& operator=(Continuation continuation) {
+ builder.setHeapType(index, continuation);
+ return *this;
+ }
Entry& operator=(const Struct& struct_) {
builder.setHeapType(index, struct_);
return *this;
@@ -687,6 +708,7 @@ std::ostream& operator<<(std::ostream&, HeapType);
std::ostream& operator<<(std::ostream&, HeapType::Printed);
std::ostream& operator<<(std::ostream&, Tuple);
std::ostream& operator<<(std::ostream&, Signature);
+std::ostream& operator<<(std::ostream&, Continuation);
std::ostream& operator<<(std::ostream&, Field);
std::ostream& operator<<(std::ostream&, Struct);
std::ostream& operator<<(std::ostream&, Array);
@@ -704,6 +726,10 @@ template<> class hash<wasm::Signature> {
public:
size_t operator()(const wasm::Signature&) const;
};
+template<> class hash<wasm::Continuation> {
+public:
+ size_t operator()(const wasm::Continuation&) const;
+};
template<> class hash<wasm::Field> {
public:
size_t operator()(const wasm::Field&) const;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index b12cb50c7..6b74f2597 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -292,6 +292,9 @@ void WasmBinaryWriter::writeTypes() {
writeType(type);
}
}
+ } else if (type.isContinuation()) {
+ o << S32LEB(BinaryConsts::EncodedType::Cont);
+ writeHeapType(type.getContinuation().type);
} else if (type.isStruct()) {
o << S32LEB(BinaryConsts::EncodedType::Struct);
auto fields = type.getStruct().fields;
@@ -1577,7 +1580,8 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
}
}
- if (type.isSignature() || type.isStruct() || type.isArray()) {
+ if (type.isSignature() || type.isContinuation() || type.isStruct() ||
+ type.isArray()) {
o << S64LEB(getTypeIndex(type)); // TODO: Actually s33
return;
}
@@ -2184,6 +2188,17 @@ void WasmBinaryReader::readTypes() {
TypeBuilder builder(getU32LEB());
BYN_TRACE("num: " << builder.size() << std::endl);
+ auto readHeapType = [&]() {
+ int64_t htCode = getS64LEB(); // TODO: Actually s33
+ HeapType ht;
+ if (getBasicHeapType(htCode, ht)) {
+ return ht;
+ }
+ if (size_t(htCode) >= builder.size()) {
+ throwError("invalid type index: " + std::to_string(htCode));
+ }
+ return builder.getTempHeapType(size_t(htCode));
+ };
auto makeType = [&](int32_t typeCode) {
Type type;
if (getBasicType(typeCode, type)) {
@@ -2196,22 +2211,19 @@ void WasmBinaryReader::readTypes() {
auto nullability = typeCode == BinaryConsts::EncodedType::nullable
? Nullable
: NonNullable;
- int64_t htCode = getS64LEB(); // TODO: Actually s33
- HeapType ht;
- if (getBasicHeapType(htCode, ht)) {
+
+ HeapType ht = readHeapType();
+ if (ht.isBasic()) {
return Type(ht, nullability);
}
- if (size_t(htCode) >= builder.size()) {
- throwError("invalid type index: " + std::to_string(htCode));
- }
- return builder.getTempRefType(builder[size_t(htCode)], nullability);
+
+ return builder.getTempRefType(ht, nullability);
}
default:
throwError("unexpected type index: " + std::to_string(typeCode));
}
WASM_UNREACHABLE("unexpected type");
};
-
auto readType = [&]() { return makeType(getS32LEB()); };
auto readSignatureDef = [&]() {
@@ -2231,6 +2243,14 @@ void WasmBinaryReader::readTypes() {
builder.getTempTupleType(results));
};
+ auto readContinuationDef = [&]() {
+ HeapType ht = readHeapType();
+ if (!ht.isSignature()) {
+ throw ParseException("cont types must be built from function types");
+ }
+ return Continuation(ht);
+ };
+
auto readMutability = [&]() {
switch (getU32LEB()) {
case 0:
@@ -2303,6 +2323,8 @@ void WasmBinaryReader::readTypes() {
}
if (form == BinaryConsts::EncodedType::Func) {
builder[i] = readSignatureDef();
+ } else if (form == BinaryConsts::EncodedType::Cont) {
+ builder[i] = readContinuationDef();
} else if (form == BinaryConsts::EncodedType::Struct) {
builder[i] = readStructDef();
} else if (form == BinaryConsts::EncodedType::Array) {
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 4074e4792..6f3fbe76b 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -817,22 +817,36 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) {
});
finishGroup();
+ auto parseHeapType = [&](Element& elem) -> HeapType {
+ auto name = elem.toString();
+ if (elem.dollared()) {
+ auto it = typeIndices.find(name);
+ if (it == typeIndices.end()) {
+ throw SParseException("invalid type name", elem);
+ } else {
+ return builder[it->second];
+ }
+ } else if (String::isNumber(name)) {
+ size_t index = parseIndex(elem);
+ if (index >= numTypes) {
+ throw SParseException("invalid type index", elem);
+ }
+ return builder[index];
+ } else {
+ return stringToHeapType(elem.str());
+ }
+ };
+
auto parseRefType = [&](Element& elem) -> Type {
// '(' 'ref' 'null'? ht ')'
auto nullable =
elem[1]->isStr() && *elem[1] == NULL_ ? Nullable : NonNullable;
auto& referent = nullable ? *elem[2] : *elem[1];
- auto name = referent.toString();
- if (referent.dollared()) {
- return builder.getTempRefType(builder[typeIndices[name]], nullable);
- } else if (String::isNumber(name)) {
- size_t index = parseIndex(referent);
- if (index >= numTypes) {
- throw SParseException("invalid type index", elem);
- }
- return builder.getTempRefType(builder[index], nullable);
+ auto ht = parseHeapType(referent);
+ if (ht.isBasic()) {
+ return Type(ht, nullable);
} else {
- return Type(stringToHeapType(referent.str()), nullable);
+ return builder.getTempRefType(ht, nullable);
}
};
@@ -886,6 +900,16 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) {
builder.getTempTupleType(results));
};
+ auto parseContinuationDef = [&](Element& elem) {
+ // '(' 'cont' index ')' | '(' 'cont' name ')'
+ HeapType ft = parseHeapType(*elem[1]);
+ if (!ft.isSignature()) {
+ throw ParseException(
+ "cont type must be created from func type", elem.line, elem.col);
+ }
+ return Continuation(ft);
+ };
+
// Parses a field, and notes the name if one is found.
auto parseField = [&](Element* elem, Name& name) {
Mutability mutable_ = Immutable;
@@ -964,6 +988,8 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) {
Element& subtypeKind = *subtype[0];
if (subtypeKind == FUNC) {
builder[index] = parseSignatureDef(subtype, 0);
+ } else if (kind == CONT) {
+ builder[index] = parseContinuationDef(subtype);
} else if (subtypeKind == STRUCT) {
builder[index] = parseStructDef(subtype, index, 0);
} else if (subtypeKind == ARRAY) {
@@ -974,6 +1000,8 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) {
} else {
if (kind == FUNC) {
builder[index] = parseSignatureDef(def, 0);
+ } else if (kind == CONT) {
+ builder[index] = parseContinuationDef(def);
} else if (kind == STRUCT) {
builder[index] = parseStructDef(def, index, 0);
} else if (kind == ARRAY) {
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 68d7f732b..cab68d00d 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -94,16 +94,20 @@ struct HeapTypeInfo {
size_t recGroupIndex = 0;
enum Kind {
SignatureKind,
+ ContinuationKind,
StructKind,
ArrayKind,
} kind;
union {
Signature signature;
+ Continuation continuation;
Struct struct_;
Array array;
};
HeapTypeInfo(Signature sig) : kind(SignatureKind), signature(sig) {}
+ HeapTypeInfo(Continuation continuation)
+ : kind(ContinuationKind), continuation(continuation) {}
HeapTypeInfo(const Struct& struct_) : kind(StructKind), struct_(struct_) {}
HeapTypeInfo(Struct&& struct_)
: kind(StructKind), struct_(std::move(struct_)) {}
@@ -111,6 +115,7 @@ struct HeapTypeInfo {
~HeapTypeInfo();
constexpr bool isSignature() const { return kind == SignatureKind; }
+ constexpr bool isContinuation() const { return kind == ContinuationKind; }
constexpr bool isStruct() const { return kind == StructKind; }
constexpr bool isArray() const { return kind == ArrayKind; }
constexpr bool isData() const { return isStruct() || isArray(); }
@@ -124,6 +129,7 @@ struct SubTyper {
bool isSubType(const Tuple& a, const Tuple& b);
bool isSubType(const Field& a, const Field& b);
bool isSubType(const Signature& a, const Signature& b);
+ bool isSubType(const Continuation& a, const Continuation& b);
bool isSubType(const Struct& a, const Struct& b);
bool isSubType(const Array& a, const Array& b);
};
@@ -155,6 +161,7 @@ struct TypePrinter {
std::ostream& print(const Tuple& tuple);
std::ostream& print(const Field& field);
std::ostream& print(const Signature& sig);
+ std::ostream& print(const Continuation& cont);
std::ostream& print(const Struct& struct_,
const std::unordered_map<Index, Name>& fieldNames);
std::ostream& print(const Array& array);
@@ -181,6 +188,7 @@ struct RecGroupHasher {
size_t hash(const Tuple& tuple) const;
size_t hash(const Field& field) const;
size_t hash(const Signature& sig) const;
+ size_t hash(const Continuation& sig) const;
size_t hash(const Struct& struct_) const;
size_t hash(const Array& array) const;
};
@@ -207,6 +215,7 @@ struct RecGroupEquator {
bool eq(const Tuple& a, const Tuple& b) const;
bool eq(const Field& a, const Field& b) const;
bool eq(const Signature& a, const Signature& b) const;
+ bool eq(const Continuation& a, const Continuation& b) const;
bool eq(const Struct& a, const Struct& b) const;
bool eq(const Array& a, const Array& b) const;
};
@@ -355,6 +364,7 @@ template<typename Self> struct HeapTypeChildWalker : HeapTypeGraphWalker<Self> {
} else {
static_cast<Self*>(this)->noteChild(ht);
}
+ isTopLevel = false;
}
private:
@@ -431,6 +441,8 @@ HeapType::BasicHeapType getBasicHeapSupertype(HeapType type) {
switch (info->kind) {
case HeapTypeInfo::SignatureKind:
return HeapType::func;
+ case HeapTypeInfo::ContinuationKind:
+ return HeapType::any;
case HeapTypeInfo::StructKind:
return HeapType::struct_;
case HeapTypeInfo::ArrayKind:
@@ -550,6 +562,9 @@ HeapTypeInfo::~HeapTypeInfo() {
case SignatureKind:
signature.~Signature();
return;
+ case ContinuationKind:
+ continuation.~Continuation();
+ return;
case StructKind:
struct_.~Struct();
return;
@@ -922,6 +937,8 @@ FeatureSet Type::getFeatures() const {
if (sig.results.isTuple()) {
feats |= FeatureSet::Multivalue;
}
+ } else if (heapType->isContinuation()) {
+ feats |= FeatureSet::TypedContinuations;
}
// In addition, scan their non-ref children, to add dependencies on
@@ -1093,6 +1110,12 @@ HeapType::HeapType(Signature sig) {
HeapType(globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(sig)));
}
+HeapType::HeapType(Continuation continuation) {
+ assert(!isTemp(continuation.type) && "Leaking temporary type!");
+ new (this) HeapType(
+ globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(continuation)));
+}
+
HeapType::HeapType(const Struct& struct_) {
#ifndef NDEBUG
for (const auto& field : struct_.fields) {
@@ -1143,6 +1166,14 @@ bool HeapType::isSignature() const {
}
}
+bool HeapType::isContinuation() const {
+ if (isBasic()) {
+ return false;
+ } else {
+ return getHeapTypeInfo(*this)->isContinuation();
+ }
+}
+
bool HeapType::isStruct() const {
if (isBasic()) {
return false;
@@ -1198,6 +1229,11 @@ Signature HeapType::getSignature() const {
return getHeapTypeInfo(*this)->signature;
}
+Continuation HeapType::getContinuation() const {
+ assert(isContinuation());
+ return getHeapTypeInfo(*this)->continuation;
+}
+
const Struct& HeapType::getStruct() const {
assert(isStruct());
return getHeapTypeInfo(*this)->struct_;
@@ -1252,6 +1288,8 @@ std::optional<HeapType> HeapType::getSuperType() const {
switch (info->kind) {
case HeapTypeInfo::SignatureKind:
return func;
+ case HeapTypeInfo::ContinuationKind:
+ return any;
case HeapTypeInfo::StructKind:
return struct_;
case HeapTypeInfo::ArrayKind:
@@ -1273,6 +1311,8 @@ size_t HeapType::getDepth() const {
if (!isBasic()) {
if (isFunction()) {
depth++;
+ } else if (isContinuation()) {
+ // cont types <: any, thus nothing to add
} else if (isStruct()) {
// specific struct types <: struct <: eq <: any
depth += 3;
@@ -1337,6 +1377,8 @@ HeapType::BasicHeapType HeapType::getBottom() const {
switch (info->kind) {
case HeapTypeInfo::SignatureKind:
return nofunc;
+ case HeapTypeInfo::ContinuationKind:
+ return none;
case HeapTypeInfo::StructKind:
case HeapTypeInfo::ArrayKind:
return none;
@@ -1376,6 +1418,9 @@ std::vector<Type> HeapType::getTypeChildren() const {
}
return children;
}
+ if (isContinuation()) {
+ return {};
+ }
WASM_UNREACHABLE("unexpected kind");
}
@@ -1496,6 +1541,8 @@ TypeNames DefaultTypeNameGenerator::getNames(HeapType type) {
std::stringstream stream;
if (type.isSignature()) {
stream << "func." << funcCount++;
+ } else if (type.isContinuation()) {
+ stream << "cont." << contCount++;
} else if (type.isStruct()) {
stream << "struct." << structCount++;
} else if (type.isArray()) {
@@ -1516,6 +1563,7 @@ template<typename T> static std::string genericToString(const T& t) {
std::string Type::toString() const { return genericToString(*this); }
std::string HeapType::toString() const { return genericToString(*this); }
std::string Signature::toString() const { return genericToString(*this); }
+std::string Continuation::toString() const { return genericToString(*this); }
std::string Struct::toString() const { return genericToString(*this); }
std::string Array::toString() const { return genericToString(*this); }
@@ -1537,6 +1585,9 @@ std::ostream& operator<<(std::ostream& os, Tuple tuple) {
std::ostream& operator<<(std::ostream& os, Signature sig) {
return TypePrinter(os).print(sig);
}
+std::ostream& operator<<(std::ostream& os, Continuation cont) {
+ return TypePrinter(os).print(cont);
+}
std::ostream& operator<<(std::ostream& os, Field field) {
return TypePrinter(os).print(field);
}
@@ -1671,6 +1722,10 @@ bool SubTyper::isSubType(const Signature& a, const Signature& b) {
return isSubType(b.params, a.params) && isSubType(a.results, b.results);
}
+bool SubTyper::isSubType(const Continuation& a, const Continuation& b) {
+ return isSubType(a.type, b.type);
+}
+
bool SubTyper::isSubType(const Struct& a, const Struct& b) {
// There may be more fields on the left, but not fewer.
if (a.fields.size() < b.fields.size()) {
@@ -1833,6 +1888,8 @@ std::ostream& TypePrinter::print(HeapType type) {
}
if (type.isSignature()) {
print(type.getSignature());
+ } else if (type.isContinuation()) {
+ print(type.getContinuation());
} else if (type.isStruct()) {
print(type.getStruct(), names.fieldNames);
} else if (type.isArray()) {
@@ -1901,6 +1958,12 @@ std::ostream& TypePrinter::print(const Signature& sig) {
return os << ')';
}
+std::ostream& TypePrinter::print(const Continuation& continuation) {
+ os << "(cont ";
+ printHeapTypeName(continuation.type);
+ return os << ')';
+}
+
std::ostream&
TypePrinter::print(const Struct& struct_,
const std::unordered_map<Index, Name>& fieldNames) {
@@ -1998,6 +2061,9 @@ size_t RecGroupHasher::hash(const HeapTypeInfo& info) const {
case HeapTypeInfo::SignatureKind:
hash_combine(digest, hash(info.signature));
return digest;
+ case HeapTypeInfo::ContinuationKind:
+ hash_combine(digest, hash(info.continuation));
+ return digest;
case HeapTypeInfo::StructKind:
hash_combine(digest, hash(info.struct_));
return digest;
@@ -2029,6 +2095,14 @@ size_t RecGroupHasher::hash(const Signature& sig) const {
return digest;
}
+size_t RecGroupHasher::hash(const Continuation& continuation) const {
+ // We throw in a magic constant to distinguish (cont $foo) from $foo
+ size_t magic = 0xc0117;
+ size_t digest = hash(continuation.type);
+ rehash(digest, magic);
+ return digest;
+}
+
size_t RecGroupHasher::hash(const Struct& struct_) const {
size_t digest = wasm::hash(struct_.fields.size());
for (const auto& field : struct_.fields) {
@@ -2124,6 +2198,8 @@ bool RecGroupEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) const {
switch (a.kind) {
case HeapTypeInfo::SignatureKind:
return eq(a.signature, b.signature);
+ case HeapTypeInfo::ContinuationKind:
+ return eq(a.continuation, b.continuation);
case HeapTypeInfo::StructKind:
return eq(a.struct_, b.struct_);
case HeapTypeInfo::ArrayKind:
@@ -2148,6 +2224,10 @@ bool RecGroupEquator::eq(const Signature& a, const Signature& b) const {
return eq(a.params, b.params) && eq(a.results, b.results);
}
+bool RecGroupEquator::eq(const Continuation& a, const Continuation& b) const {
+ return eq(a.type, b.type);
+}
+
bool RecGroupEquator::eq(const Struct& a, const Struct& b) const {
return std::equal(a.fields.begin(),
a.fields.end(),
@@ -2234,6 +2314,9 @@ void TypeGraphWalkerBase<Self>::scanHeapType(HeapType* ht) {
taskList.push_back(Task::scan(&info->signature.results));
taskList.push_back(Task::scan(&info->signature.params));
break;
+ case HeapTypeInfo::ContinuationKind:
+ taskList.push_back(Task::scan(&info->continuation.type));
+ break;
case HeapTypeInfo::StructKind: {
auto& fields = info->struct_.fields;
for (auto field = fields.rbegin(); field != fields.rend(); ++field) {
@@ -2274,6 +2357,9 @@ struct TypeBuilder::Impl {
case HeapTypeInfo::SignatureKind:
info->signature = hti.signature;
break;
+ case HeapTypeInfo::ContinuationKind:
+ info->continuation = hti.continuation;
+ break;
case HeapTypeInfo::StructKind:
info->struct_ = std::move(hti.struct_);
break;
@@ -2312,6 +2398,11 @@ void TypeBuilder::setHeapType(size_t i, Signature signature) {
impl->entries[i].set(signature);
}
+void TypeBuilder::setHeapType(size_t i, Continuation continuation) {
+ assert(i < size() && "index out of bounds");
+ impl->entries[i].set(continuation);
+}
+
void TypeBuilder::setHeapType(size_t i, const Struct& struct_) {
assert(i < size() && "index out of bounds");
impl->entries[i].set(struct_);
@@ -2389,6 +2480,8 @@ bool isValidSupertype(const HeapTypeInfo& sub, const HeapTypeInfo& super) {
switch (sub.kind) {
case HeapTypeInfo::SignatureKind:
return typer.isSubType(sub.signature, super.signature);
+ case HeapTypeInfo::ContinuationKind:
+ return typer.isSubType(sub.continuation, super.continuation);
case HeapTypeInfo::StructKind:
return typer.isSubType(sub.struct_, super.struct_);
case HeapTypeInfo::ArrayKind:
@@ -2426,7 +2519,12 @@ void updateReferencedHeapTypes(
void scanHeapType(HeapType* type) {
if (isTopLevel) {
+ isTopLevel = false;
TypeGraphWalkerBase<ChildUpdater>::scanHeapType(type);
+ } else {
+ if (auto it = canonicalized.find(*type); it != canonicalized.end()) {
+ *type = it->second;
+ }
}
}
};
@@ -2686,6 +2784,15 @@ size_t hash<wasm::Signature>::operator()(const wasm::Signature& sig) const {
return digest;
}
+size_t
+hash<wasm::Continuation>::operator()(const wasm::Continuation& cont) const {
+ // We throw in a magic constant to distinguish (cont $foo) from $foo
+ auto magic = 0xc0117;
+ auto digest = wasm::hash(cont.type);
+ wasm::rehash(digest, magic);
+ return digest;
+}
+
size_t hash<wasm::Field>::operator()(const wasm::Field& field) const {
auto digest = wasm::hash(field.type);
wasm::rehash(digest, field.packedType);
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index e5f3deb33..fef613cd2 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -60,6 +60,7 @@ Name MODULE("module");
Name START("start");
Name GLOBAL("global");
Name FUNC("func");
+Name CONT("cont");
Name PARAM("param");
Name RESULT("result");
Name MEMORY("memory");