Skip to content
Open
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,11 @@ not handle things like re-indexing of locals, and so passes that might break
DWARF are disabled by default. As a result, this mode is not suitable for a
fully optimized release build, but it can be useful for local debugging.

When rewriting line tables, surviving instructions retain their original source
intervals. Inserted instructions without an original location are marked with
line zero, rather than inheriting a neighboring source line. This does not
synthesize source-level DWARF for newly generated helper functions.

## FAQ

* Why the weird name for the project?
Expand Down
3 changes: 3 additions & 0 deletions src/passes/Asyncify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,9 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
newBody->finalize(func->getResults());
}
func->body = newBody;
// The terminal end now returns from unwinding, not from the original source
// body. In particular, its dummy return value is not a source-level return.
func->hasSyntheticEnd = true;
// Making things like returns conditional may alter types.
ReFinalize().walkFunctionInModule(func, getModule());
}
Expand Down
7 changes: 7 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,13 @@ class WasmBinaryWriter {
void trackExpressionEnd(Expression* curr, Function* func);
void trackExpressionDelimiter(Expression* curr, Function* func, size_t id);

// Track a written instruction (not an empty expression). A null expression
// denotes generated code, or the function's final end when isEnd is true.
void trackInstruction(Expression* curr,
Function* func,
BinaryLocation start,
bool isEnd = false);

// Writes code annotations into a buffer and returns it. We cannot write them
// directly into the output since we write function code first (to get the
// offsets for the annotations), and only then can write annotations, which we
Expand Down
10 changes: 8 additions & 2 deletions src/wasm-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,16 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
scratchLocals(parent.getModule()->features) {}

void visit(Expression* curr) {
auto start = o.size();
if (func) {
parent.trackExpressionStart(curr, func);
}
OverriddenVisitor<BinaryInstWriter>::visit(curr);
if (func) {
parent.trackExpressionEnd(curr, func);
if (DWARF) {
parent.trackInstruction(curr, func, start);
}
}
}

Expand All @@ -123,7 +127,9 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
void emitScopeEnd(Expression* curr);
// emit an end at the end of a function
void emitFunctionEnd();
void emitUnreachable();
// Standalone writer-inserted traps have no origin. Other traps get their
// origin from the surrounding visit(), including explicit unreachables.
void emitUnreachable(bool generated = false);
void emitUnreachableLocalSet(Index index);
void mapLocalsAndEmitHeader();

Expand Down Expand Up @@ -554,7 +560,7 @@ class BinaryenIRToBinaryWriter
}
writer.emitFunctionEnd();
}
void emitUnreachable() { writer.emitUnreachable(); }
void emitUnreachable() { writer.emitUnreachable(true); }
void emitUnreachableLocalSet(Index index) {
writer.emitUnreachableLocalSet(index);
}
Expand Down
11 changes: 11 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -2366,6 +2366,13 @@ struct BinaryLocations {
};

std::unordered_map<Function*, FunctionLocations> functions;

// Instruction origins in output order, including instructions added by the
// binary/stack IR writer. An old address of zero means no source origin.
struct InstructionLocation {
BinaryLocation oldAddr, newAddr;
};
std::vector<InstructionLocation> instructions;
};

// Forward declaration for FuncEffectsMap.
Expand Down Expand Up @@ -2485,6 +2492,10 @@ class Function : public Importable {
std::unordered_map<Expression*, BinaryLocations::DelimiterLocations>
delimiterLocations;
BinaryLocations::FunctionLocations funcLocation;
// A rewritten function may end in synthetic control flow rather than its
// original return. Keep its range for DWARF, but do not attribute the new
// terminal end instruction to the original end's source location.
bool hasSyntheticEnd = false;

// Annotations on expressions. As with debug info, we do not store these on
// Expressions as we assume most instances are unannotated, and do not want to
Expand Down
34 changes: 34 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ void WasmBinaryWriter::finishSection(int32_t start) {
item -= totalAdjustment;
}
}
for (auto& location : binaryLocations.instructions) {
location.newAddr -= totalAdjustment;
}
}
}

Expand Down Expand Up @@ -530,6 +533,7 @@ void WasmBinaryWriter::writeFunctions() {
// Do not smear any debug location from the previous function.
writeNoDebugLocation();
size_t sourceMapLocationsSizeAtFunctionStart = sourceMapLocations.size();
auto instructionLocationsStart = binaryLocations.instructions.size();
size_t sizePos = writeU32LEBPlaceholder();
size_t start = o.size();
// Emit Stack IR if present.
Expand Down Expand Up @@ -582,6 +586,11 @@ void WasmBinaryWriter::writeFunctions() {
}
}
}
for (auto i = instructionLocationsStart;
i < binaryLocations.instructions.size();
++i) {
binaryLocations.instructions[i].newAddr -= adjustmentForLEBShrinking;
}
}
// We need to track the function location if we are tracking the locations
// of expressions inside it, or, if it has code annotations (the function
Expand Down Expand Up @@ -1754,7 +1763,32 @@ void WasmBinaryWriter::trackExpressionDelimiter(Expression* curr,
// need to enable that here.
if (func && !func->expressionLocations.empty()) {
binaryLocations.delimiters[curr][id] = o.size();
auto old = func->delimiterLocations.find(curr);
auto oldAddr =
old != func->delimiterLocations.end() && id < old->second.size()
? old->second[id]
: 0;
binaryLocations.instructions.push_back({oldAddr, BinaryLocation(o.size())});
}
}

void WasmBinaryWriter::trackInstruction(Expression* curr,
Function* func,
BinaryLocation start,
bool isEnd) {
if (!func || func->expressionLocations.empty() || start == o.size()) {
return;
}
BinaryLocation oldAddr = 0;
if (curr) {
auto old = func->expressionLocations.find(curr);
if (old != func->expressionLocations.end()) {
oldAddr = isEnd ? old->second.end - 1 : old->second.start;
}
} else if (isEnd && !func->hasSyntheticEnd) {
oldAddr = func->funcLocation.end - 1;
}
binaryLocations.instructions.push_back({oldAddr, start});
}

std::optional<BufferWithRandomAccess> WasmBinaryWriter::writeCodeAnnotations() {
Expand Down
Loading
Loading