Skip to content

Commit 7e9f7f6

Browse files
authored
Add wasm-emscripten-finalize flag to separate data segments into a file (#1741)
This writes the data section into a file suitable for use with emscripten's --memory-init-file flag
1 parent 37d82ba commit 7e9f7f6

File tree

7 files changed

+103
-5
lines changed

7 files changed

+103
-5
lines changed

scripts/test/lld.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
def test_wasm_emscripten_finalize():
2525
print '\n[ checking wasm-emscripten-finalize testcases... ]\n'
2626

27-
extension_arg_map = {
28-
'.out': [],
29-
'.jscall.out': ['--emscripten-reserved-function-pointers=3'],
30-
}
31-
3227
for wast_path in files_with_pattern(options.binaryen_test, 'lld', '*.wast'):
3328
print '..', wast_path
29+
mem_file = wast_path + '.mem'
30+
extension_arg_map = {
31+
'.out': [],
32+
'.jscall.out': ['--emscripten-reserved-function-pointers=3'],
33+
'.mem.out': ['--separate-data-segments', mem_file],
34+
}
3435
for ext, ext_args in extension_arg_map.items():
3536
expected_file = wast_path + ext
3637
if ext != '.out' and not os.path.exists(expected_file):
@@ -44,6 +45,11 @@ def test_wasm_emscripten_finalize():
4445
print actual
4546
fail_with_error('output ' + expected_file + ' does not exist')
4647
fail_if_not_identical_to_file(actual, expected_file)
48+
if ext == '.mem.out':
49+
with open(mem_file) as mf:
50+
mem = mf.read()
51+
fail_if_not_identical_to_file(mem, wast_path + '.mem.mem')
52+
os.remove(mem_file)
4753

4854

4955
if __name__ == '__main__':

src/support/file.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ class Output {
5959
return out;
6060
}
6161

62+
std::ostream& write(const char* s, std::streamsize c) {
63+
return out.write(s, c);
64+
}
65+
6266
private:
6367
Output() = delete;
6468
Output(const Output &) = delete;

src/tools/wasm-emscripten-finalize.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ int main(int argc, const char *argv[]) {
4040
std::string inputSourceMapFilename;
4141
std::string outputSourceMapFilename;
4242
std::string outputSourceMapUrl;
43+
std::string dataSegmentFile;
4344
bool emitBinary = true;
4445
bool debugInfo = false;
4546
bool legalizeJavaScriptFFI = true;
@@ -94,6 +95,9 @@ int main(int argc, const char *argv[]) {
9495
.add("--output-source-map-url", "-osu", "Emit specified string as source map URL",
9596
Options::Arguments::One,
9697
[&outputSourceMapUrl](Options *o, const std::string& argument) { outputSourceMapUrl = argument; })
98+
.add("--separate-data-segments", "", "Separate data segments to a file",
99+
Options::Arguments::One,
100+
[&dataSegmentFile](Options *o, const std::string& argument) { dataSegmentFile = argument;})
97101
.add_positional("INFILE", Options::Arguments::One,
98102
[&infile](Options *o, const std::string& argument) {
99103
infile = argument;
@@ -161,6 +165,10 @@ int main(int argc, const char *argv[]) {
161165
generator.generateDynCallThunks();
162166
generator.generateJSCallThunks(numReservedFunctionPointers);
163167
std::string metadata = generator.generateEmscriptenMetadata(dataSize, initializerFunctions, numReservedFunctionPointers);
168+
if (!dataSegmentFile.empty()) {
169+
Output memInitFile(dataSegmentFile, Flags::Binary, Flags::Release);
170+
generator.separateDataSegments(&memInitFile);
171+
}
164172

165173
if (options.debug) {
166174
std::cerr << "Module after:\n";

src/wasm-emscripten.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#include "wasm.h"
2121
#include "wasm-builder.h"
22+
#include "support/file.h"
23+
2224

2325
namespace wasm {
2426

@@ -53,6 +55,8 @@ class EmscriptenGlueGenerator {
5355

5456
void fixInvokeFunctionNames();
5557

58+
void separateDataSegments(Output* outfile);
59+
5660
private:
5761
Module& wasm;
5862
Builder builder;

src/wasm/wasm-emscripten.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,4 +810,19 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
810810
return meta.str();
811811
}
812812

813+
void EmscriptenGlueGenerator::separateDataSegments(Output* outfile) {
814+
size_t lastEnd = 0;
815+
for (Memory::Segment& seg : wasm.memory.segments) {
816+
size_t offset = seg.offset->cast<Const>()->value.geti32();
817+
size_t fill = offset - lastEnd;
818+
if (fill > 0) {
819+
std::vector<char> buf(fill);
820+
outfile->write(buf.data(), fill);
821+
}
822+
outfile->write(seg.data.data(), seg.data.size());
823+
lastEnd = offset + seg.data.size();
824+
}
825+
wasm.memory.segments.clear();
826+
}
827+
813828
} // namespace wasm

test/lld/hello_world.wast.mem.mem

581 Bytes
Binary file not shown.

test/lld/hello_world.wast.mem.out

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(module
2+
(type $0 (func (param i32) (result i32)))
3+
(type $1 (func (result i32)))
4+
(type $2 (func))
5+
(type $FUNCSIG$ii (func (param i32) (result i32)))
6+
(import "env" "puts" (func $puts (param i32) (result i32)))
7+
(memory $0 2)
8+
(table $0 1 1 anyfunc)
9+
(global $global$0 (mut i32) (i32.const 66128))
10+
(global $global$1 i32 (i32.const 66128))
11+
(global $global$2 i32 (i32.const 581))
12+
(export "memory" (memory $0))
13+
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
14+
(export "main" (func $main))
15+
(export "__heap_base" (global $global$1))
16+
(export "__data_end" (global $global$2))
17+
(export "stackSave" (func $stackSave))
18+
(export "stackAlloc" (func $stackAlloc))
19+
(export "stackRestore" (func $stackRestore))
20+
(export "__growWasmMemory" (func $__growWasmMemory))
21+
(func $main (; 1 ;) (type $1) (result i32)
22+
(drop
23+
(call $puts
24+
(i32.const 568)
25+
)
26+
)
27+
(i32.const 0)
28+
)
29+
(func $__wasm_call_ctors (; 2 ;) (type $2)
30+
(nop)
31+
)
32+
(func $stackSave (; 3 ;) (result i32)
33+
(get_global $global$0)
34+
)
35+
(func $stackAlloc (; 4 ;) (param $0 i32) (result i32)
36+
(local $1 i32)
37+
(set_global $global$0
38+
(tee_local $1
39+
(i32.and
40+
(i32.sub
41+
(get_global $global$0)
42+
(get_local $0)
43+
)
44+
(i32.const -16)
45+
)
46+
)
47+
)
48+
(get_local $1)
49+
)
50+
(func $stackRestore (; 5 ;) (param $0 i32)
51+
(set_global $global$0
52+
(get_local $0)
53+
)
54+
)
55+
(func $__growWasmMemory (; 6 ;) (param $newSize i32) (result i32)
56+
(grow_memory
57+
(get_local $newSize)
58+
)
59+
)
60+
)
61+
;; METADATA: { "asmConsts": {},"staticBump": 13, "initializers": ["__wasm_call_ctors"], "declares": ["puts"], "externs": [], "implementedFunctions": ["___wasm_call_ctors","_main","_stackSave","_stackAlloc","_stackRestore","___growWasmMemory"], "exports": ["memory","__wasm_call_ctors","main","__heap_base","__data_end","stackSave","stackAlloc","stackRestore","__growWasmMemory"], "invokeFuncs": [] }

0 commit comments

Comments
 (0)