Skip to content

Commit 247884e

Browse files
authored
Add a RoundTrip pass (#2516)
This pass writes and reads the module. This shows the effects of converting to and back from the binary format, and will be useful in testing dwarf debug support (where we'll need to see that writing and reading a module preserves debug info properly).
1 parent 72bacfd commit 247884e

8 files changed

Lines changed: 111 additions & 2 deletions

File tree

scripts/fuzz_opt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ def write_commands(commands, filename):
496496
["--reorder-functions"],
497497
["--reorder-locals"],
498498
["--flatten", "--rereloop"],
499+
["--roundtrip"],
499500
["--rse"],
500501
["--simplify-locals"],
501502
["--simplify-locals-nonesting"],

src/ir/module-utils.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ inline Event* copyEvent(Event* event, Module& out) {
105105
return ret;
106106
}
107107

108-
inline void copyModule(Module& in, Module& out) {
109-
// we use names throughout, not raw points, so simple copying is fine
108+
inline void copyModule(const Module& in, Module& out) {
109+
// we use names throughout, not raw pointers, so simple copying is fine
110110
// for everything *but* expressions
111111
for (auto& curr : in.functionTypes) {
112112
out.addFunctionType(make_unique<FunctionType>(*curr));
@@ -136,6 +136,20 @@ inline void copyModule(Module& in, Module& out) {
136136
out.debugInfoFileNames = in.debugInfoFileNames;
137137
}
138138

139+
inline void clearModule(Module& wasm) {
140+
wasm.functionTypes.clear();
141+
wasm.exports.clear();
142+
wasm.functions.clear();
143+
wasm.globals.clear();
144+
wasm.events.clear();
145+
wasm.table.segments.clear();
146+
wasm.memory.segments.clear();
147+
wasm.start = Name();
148+
wasm.userSections.clear();
149+
wasm.debugInfoFileNames.clear();
150+
wasm.updateMaps();
151+
}
152+
139153
// Renaming
140154

141155
// Rename functions along with all their uses.

src/passes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ set(passes_SOURCES
4747
PrintCallGraph.cpp
4848
PrintFeatures.cpp
4949
PrintFunctionMap.cpp
50+
RoundTrip.cpp
5051
StackIR.cpp
5152
Strip.cpp
5253
StripTargetFeatures.cpp

src/passes/RoundTrip.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2019 WebAssembly Community Group participants
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
//
18+
// Write the module to binary, and load it from there. This is useful in
19+
// testing to check for the effects of roundtripping in a single wasm-opt
20+
// parameter.
21+
//
22+
23+
#ifdef _WIN32
24+
#include <io.h>
25+
#endif
26+
27+
#include <cstdlib>
28+
#include <vector>
29+
30+
#include "ir/module-utils.h"
31+
#include "pass.h"
32+
#include "support/file.h"
33+
#include "wasm-io.h"
34+
#include "wasm.h"
35+
36+
using namespace std;
37+
38+
namespace wasm {
39+
40+
struct RoundTrip : public Pass {
41+
void run(PassRunner* runner, Module* module) override {
42+
std::string templateName = "byn_round_trip_XXXXXX";
43+
std::vector<char> buffer(templateName.begin(), templateName.end());
44+
buffer.push_back(0);
45+
#ifndef _WIN32
46+
auto fd = mkstemp(buffer.data());
47+
WASM_UNUSED(fd);
48+
std::string tempName(buffer.begin(), buffer.end());
49+
#else
50+
std::string tempName = _mktemp(buffer.data());
51+
#endif
52+
// Write
53+
ModuleWriter writer;
54+
writer.setBinary(true);
55+
writer.setDebugInfo(runner->options.debugInfo);
56+
writer.write(*module, tempName);
57+
// Read
58+
Module newModule;
59+
ModuleReader reader;
60+
reader.read(tempName, newModule);
61+
// Clean up
62+
std::remove(tempName.c_str());
63+
// Swap in
64+
ModuleUtils::clearModule(*module);
65+
ModuleUtils::copyModule(newModule, *module);
66+
}
67+
};
68+
69+
Pass* createRoundTripPass() { return new RoundTrip(); }
70+
71+
} // namespace wasm

src/passes/pass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ void PassRegistry::registerPasses() {
276276
createReReloopPass);
277277
registerPass(
278278
"rse", "remove redundant local.sets", createRedundantSetEliminationPass);
279+
registerPass("roundtrip",
280+
"write the module to binary, then read it",
281+
createRoundTripPass);
279282
registerPass("safe-heap",
280283
"instrument loads and stores to check for invalid behavior",
281284
createSafeHeapPass);

src/passes/passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Pass* createReorderFunctionsPass();
9494
Pass* createReorderLocalsPass();
9595
Pass* createReReloopPass();
9696
Pass* createRedundantSetEliminationPass();
97+
Pass* createRoundTripPass();
9798
Pass* createSafeHeapPass();
9899
Pass* createSimplifyLocalsPass();
99100
Pass* createSimplifyGlobalsPass();

test/passes/roundtrip.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(module
2+
(type $0 (func))
3+
(export "foo" (func $0))
4+
(func $0 (; 0 ;)
5+
(unreachable)
6+
)
7+
)

test/passes/roundtrip.wast

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(module
2+
(func "foo"
3+
;; binaryen skips unreachable code while reading the binary format
4+
(unreachable)
5+
(nop)
6+
(nop)
7+
(nop)
8+
(nop)
9+
(nop)
10+
)
11+
)

0 commit comments

Comments
 (0)