-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sourcemap support to wasm-metadce and wasm-merge #6372
Changes from all commits
206edf6
18b2d63
5a3caa4
824eda0
ad6acac
8ddd780
b37f66c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
*/ | ||
|
||
#include "module-utils.h" | ||
#include "ir/debug.h" | ||
#include "ir/intrinsics.h" | ||
#include "ir/manipulation.h" | ||
#include "ir/properties.h" | ||
|
@@ -23,17 +24,46 @@ | |
|
||
namespace wasm::ModuleUtils { | ||
|
||
// Update the file name indices when moving a set of debug locations from one | ||
// module to another. | ||
static void updateLocationSet(std::set<Function::DebugLocation>& locations, | ||
std::vector<Index>& fileIndexMap) { | ||
std::set<Function::DebugLocation> updatedLocations; | ||
|
||
for (auto iter : locations) { | ||
iter.fileIndex = fileIndexMap[iter.fileIndex]; | ||
updatedLocations.insert(iter); | ||
} | ||
locations.clear(); | ||
std::swap(locations, updatedLocations); | ||
} | ||
|
||
// Copies a function into a module. If newName is provided it is used as the | ||
// name of the function (otherwise the original name is copied). | ||
Function* copyFunction(Function* func, Module& out, Name newName) { | ||
// name of the function (otherwise the original name is copied). If fileIndexMap | ||
// is specified, it is used to rename source map filename indices when copying | ||
// the function from one module to another one. | ||
Function* copyFunction(Function* func, | ||
Module& out, | ||
Name newName, | ||
std::optional<std::vector<Index>> fileIndexMap) { | ||
auto ret = std::make_unique<Function>(); | ||
ret->name = newName.is() ? newName : func->name; | ||
ret->type = func->type; | ||
ret->vars = func->vars; | ||
ret->localNames = func->localNames; | ||
ret->localIndices = func->localIndices; | ||
ret->debugLocations = func->debugLocations; | ||
ret->body = ExpressionManipulator::copy(func->body, out); | ||
debug::copyDebugInfo(func->body, ret->body, func, ret.get()); | ||
ret->prologLocation = func->prologLocation; | ||
ret->epilogLocation = func->epilogLocation; | ||
// Update file indices if needed | ||
if (fileIndexMap) { | ||
for (auto& iter : ret->debugLocations) { | ||
iter.second.fileIndex = (*fileIndexMap)[iter.second.fileIndex]; | ||
} | ||
updateLocationSet(ret->prologLocation, *fileIndexMap); | ||
updateLocationSet(ret->epilogLocation, *fileIndexMap); | ||
} | ||
ret->module = func->module; | ||
ret->base = func->base; | ||
ret->noFullInline = func->noFullInline; | ||
|
@@ -136,8 +166,30 @@ DataSegment* copyDataSegment(const DataSegment* segment, Module& out) { | |
// Copies named toplevel module items (things of kind ModuleItemKind). See | ||
// copyModule() for something that also copies exports, the start function, etc. | ||
void copyModuleItems(const Module& in, Module& out) { | ||
// If the source module has some debug information, we first compute how | ||
// to map file name indices from this modules to file name indices in | ||
// the target module. | ||
std::optional<std::vector<Index>> fileIndexMap; | ||
if (!in.debugInfoFileNames.empty()) { | ||
std::unordered_map<std::string, Index> debugInfoFileIndices; | ||
for (Index i = 0; i < out.debugInfoFileNames.size(); i++) { | ||
debugInfoFileIndices[out.debugInfoFileNames[i]] = i; | ||
} | ||
fileIndexMap.emplace(); | ||
for (Index i = 0; i < in.debugInfoFileNames.size(); i++) { | ||
std::string file = in.debugInfoFileNames[i]; | ||
auto iter = debugInfoFileIndices.find(file); | ||
if (iter == debugInfoFileIndices.end()) { | ||
Index index = out.debugInfoFileNames.size(); | ||
out.debugInfoFileNames.push_back(file); | ||
debugInfoFileIndices[file] = index; | ||
} | ||
fileIndexMap->push_back(debugInfoFileIndices[file]); | ||
} | ||
} | ||
|
||
for (auto& curr : in.functions) { | ||
copyFunction(curr.get(), out); | ||
copyFunction(curr.get(), out, Name(), fileIndexMap); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For efficiency, how about only passing a non-nullopt ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have also added a test at the beginning of |
||
} | ||
for (auto& curr : in.globals) { | ||
copyGlobal(curr.get(), out); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -365,6 +365,9 @@ int main(int argc, const char* argv[]) { | |
bool debugInfo = false; | ||
std::string graphFile; | ||
bool dump = false; | ||
std::string inputSourceMapFilename; | ||
std::string outputSourceMapFilename; | ||
std::string outputSourceMapUrl; | ||
|
||
const std::string WasmMetaDCEOption = "wasm-opt options"; | ||
|
||
|
@@ -423,6 +426,30 @@ int main(int argc, const char* argv[]) { | |
o->extra["output"] = argument; | ||
Colors::setEnabled(false); | ||
}) | ||
.add("--input-source-map", | ||
"-ism", | ||
"Consume source map from the specified file", | ||
WasmMetaDCEOption, | ||
Options::Arguments::One, | ||
[&inputSourceMapFilename](Options* o, const std::string& argument) { | ||
inputSourceMapFilename = argument; | ||
}) | ||
.add("--output-source-map", | ||
"-osm", | ||
"Emit source map to the specified file", | ||
WasmMetaDCEOption, | ||
Options::Arguments::One, | ||
[&outputSourceMapFilename](Options* o, const std::string& argument) { | ||
outputSourceMapFilename = argument; | ||
}) | ||
.add("--output-source-map-url", | ||
"-osu", | ||
"Emit specified string as source map URL", | ||
WasmMetaDCEOption, | ||
Options::Arguments::One, | ||
[&outputSourceMapUrl](Options* o, const std::string& argument) { | ||
outputSourceMapUrl = argument; | ||
}) | ||
.add("--emit-text", | ||
"-S", | ||
"Emit text instead of binary for the output file", | ||
|
@@ -470,7 +497,7 @@ int main(int argc, const char* argv[]) { | |
ModuleReader reader; | ||
reader.setDWARF(debugInfo); | ||
try { | ||
reader.read(options.extra["infile"], wasm); | ||
reader.read(options.extra["infile"], wasm, inputSourceMapFilename); | ||
} catch (ParseException& p) { | ||
p.dump(std::cerr); | ||
Fatal() << "error in parsing wasm input"; | ||
|
@@ -578,6 +605,10 @@ int main(int argc, const char* argv[]) { | |
ModuleWriter writer; | ||
writer.setBinary(emitBinary); | ||
writer.setDebugInfo(debugInfo); | ||
if (outputSourceMapFilename.size()) { | ||
writer.setSourceMapFilename(outputSourceMapFilename); | ||
writer.setSourceMapUrl(outputSourceMapUrl); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a test for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have also updated the test for |
||
writer.write(wasm, options.extra["output"]); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | ||
|
||
;; RUN: wasm-merge %s first %s.second second -S -o - | filecheck %s --check-prefix=CHECK-TEXT | ||
;; RUN: wasm-as %s -o %t.wasm --source-map %t.map | ||
;; RUN: wasm-as %s.second -o %t.second.wasm --source-map %t.second.map | ||
;; RUN: wasm-merge %t.wasm first --input-source-map %t.map %t.second.wasm second --input-source-map %t.second.map -o %t.merged.wasm --output-source-map %t.merged.map | ||
;; RUN: wasm-dis %t.merged.wasm --source-map %t.merged.map -o - | filecheck %s --check-prefix=CHECK-BIN | ||
|
||
;; Test that sourcemap information is preserved | ||
|
||
(module | ||
;;@ a:1:1 | ||
(func (export "f") | ||
;;@ a:2:1 | ||
(nop) | ||
;;@ a:3:1 | ||
) | ||
) | ||
;; CHECK-TEXT: (type $0 (func)) | ||
|
||
;; CHECK-TEXT: (export "f" (func $0)) | ||
|
||
;; CHECK-TEXT: (export "g" (func $0_1)) | ||
|
||
;; CHECK-TEXT: ;;@ a:1:1 | ||
;; CHECK-TEXT-NEXT: (func $0 | ||
;; CHECK-TEXT-NEXT: ;;@ a:2:1 | ||
;; CHECK-TEXT-NEXT: (nop) | ||
;; CHECK-TEXT-NEXT: ;;@ a:3:1 | ||
;; CHECK-TEXT-NEXT: ) | ||
|
||
;; CHECK-TEXT: ;;@ b:1:2 | ||
;; CHECK-TEXT-NEXT: (func $0_1 | ||
;; CHECK-TEXT-NEXT: ;;@ b:2:2 | ||
;; CHECK-TEXT-NEXT: (nop) | ||
;; CHECK-TEXT-NEXT: ;;@ b:3:2 | ||
;; CHECK-TEXT-NEXT: ) | ||
|
||
;; CHECK-BIN: (type $0 (func)) | ||
|
||
;; CHECK-BIN: (export "f" (func $0)) | ||
|
||
;; CHECK-BIN: (export "g" (func $1)) | ||
|
||
;; CHECK-BIN: ;;@ a:1:1 | ||
;; CHECK-BIN-NEXT: (func $0 | ||
;; CHECK-BIN-NEXT: ;;@ a:2:1 | ||
;; CHECK-BIN-NEXT: (nop) | ||
;; CHECK-BIN-NEXT: ;;@ a:3:1 | ||
;; CHECK-BIN-NEXT: ) | ||
|
||
;; CHECK-BIN: ;;@ b:1:2 | ||
;; CHECK-BIN-NEXT: (func $1 | ||
;; CHECK-BIN-NEXT: ;;@ b:2:2 | ||
;; CHECK-BIN-NEXT: (nop) | ||
;; CHECK-BIN-NEXT: ;;@ b:3:2 | ||
;; CHECK-BIN-NEXT: ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
(module | ||
;;@ b:1:2 | ||
(func (export "g") | ||
;;@ b:2:2 | ||
(nop) | ||
;;@ b:3:2 | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment explaining what this function does.