Skip to content
Merged
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
59 changes: 34 additions & 25 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2487,32 +2487,55 @@ void TranslateToFuzzReader::mutateJSBoundary() {
if (new_ == Type::unreachable) {
new_ = Type(old.getHeapType().getBottom(), NonNullable);
}
assert(Type::isSubType(new_, old));

// Find all heap types between the old and new, starting from new.
auto oldHeapType = old.getHeapType();
auto oldExactness = old.getExactness();
auto newHeapType = new_.getHeapType();
assert(HeapType::isSubType(newHeapType, oldHeapType));
std::vector<HeapType> options;
auto newExactness = new_.getExactness();
std::vector<std::pair<HeapType, Exactness>> options;
while (1) {
options.push_back(newHeapType);
options.push_back({newHeapType, newExactness});
// We cannot look at a bottom type's supers (there can be many, and the
// getSuperType() API doesn't return them), but can use
// interestingHeapSubTypes: any subtype of old is valid.
if (newHeapType.isBottom()) {
for (auto type : interestingHeapSubTypes[oldHeapType]) {
options.push_back(type);
// We can only do this when the old exactness is inexact: if old was
// (exact $A) then the only valid subtypes are (exact $A) itself, and
// the bottom type.
if (oldExactness == Inexact) {
for (auto type : interestingHeapSubTypes[oldHeapType]) {
options.push_back({type, Inexact});
options.push_back({type, Exact});
}
options.push_back({oldHeapType, Inexact});
}
// Regardless of the old exactness, it is valid to add the old type as
// exact (unless the old type was a basic type).
if (!oldHeapType.isBasic()) {
options.push_back({oldHeapType, Exact});
}
break;
}
// Continue until we reach the old type.
if (newHeapType == oldHeapType) {
// Continue until we reach the old type and exactness.
if (newHeapType == oldHeapType && newExactness == oldExactness) {
break;
}
if (newExactness == Exact) {
// We are not at the old type and exactness yet (or we would have just
// stopped). Remove exactness, as the only exact result that is valid is
// newHeapType itself. That is, if the actual output is (exact $B) then
// we cannot return (exact $A) for some supertype $A, as that would
// break subtyping.
newExactness = Inexact;
continue;
}
auto next = newHeapType.getSuperType();
assert(next);
newHeapType = *next;
}
newHeapType = pick(options);
auto [heapType, exactness] = pick(options);

// Pick the nullability.
auto oldNullability = old.getNullability();
Expand All @@ -2521,23 +2544,9 @@ void TranslateToFuzzReader::mutateJSBoundary() {
newNullability = getNullability();
}

// Pick the exactness.
auto oldExactness = old.getExactness();
auto newExactness = new_.getExactness();
// We can only be exact if we are using the new heap type: that type is
// exactly what is sent here, and no intermediate heap type would be valid.
// For example, given $A :> $B :> $C, then maybeRefine($A, exact $C) can
// return exact $C, but cannot return exact $B.
//
// Also, basic heap types cannot be exact.
if (newHeapType != new_.getHeapType() || newHeapType.isBasic()) {
newExactness = Inexact;
} else if (newExactness != oldExactness) {
// TODO: once getExactness() is fixed (see there), use that
newExactness = oneIn(2) ? Exact : Inexact;
}

return Type(newHeapType, newNullability, newExactness);
auto refined = Type(heapType, newNullability, exactness);
assert(Type::isSubType(refined, old));
return refined;
};

// Given a set of types (all params or all results), and an index among them,
Expand Down
Loading