Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/ir/gc-type-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,15 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) {
//
// TODO: use in more places
inline std::optional<Field> getField(HeapType type, Index index = 0) {
if (type.isStruct()) {
return type.getStruct().fields[index];
} else if (type.isArray()) {
return type.getArray().element;
switch (type.getKind()) {
case HeapTypeKind::Struct:
return type.getStruct().fields[index];
case HeapTypeKind::Array:
return type.getArray().element;
case HeapTypeKind::Func:
case HeapTypeKind::Cont:
case HeapTypeKind::Basic:
break;
}
return {};
}
Expand Down
21 changes: 14 additions & 7 deletions src/ir/subtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,20 @@ struct SubTypes {
for (auto type : types) {
HeapType basic;
auto share = type.getShared();
if (type.isStruct()) {
basic = HeapTypes::struct_.getBasic(share);
} else if (type.isArray()) {
basic = HeapTypes::array.getBasic(share);
} else {
assert(type.isSignature());
basic = HeapTypes::func.getBasic(share);
switch (type.getKind()) {
case HeapTypeKind::Func:
basic = HeapTypes::func.getBasic(share);
break;
case HeapTypeKind::Struct:
basic = HeapTypes::struct_.getBasic(share);
break;
case HeapTypeKind::Array:
basic = HeapTypes::array.getBasic(share);
break;
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
auto& basicDepth = depths[basic];
basicDepth = std::max(basicDepth, depths[type] + 1);
Expand Down
51 changes: 32 additions & 19 deletions src/passes/TypeMerging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,34 +544,47 @@ bool shapeEq(HeapType a, HeapType b) {
if (a.isShared() != b.isShared()) {
return false;
}
if (a.isStruct() && b.isStruct()) {
return shapeEq(a.getStruct(), b.getStruct());
}
if (a.isArray() && b.isArray()) {
return shapeEq(a.getArray(), b.getArray());
auto aKind = a.getKind();
auto bKind = b.getKind();
if (aKind != bKind) {
return false;
}
if (a.isSignature() && b.isSignature()) {
return shapeEq(a.getSignature(), b.getSignature());
switch (aKind) {
case HeapTypeKind::Func:
return shapeEq(a.getSignature(), b.getSignature());
case HeapTypeKind::Struct:
return shapeEq(a.getStruct(), b.getStruct());
case HeapTypeKind::Array:
return shapeEq(a.getArray(), b.getArray());
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
return false;
}

size_t shapeHash(HeapType a) {
size_t digest = hash(a.isOpen());
rehash(digest, a.isShared());
if (a.isStruct()) {
rehash(digest, 0);
hash_combine(digest, shapeHash(a.getStruct()));
} else if (a.isArray()) {
rehash(digest, 1);
hash_combine(digest, shapeHash(a.getArray()));
} else if (a.isSignature()) {
rehash(digest, 2);
hash_combine(digest, shapeHash(a.getSignature()));
} else {
WASM_UNREACHABLE("unexpected kind");
auto kind = a.getKind();
rehash(digest, kind);
switch (kind) {
case HeapTypeKind::Func:
hash_combine(digest, shapeHash(a.getSignature()));
return digest;
case HeapTypeKind::Struct:
hash_combine(digest, shapeHash(a.getStruct()));
return digest;
case HeapTypeKind::Array:
hash_combine(digest, shapeHash(a.getArray()));
return digest;
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
break;
}
return digest;
WASM_UNREACHABLE("unexpected kind");
}

bool shapeEq(const Struct& a, const Struct& b) {
Expand Down
17 changes: 11 additions & 6 deletions src/passes/TypeSSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,17 @@ struct TypeSSA : public Pass {
for (Index i = 0; i < num; i++) {
auto* curr = newsToModify[i];
auto oldType = curr->type.getHeapType();
if (oldType.isStruct()) {
builder[i] = oldType.getStruct();
} else if (oldType.isArray()) {
builder[i] = oldType.getArray();
} else {
WASM_UNREACHABLE("unexpected type kind");
switch (oldType.getKind()) {
case HeapTypeKind::Struct:
builder[i] = oldType.getStruct();
break;
case HeapTypeKind::Array:
builder[i] = oldType.getArray();
break;
case HeapTypeKind::Func:
case HeapTypeKind::Cont:
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
builder[i].subTypeOf(oldType);
builder[i].setShared(oldType.getShared());
Expand Down
38 changes: 24 additions & 14 deletions src/passes/Unsubtyping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,21 +264,31 @@ struct Unsubtyping
if (super.isBasic()) {
continue;
}
if (type.isStruct()) {
const auto& fields = type.getStruct().fields;
const auto& superFields = super.getStruct().fields;
for (size_t i = 0, size = superFields.size(); i < size; ++i) {
noteSubtype(fields[i].type, superFields[i].type);
switch (type.getKind()) {
case HeapTypeKind::Func: {
auto sig = type.getSignature();
auto superSig = super.getSignature();
noteSubtype(superSig.params, sig.params);
noteSubtype(sig.results, superSig.results);
break;
}
} else if (type.isArray()) {
auto elem = type.getArray().element;
noteSubtype(elem.type, super.getArray().element.type);
} else {
assert(type.isSignature());
auto sig = type.getSignature();
auto superSig = super.getSignature();
noteSubtype(superSig.params, sig.params);
noteSubtype(sig.results, superSig.results);
case HeapTypeKind::Struct: {
const auto& fields = type.getStruct().fields;
const auto& superFields = super.getStruct().fields;
for (size_t i = 0, size = superFields.size(); i < size; ++i) {
noteSubtype(fields[i].type, superFields[i].type);
}
break;
}
case HeapTypeKind::Array: {
auto elem = type.getArray().element;
noteSubtype(elem.type, super.getArray().element.type);
break;
}
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
}

Expand Down
119 changes: 66 additions & 53 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,28 +291,35 @@ void TranslateToFuzzReader::setupHeapTypes() {
auto eq = HeapTypes::eq.getBasic(share);
auto any = HeapTypes::any.getBasic(share);
auto func = HeapTypes::func.getBasic(share);
if (type.isStruct()) {
interestingHeapSubTypes[struct_].push_back(type);
interestingHeapSubTypes[eq].push_back(type);
interestingHeapSubTypes[any].push_back(type);

// Note the mutable fields.
auto& fields = type.getStruct().fields;
for (Index i = 0; i < fields.size(); i++) {
if (fields[i].mutable_) {
mutableStructFields.push_back(StructField{type, i});
switch (type.getKind()) {
case HeapTypeKind::Func:
interestingHeapSubTypes[func].push_back(type);
break;
case HeapTypeKind::Struct: {
interestingHeapSubTypes[struct_].push_back(type);
interestingHeapSubTypes[eq].push_back(type);
interestingHeapSubTypes[any].push_back(type);
// Note the mutable fields.
auto& fields = type.getStruct().fields;
for (Index i = 0; i < fields.size(); i++) {
if (fields[i].mutable_) {
mutableStructFields.push_back(StructField{type, i});
}
}
break;
}
} else if (type.isArray()) {
interestingHeapSubTypes[array].push_back(type);
interestingHeapSubTypes[eq].push_back(type);
interestingHeapSubTypes[any].push_back(type);

if (type.getArray().element.mutable_) {
mutableArrays.push_back(type);
}
} else if (type.isSignature()) {
interestingHeapSubTypes[func].push_back(type);
case HeapTypeKind::Array:
interestingHeapSubTypes[array].push_back(type);
interestingHeapSubTypes[eq].push_back(type);
interestingHeapSubTypes[any].push_back(type);
if (type.getArray().element.mutable_) {
mutableArrays.push_back(type);
}
break;
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
WASM_UNREACHABLE("unexpected kind");
}
}

Expand Down Expand Up @@ -2757,43 +2764,49 @@ Expression* TranslateToFuzzReader::makeCompoundRef(Type type) {
return funcContext ? make(type) : makeTrivial(type);
};

if (heapType.isSignature()) {
return makeRefFuncConst(type);
} else if (type.isStruct()) {
auto& fields = heapType.getStruct().fields;
std::vector<Expression*> values;
// If there is a nondefaultable field, we must provide the value and not
// depend on defaults. Also do that randomly half the time.
if (std::any_of(
fields.begin(),
fields.end(),
[&](const Field& field) { return !field.type.isDefaultable(); }) ||
oneIn(2)) {
for (auto& field : fields) {
values.push_back(makeChild(field.type));
}
// Add more nesting manually, as we can easily get exponential blowup
// here. This nesting makes it much less likely for a recursive data
// structure to end up as a massive tree of struct.news, since the nesting
// limitation code at the top of this function will kick in.
if (!values.empty()) {
// Subtract 1 since if there is a single value there cannot be
// exponential blowup.
nester.add(values.size() - 1);
switch (heapType.getKind()) {
case HeapTypeKind::Func:
return makeRefFuncConst(type);
case HeapTypeKind::Struct: {
auto& fields = heapType.getStruct().fields;
std::vector<Expression*> values;
// If there is a nondefaultable field, we must provide the value and not
// depend on defaults. Also do that randomly half the time.
if (std::any_of(
fields.begin(),
fields.end(),
[&](const Field& field) { return !field.type.isDefaultable(); }) ||
oneIn(2)) {
for (auto& field : fields) {
values.push_back(makeChild(field.type));
}
// Add more nesting manually, as we can easily get exponential blowup
// here. This nesting makes it much less likely for a recursive data
// structure to end up as a massive tree of struct.news, since the
// nesting limitation code at the top of this function will kick in.
if (!values.empty()) {
// Subtract 1 since if there is a single value there cannot be
// exponential blowup.
nester.add(values.size() - 1);
}
}
return builder.makeStructNew(heapType, values);
}
return builder.makeStructNew(heapType, values);
} else if (type.isArray()) {
auto element = heapType.getArray().element;
Expression* init = nullptr;
if (!element.type.isDefaultable() || oneIn(2)) {
init = makeChild(element.type);
case HeapTypeKind::Array: {
auto element = heapType.getArray().element;
Expression* init = nullptr;
if (!element.type.isDefaultable() || oneIn(2)) {
init = makeChild(element.type);
}
auto* count = builder.makeConst(int32_t(upTo(MAX_ARRAY_SIZE)));
return builder.makeArrayNew(type.getHeapType(), count, init);
}
auto* count = builder.makeConst(int32_t(upTo(MAX_ARRAY_SIZE)));
return builder.makeArrayNew(type.getHeapType(), count, init);
} else {
WASM_UNREACHABLE("bad user-defined ref type");
case HeapTypeKind::Cont:
WASM_UNREACHABLE("TODO: cont");
case HeapTypeKind::Basic:
break;
}
WASM_UNREACHABLE("unexpected kind");
}

Expression* TranslateToFuzzReader::makeStringNewArray() {
Expand Down
Loading