summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/module-utils.h54
-rw-r--r--src/wasm-binary.h4
-rw-r--r--src/wasm-type.h3
-rw-r--r--src/wasm/wasm-binary.cpp271
-rw-r--r--src/wasm/wasm-type.cpp1
5 files changed, 191 insertions, 142 deletions
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index 29ebcc2b5..84ef3a508 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -433,10 +433,7 @@ inline void collectHeapTypes(Module& wasm,
std::unordered_map<HeapType, Index>& typeIndices) {
struct Counts : public std::unordered_map<HeapType, size_t> {
bool isRelevant(Type type) {
- if (type.isRef()) {
- return !type.getHeapType().isBasic();
- }
- return type.isRtt();
+ return (type.isRef() || type.isRtt()) && !type.getHeapType().isBasic();
}
void note(HeapType type) { (*this)[type]++; }
void maybeNote(Type type) {
@@ -469,10 +466,11 @@ inline void collectHeapTypes(Module& wasm,
} else if (auto* set = curr->dynCast<StructSet>()) {
counts.maybeNote(set->ref->type);
} else if (Properties::isControlFlowStructure(curr)) {
- counts.maybeNote(curr->type);
if (curr->type.isTuple()) {
// TODO: Allow control flow to have input types as well
counts.note(Signature(Type::none, curr->type));
+ } else {
+ counts.maybeNote(curr->type);
}
}
}
@@ -509,8 +507,7 @@ inline void collectHeapTypes(Module& wasm,
}
// A generic utility to traverse the child types of a type.
// TODO: work with tlively to refactor this to a shared place
- auto walkRelevantChildren = [&](HeapType type,
- std::function<void(HeapType)> callback) {
+ auto walkRelevantChildren = [&](HeapType type, auto callback) {
auto callIfRelevant = [&](Type type) {
if (counts.isRelevant(type)) {
callback(type.getHeapType());
@@ -538,7 +535,6 @@ inline void collectHeapTypes(Module& wasm,
// As we do this we may find more and more types, as nested children of
// previous ones. Each such type will appear in the type section once, so
// we just need to visit it once.
- // TODO: handle struct and array fields
std::unordered_set<HeapType> newTypes;
for (auto& pair : counts) {
newTypes.insert(pair.first);
@@ -555,49 +551,9 @@ inline void collectHeapTypes(Module& wasm,
});
}
- // We must sort all the dependencies of a type before it. For example,
- // (func (param (ref (func)))) must appear after (func). To do that, find the
- // depth of dependencies of each type. For example, if A depends on B
- // which depends on C, then A's depth is 2, B's is 1, and C's is 0 (assuming
- // no other dependencies).
- Counts depthOfDependencies;
- std::unordered_map<HeapType, std::unordered_set<HeapType>> isDependencyOf;
- // To calculate the depth of dependencies, we'll do a flow analysis, visiting
- // each type as we find out new things about it.
- std::set<HeapType> toVisit;
- for (auto& pair : counts) {
- auto type = pair.first;
- depthOfDependencies[type] = 0;
- toVisit.insert(type);
- walkRelevantChildren(type, [&](HeapType childType) {
- isDependencyOf[childType].insert(type); // XXX flip?
- });
- }
- while (!toVisit.empty()) {
- auto iter = toVisit.begin();
- auto type = *iter;
- toVisit.erase(iter);
- // Anything that depends on this has a depth of dependencies equal to this
- // type's, plus this type itself.
- auto newDepth = depthOfDependencies[type] + 1;
- if (newDepth > counts.size()) {
- Fatal() << "Cyclic types detected, cannot sort them.";
- }
- for (auto& other : isDependencyOf[type]) {
- if (depthOfDependencies[other] < newDepth) {
- // We found something new to propagate.
- depthOfDependencies[other] = newDepth;
- toVisit.insert(other);
- }
- }
- }
- // Sort by frequency and then simplicity, and also keeping every type
- // before things that depend on it.
+ // Sort by frequency and then simplicity.
std::vector<std::pair<HeapType, size_t>> sorted(counts.begin(), counts.end());
std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) {
- if (depthOfDependencies[a.first] != depthOfDependencies[b.first]) {
- return depthOfDependencies[a.first] < depthOfDependencies[b.first];
- }
if (a.second != b.second) {
return a.second > b.second;
}
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 99305acb2..3f76a4421 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1322,14 +1322,14 @@ public:
int64_t getS64LEB();
uint64_t getUPtrLEB();
+ bool getBasicType(int32_t code, Type& out);
+ bool getBasicHeapType(int64_t code, HeapType& out);
// Read a value and get a type for it.
Type getType();
// Get a type given the initial S32LEB has already been read, and is provided.
Type getType(int initial);
HeapType getHeapType();
- Mutability getMutability();
- Field getField();
Type getConcreteType();
Name getInlineString();
void verifyInt8(int8_t x);
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 4188c438d..b61fe68a6 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -315,6 +315,9 @@ public:
// But converting raw TypeID is more dangerous, so make it explicit
explicit HeapType(TypeID id) : id(id) {}
+ // Choose an arbitrary heap type as the default.
+ constexpr HeapType() : HeapType(func) {}
+
HeapType(Signature signature);
HeapType(const Struct& struct_);
HeapType(Struct&& struct_);
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 730129892..49d7128dd 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1444,45 +1444,91 @@ uint64_t WasmBinaryBuilder::getUPtrLEB() {
return wasm.memory.is64() ? getU64LEB() : getU32LEB();
}
+bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) {
+ switch (code) {
+ case BinaryConsts::EncodedType::i32:
+ out = Type::i32;
+ return true;
+ case BinaryConsts::EncodedType::i64:
+ out = Type::i64;
+ return true;
+ case BinaryConsts::EncodedType::f32:
+ out = Type::f32;
+ return true;
+ case BinaryConsts::EncodedType::f64:
+ out = Type::f64;
+ return true;
+ case BinaryConsts::EncodedType::v128:
+ out = Type::v128;
+ return true;
+ case BinaryConsts::EncodedType::funcref:
+ out = Type::funcref;
+ return true;
+ case BinaryConsts::EncodedType::externref:
+ out = Type::externref;
+ return true;
+ case BinaryConsts::EncodedType::anyref:
+ out = Type::anyref;
+ return true;
+ case BinaryConsts::EncodedType::eqref:
+ out = Type::eqref;
+ return true;
+ case BinaryConsts::EncodedType::i31ref:
+ // FIXME: for now, force all inputs to be nullable
+ out = Type(HeapType::i31, Nullable);
+ return true;
+ case BinaryConsts::EncodedType::dataref:
+ // FIXME: for now, force all inputs to be nullable
+ out = Type(HeapType::data, Nullable);
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool WasmBinaryBuilder::getBasicHeapType(int64_t code, HeapType& out) {
+ switch (code) {
+ case BinaryConsts::EncodedHeapType::func:
+ out = HeapType::func;
+ return true;
+ case BinaryConsts::EncodedHeapType::extern_:
+ out = HeapType::ext;
+ return true;
+ case BinaryConsts::EncodedHeapType::any:
+ out = HeapType::any;
+ return true;
+ case BinaryConsts::EncodedHeapType::eq:
+ out = HeapType::eq;
+ return true;
+ case BinaryConsts::EncodedHeapType::i31:
+ out = HeapType::i31;
+ return true;
+ case BinaryConsts::EncodedHeapType::data:
+ out = HeapType::data;
+ return true;
+ default:
+ return false;
+ }
+}
+
Type WasmBinaryBuilder::getType(int initial) {
// Single value types are negative; signature indices are non-negative
if (initial >= 0) {
// TODO: Handle block input types properly.
return getSignatureByTypeIndex(initial).results;
}
+ Type type;
+ if (getBasicType(initial, type)) {
+ return type;
+ }
switch (initial) {
// None only used for block signatures. TODO: Separate out?
case BinaryConsts::EncodedType::Empty:
return Type::none;
- case BinaryConsts::EncodedType::i32:
- return Type::i32;
- case BinaryConsts::EncodedType::i64:
- return Type::i64;
- case BinaryConsts::EncodedType::f32:
- return Type::f32;
- case BinaryConsts::EncodedType::f64:
- return Type::f64;
- case BinaryConsts::EncodedType::v128:
- return Type::v128;
- case BinaryConsts::EncodedType::funcref:
- return Type::funcref;
- case BinaryConsts::EncodedType::externref:
- return Type::externref;
- case BinaryConsts::EncodedType::anyref:
- return Type::anyref;
- case BinaryConsts::EncodedType::eqref:
- return Type::eqref;
case BinaryConsts::EncodedType::nullable:
- return Type(getHeapType(), Nullable);
case BinaryConsts::EncodedType::nonnullable:
// FIXME: for now, force all inputs to be nullable
return Type(getHeapType(), Nullable);
- case BinaryConsts::EncodedType::i31ref:
- // FIXME: for now, force all inputs to be nullable
- return Type(HeapType::BasicHeapType::i31, Nullable);
- case BinaryConsts::EncodedType::dataref:
- // FIXME: for now, force all inputs to be nullable
- return Type(HeapType::BasicHeapType::data, Nullable);
case BinaryConsts::EncodedType::rtt_n: {
auto depth = getU32LEB();
auto heapType = getHeapType();
@@ -1508,54 +1554,15 @@ HeapType WasmBinaryBuilder::getHeapType() {
}
return types[type];
}
- switch (type) {
- case BinaryConsts::EncodedHeapType::func:
- return HeapType::func;
- case BinaryConsts::EncodedHeapType::extern_:
- return HeapType::ext;
- case BinaryConsts::EncodedHeapType::any:
- return HeapType::any;
- case BinaryConsts::EncodedHeapType::eq:
- return HeapType::eq;
- case BinaryConsts::EncodedHeapType::i31:
- return HeapType::i31;
- case BinaryConsts::EncodedHeapType::data:
- return HeapType::data;
- default:
- throwError("invalid wasm heap type: " + std::to_string(type));
+ HeapType ht;
+ if (getBasicHeapType(type, ht)) {
+ return ht;
+ } else {
+ throwError("invalid wasm heap type: " + std::to_string(type));
}
WASM_UNREACHABLE("unexpected type");
}
-Mutability WasmBinaryBuilder::getMutability() {
- switch (getU32LEB()) {
- case 0:
- return Immutable;
- case 1:
- return Mutable;
- default:
- throw ParseException("Expected 0 or 1 for mutability");
- }
-}
-
-Field WasmBinaryBuilder::getField() {
- // The value may be a general wasm type, or one of the types only possible in
- // a field.
- auto initial = getS32LEB();
- if (initial == BinaryConsts::EncodedType::i8) {
- auto mutable_ = getMutability();
- return Field(Field::i8, mutable_);
- }
- if (initial == BinaryConsts::EncodedType::i16) {
- auto mutable_ = getMutability();
- return Field(Field::i16, mutable_);
- }
- // It's a regular wasm value.
- auto type = getType(initial);
- auto mutable_ = getMutability();
- return Field(type, mutable_);
-}
-
Type WasmBinaryBuilder::getConcreteType() {
auto type = getType();
if (!type.isConcrete()) {
@@ -1643,37 +1650,121 @@ void WasmBinaryBuilder::readTypes() {
BYN_TRACE("== readTypes\n");
size_t numTypes = getU32LEB();
BYN_TRACE("num: " << numTypes << std::endl);
+ TypeBuilder builder(numTypes);
+
+ auto makeType = [&](int32_t typeCode) {
+ Type type;
+ if (getBasicType(typeCode, type)) {
+ return type;
+ }
+
+ switch (typeCode) {
+ case BinaryConsts::EncodedType::nullable:
+ case BinaryConsts::EncodedType::nonnullable: {
+ // FIXME: for now, force all inputs to be nullable
+ int64_t htCode = getS64LEB(); // TODO: Actually s33
+ HeapType ht;
+ if (getBasicHeapType(htCode, ht)) {
+ return Type(ht, Nullable);
+ }
+ if (size_t(htCode) >= numTypes) {
+ throwError("invalid type index: " + std::to_string(htCode));
+ }
+ return builder.getTempRefType(size_t(htCode), Nullable);
+ }
+ case BinaryConsts::EncodedType::rtt_n:
+ case BinaryConsts::EncodedType::rtt: {
+ auto depth = typeCode == BinaryConsts::EncodedType::rtt ? Rtt::NoDepth
+ : getU32LEB();
+ int64_t htCode = getS64LEB(); // TODO: Actually s33
+ HeapType ht;
+ if (getBasicHeapType(htCode, ht)) {
+ return Type(Rtt(depth, ht));
+ }
+ if (size_t(htCode) >= numTypes) {
+ throwError("invalid type index: " + std::to_string(htCode));
+ }
+ return builder.getTempRttType(htCode, depth);
+ }
+ default:
+ throwError("unexpected type index: " + std::to_string(typeCode));
+ }
+ WASM_UNREACHABLE("unexpected type");
+ };
+
+ auto readType = [&]() { return makeType(getS32LEB()); };
+
+ auto readSignatureDef = [&]() {
+ std::vector<Type> params;
+ std::vector<Type> results;
+ size_t numParams = getU32LEB();
+ BYN_TRACE("num params: " << numParams << std::endl);
+ for (size_t j = 0; j < numParams; j++) {
+ params.push_back(readType());
+ }
+ auto numResults = getU32LEB();
+ BYN_TRACE("num results: " << numResults << std::endl);
+ for (size_t j = 0; j < numResults; j++) {
+ results.push_back(readType());
+ }
+ return Signature(builder.getTempTupleType(params),
+ builder.getTempTupleType(results));
+ };
+
+ auto readMutability = [&]() {
+ switch (getU32LEB()) {
+ case 0:
+ return Immutable;
+ case 1:
+ return Mutable;
+ default:
+ throw ParseException("Expected 0 or 1 for mutability");
+ }
+ };
+
+ auto readFieldDef = [&]() {
+ // The value may be a general wasm type, or one of the types only possible
+ // in a field.
+ auto typeCode = getS32LEB();
+ if (typeCode == BinaryConsts::EncodedType::i8) {
+ auto mutable_ = readMutability();
+ return Field(Field::i8, mutable_);
+ }
+ if (typeCode == BinaryConsts::EncodedType::i16) {
+ auto mutable_ = readMutability();
+ return Field(Field::i16, mutable_);
+ }
+ // It's a regular wasm value.
+ auto type = makeType(typeCode);
+ auto mutable_ = readMutability();
+ return Field(type, mutable_);
+ };
+
+ auto readStructDef = [&]() {
+ FieldList fields;
+ size_t numFields = getU32LEB();
+ BYN_TRACE("num fields: " << numFields << std::endl);
+ for (size_t j = 0; j < numFields; j++) {
+ fields.push_back(readFieldDef());
+ }
+ return Struct(std::move(fields));
+ };
+
for (size_t i = 0; i < numTypes; i++) {
BYN_TRACE("read one\n");
auto form = getS32LEB();
if (form == BinaryConsts::EncodedType::Func) {
- std::vector<Type> params;
- std::vector<Type> results;
- size_t numParams = getU32LEB();
- BYN_TRACE("num params: " << numParams << std::endl);
- for (size_t j = 0; j < numParams; j++) {
- params.push_back(getConcreteType());
- }
- auto numResults = getU32LEB();
- BYN_TRACE("num results: " << numResults << std::endl);
- for (size_t j = 0; j < numResults; j++) {
- results.push_back(getConcreteType());
- }
- types.emplace_back(Signature(Type(params), Type(results)));
+ builder.setHeapType(i, readSignatureDef());
} else if (form == BinaryConsts::EncodedType::Struct) {
- FieldList fields;
- size_t numFields = getU32LEB();
- BYN_TRACE("num fields: " << numFields << std::endl);
- for (size_t j = 0; j < numFields; j++) {
- fields.push_back(getField());
- }
- types.emplace_back(Struct(fields));
+ builder.setHeapType(i, readStructDef());
} else if (form == BinaryConsts::EncodedType::Array) {
- types.emplace_back(Array(getField()));
+ builder.setHeapType(i, Array(readFieldDef()));
} else {
throwError("bad type form " + std::to_string(form));
}
}
+
+ types = builder.build();
}
Name WasmBinaryBuilder::getFunctionName(Index index) {
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 87dd2b289..4936bc3ff 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -1304,7 +1304,6 @@ void Canonicalizer::makeAncestorsFixedPoint() {
std::vector<Canonicalizer::Item> Canonicalizer::getOrderedItems() {
// Topologically sort the Types and HeapTypes so that all children are
// canonicalized before their parents.
-
std::vector<TypeID> sorted;
std::unordered_set<TypeID> seen;