Skip to content

Commit 777d33d

Browse files
authored
Emscripten stack simplification (#1870)
This takes advantage of the recent memory simplification in emscripten, where JS static allocation is done at compile time. That means we know the stack's initial location at compile time, and can apply it. This is the binaryen side of that: * asm2wasm support for asm.js globals with an initial value var X = Y; where Y is not 0 (which is what the stack now is). * wasm-emscripten-finalize support for a flag --initial-stack-pointer=X, and remove the old code to import the stack's initial location.
1 parent cbb24eb commit 777d33d

22 files changed

+82
-40
lines changed

auto_update_tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def update_lld_tests():
8787
if ext != '.out' and not os.path.exists(out_path):
8888
continue
8989
cmd = (WASM_EMSCRIPTEN_FINALIZE +
90-
[wast_path, '-S', '--global-base=568'] + ext_args)
90+
[wast_path, '-S', '--global-base=568', '--initial-stack-pointer=16384'] + ext_args)
9191
actual = run_command(cmd)
9292
with open(out_path, 'w') as o:
9393
o.write(actual)

scripts/test/lld.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_wasm_emscripten_finalize():
3838
continue
3939

4040
cmd = (WASM_EMSCRIPTEN_FINALIZE +
41-
[wast_path, '-S', '--global-base=568'] + ext_args)
41+
[wast_path, '-S', '--global-base=568', '--initial-stack-pointer=16384'] + ext_args)
4242
actual = run_command(cmd)
4343

4444
if not os.path.exists(expected_file):

src/asm2wasm.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,16 @@ class Asm2WasmBuilder {
426426
std::map<IString, MappedGlobal> mappedGlobals;
427427

428428
private:
429-
void allocateGlobal(IString name, Type type) {
429+
void allocateGlobal(IString name, Type type, Literal value=Literal()) {
430430
assert(mappedGlobals.find(name) == mappedGlobals.end());
431+
if (value.type == none) {
432+
value = Literal::makeZero(type);
433+
}
431434
mappedGlobals.emplace(name, MappedGlobal(type));
432435
wasm.addGlobal(builder.makeGlobal(
433436
name,
434437
type,
435-
LiteralUtils::makeZero(type, wasm),
438+
builder.makeConst(value),
436439
Builder::Mutable
437440
));
438441
}
@@ -986,8 +989,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
986989
Ref value = pair[1];
987990
if (value->isNumber()) {
988991
// global int
989-
assert(value->getNumber() == 0);
990-
allocateGlobal(name, Type::i32);
992+
allocateGlobal(name, Type::i32, Literal(int32_t(value->getInteger())));
991993
} else if (value[0] == BINARY) {
992994
// int import
993995
assert(value[1] == OR && value[3]->isNumber() && value[3]->getNumber() == 0);

src/tools/wasm-emscripten-finalize.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ using namespace cashew;
3636
using namespace wasm;
3737

3838
int main(int argc, const char *argv[]) {
39+
const uint64_t INVALID_BASE = -1;
40+
3941
std::string infile;
4042
std::string outfile;
4143
std::string inputSourceMapFilename;
@@ -46,7 +48,8 @@ int main(int argc, const char *argv[]) {
4648
bool debugInfo = false;
4749
bool legalizeJavaScriptFFI = true;
4850
unsigned numReservedFunctionPointers = 0;
49-
uint64_t globalBase;
51+
uint64_t globalBase = INVALID_BASE;
52+
uint64_t initialStackPointer = INVALID_BASE;
5053
Options options("wasm-emscripten-finalize",
5154
"Performs Emscripten-specific transforms on .wasm files");
5255
options
@@ -75,11 +78,16 @@ int main(int argc, const char *argv[]) {
7578
const std::string &argument) {
7679
numReservedFunctionPointers = std::stoi(argument);
7780
})
78-
.add("--global-base", "", "Where lld started to place globals",
81+
.add("--global-base", "", "The address at which static globals were placed",
7982
Options::Arguments::One,
8083
[&globalBase](Options*, const std::string&argument ) {
8184
globalBase = std::stoull(argument);
8285
})
86+
.add("--initial-stack-pointer", "", "The initial location of the stack pointer",
87+
Options::Arguments::One,
88+
[&initialStackPointer](Options*, const std::string&argument ) {
89+
initialStackPointer = std::stoull(argument);
90+
})
8391

8492
.add("--input-source-map", "-ism", "Consume source map from the specified file",
8593
Options::Arguments::One,
@@ -141,6 +149,12 @@ int main(int argc, const char *argv[]) {
141149
uint32_t dataSize = 0;
142150

143151
if (!isSideModule) {
152+
if (globalBase == INVALID_BASE) {
153+
Fatal() << "globalBase must be set";
154+
}
155+
if (initialStackPointer == INVALID_BASE) {
156+
Fatal() << "initialStackPointer must be set";
157+
}
144158
Export* dataEndExport = wasm.getExport("__data_end");
145159
if (dataEndExport == nullptr) {
146160
Fatal() << "__data_end export not found";
@@ -189,7 +203,7 @@ int main(int argc, const char *argv[]) {
189203
} else {
190204
generator.generateRuntimeFunctions();
191205
generator.generateMemoryGrowthFunction();
192-
generator.generateStackInitialization();
206+
generator.generateStackInitialization(initialStackPointer);
193207
// emscripten calls this by default for side libraries so we only need
194208
// to include in as a static ctor for main module case.
195209
if (wasm.getExportOrNull("__post_instantiate")) {

src/wasm-emscripten.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EmscriptenGlueGenerator {
3636

3737
void generateRuntimeFunctions();
3838
Function* generateMemoryGrowthFunction();
39-
void generateStackInitialization();
39+
void generateStackInitialization(Address addr);
4040

4141
// Create thunks for use with emscripten Runtime.dynCall. Creates one for each
4242
// signature in the indirect function table.

src/wasm/wasm-emscripten.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,19 +156,9 @@ Function* EmscriptenGlueGenerator::generateMemoryGrowthFunction() {
156156
return growFunction;
157157
}
158158

159-
void EmscriptenGlueGenerator::generateStackInitialization() {
160-
// Replace a global with a constant initial value with an imported
161-
// initial value, which emscripten JS will send us.
162-
// TODO: with mutable imported globals, we can avoid adding another
163-
// global for the import.
164-
Builder builder(wasm);
165-
auto* import = builder.makeGlobal(STACK_INIT, i32, nullptr, Builder::Immutable);
166-
import->module = ENV;
167-
import->base = STACKTOP;
168-
wasm.addGlobal(import);
159+
void EmscriptenGlueGenerator::generateStackInitialization(Address addr) {
169160
auto* stackPointer = getStackPointerGlobal();
170-
assert(stackPointer->init->is<Const>());
171-
stackPointer->init = builder.makeGetGlobal(import->name, i32);
161+
stackPointer->init->cast<Const>()->value = Literal(int32_t(addr));
172162
}
173163

174164
static bool hasI64ResultOrParam(FunctionType* ft) {

test/lld/duplicate_imports.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@
99
(type $legaltype$puts2 (func (param i32 i32) (result i32)))
1010
(type $legaltype$invoke_ffd (func (param i32 f64 f64) (result f64)))
1111
(type $legaltype$invoke_ffd2 (func (param i32 f64 f64) (result f64)))
12-
(import "env" "STACKTOP" (global $stack$init i32))
1312
(import "env" "puts" (func $puts1 (param i32) (result i32)))
1413
(import "env" "puts" (func $legalimport$puts2 (param i32 i32) (result i32)))
1514
(import "env" "invoke_ffd" (func $legalimport$invoke_ffd (param i32 f64 f64) (result f64)))
1615
(import "env" "invoke_ffd" (func $legalimport$invoke_ffd2 (param i32 f64 f64) (result f64)))
1716
(memory $0 2)
1817
(data (i32.const 568) "Hello, world\00")
1918
(table $0 1 1 funcref)
20-
(global $global$0 (mut i32) (global.get $stack$init))
19+
(global $global$0 (mut i32) (i32.const 16384))
2120
(global $global$1 i32 (i32.const 66128))
2221
(global $global$2 i32 (i32.const 581))
2322
(export "memory" (memory $0))

test/lld/em_asm.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@
77
(type $FUNCSIG$ii (func (param i32) (result i32)))
88
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
99
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
10-
(import "env" "STACKTOP" (global $stack$init i32))
1110
(import "env" "emscripten_asm_const_i" (func $emscripten_asm_const_i (param i32) (result i32)))
1211
(import "env" "emscripten_asm_const_iii" (func $emscripten_asm_const_iii (param i32 i32 i32) (result i32)))
1312
(import "env" "emscripten_asm_const_ii" (func $emscripten_asm_const_ii (param i32 i32) (result i32)))
1413
(memory $0 2)
1514
(data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00")
1615
(table $0 1 1 funcref)
17-
(global $global$0 (mut i32) (global.get $stack$init))
16+
(global $global$0 (mut i32) (i32.const 16384))
1817
(global $global$1 i32 (i32.const 66192))
1918
(global $global$2 i32 (i32.const 652))
2019
(export "memory" (memory $0))

test/lld/em_asm_table.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
(type $FUNCSIG$vii (func (param i32 i32)))
55
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
66
(import "env" "memory" (memory $0 8192))
7-
(import "env" "STACKTOP" (global $stack$init i32))
87
(import "env" "emscripten_log" (func $fimport$0 (param i32 i32)))
98
(import "env" "emscripten_asm_const_iii" (func $emscripten_asm_const_iii (param i32 i32 i32) (result i32)))
109
(table $0 159609 funcref)
1110
(elem (i32.const 1) $fimport$0 $emscripten_asm_const_iii)
12-
(global $global$0 (mut i32) (global.get $stack$init))
11+
(global $global$0 (mut i32) (i32.const 16384))
1312
(global $global$1 i32 (i32.const 1048))
1413
(export "__data_end" (global $global$1))
1514
(export "stackSave" (func $stackSave))

test/lld/hello_world.wast.mem.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
(type $1 (func (result i32)))
44
(type $2 (func))
55
(type $FUNCSIG$ii (func (param i32) (result i32)))
6-
(import "env" "STACKTOP" (global $stack$init i32))
76
(import "env" "puts" (func $puts (param i32) (result i32)))
87
(memory $0 2)
98
(table $0 1 1 funcref)
10-
(global $global$0 (mut i32) (global.get $stack$init))
9+
(global $global$0 (mut i32) (i32.const 16384))
1110
(global $global$1 i32 (i32.const 66128))
1211
(global $global$2 i32 (i32.const 581))
1312
(export "memory" (memory $0))

test/lld/hello_world.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
(type $1 (func (result i32)))
44
(type $2 (func))
55
(type $FUNCSIG$ii (func (param i32) (result i32)))
6-
(import "env" "STACKTOP" (global $stack$init i32))
76
(import "env" "puts" (func $puts (param i32) (result i32)))
87
(memory $0 2)
98
(data (i32.const 568) "Hello, world\00")
109
(table $0 1 1 funcref)
11-
(global $global$0 (mut i32) (global.get $stack$init))
10+
(global $global$0 (mut i32) (i32.const 16384))
1211
(global $global$1 i32 (i32.const 66128))
1312
(global $global$2 i32 (i32.const 581))
1413
(export "memory" (memory $0))

test/lld/init.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
(module
22
(type $0 (func))
33
(type $1 (func (result i32)))
4-
(import "env" "STACKTOP" (global $stack$init i32))
54
(memory $0 2)
65
(data (i32.const 568) "\00\00\00\00\00\00\00\00")
76
(table $0 1 1 funcref)
8-
(global $global$0 (mut i32) (global.get $stack$init))
7+
(global $global$0 (mut i32) (i32.const 16384))
98
(global $global$1 i32 (i32.const 66112))
109
(global $global$2 i32 (i32.const 576))
1110
(export "memory" (memory $0))

test/lld/recursive.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
(type $1 (func (result i32)))
44
(type $2 (func))
55
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
6-
(import "env" "STACKTOP" (global $stack$init i32))
76
(import "env" "printf" (func $printf (param i32 i32) (result i32)))
87
(memory $0 2)
98
(data (i32.const 568) "%d:%d\n\00Result: %d\n\00")
109
(table $0 1 1 funcref)
11-
(global $global$0 (mut i32) (global.get $stack$init))
10+
(global $global$0 (mut i32) (i32.const 16384))
1211
(global $global$1 i32 (i32.const 66128))
1312
(global $global$2 i32 (i32.const 587))
1413
(export "memory" (memory $0))

test/lld/reserved_func_ptr.wast.jscall.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
(type $FUNCSIG$v (func))
1919
(type $FUNCSIG$vii (func (param i32 i32)))
2020
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
21-
(import "env" "STACKTOP" (global $stack$init i32))
2221
(import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32)))
2322
(import "env" "jsCall_ddi" (func $jsCall_ddi (param i32 f64 i32) (result f64)))
2423
(import "env" "jsCall_fffi" (func $jsCall_fffi (param i32 f32 f32 i32) (result f32)))
@@ -29,7 +28,7 @@
2928
(memory $0 2)
3029
(table $0 21 21 funcref)
3130
(elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii $jsCall_ddi_0 $jsCall_ddi_1 $jsCall_ddi_2 $jsCall_fffi_0 $jsCall_fffi_1 $jsCall_fffi_2 $jsCall_iii_0 $jsCall_iii_1 $jsCall_iii_2 $jsCall_v_0 $jsCall_v_1 $jsCall_v_2 $jsCall_vi_0 $jsCall_vi_1 $jsCall_vi_2 $jsCall_viii_0 $jsCall_viii_1 $jsCall_viii_2)
32-
(global $global$0 (mut i32) (global.get $stack$init))
31+
(global $global$0 (mut i32) (i32.const 16384))
3332
(global $global$1 i32 (i32.const 66112))
3433
(global $global$2 i32 (i32.const 568))
3534
(export "memory" (memory $0))

test/lld/reserved_func_ptr.wast.out

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
(type $6 (func (param i32) (result i32)))
99
(type $FUNCSIG$ii (func (param i32) (result i32)))
1010
(type $FUNCSIG$viii (func (param i32 i32 i32)))
11-
(import "env" "STACKTOP" (global $stack$init i32))
1211
(import "env" "_Z4atoiPKc" (func $_Z4atoiPKc (param i32) (result i32)))
1312
(memory $0 2)
1413
(table $0 3 3 funcref)
1514
(elem (i32.const 1) $_Z18address_taken_funciii $_Z19address_taken_func2iii)
16-
(global $global$0 (mut i32) (global.get $stack$init))
15+
(global $global$0 (mut i32) (i32.const 16384))
1716
(global $global$1 i32 (i32.const 66112))
1817
(global $global$2 i32 (i32.const 568))
1918
(export "memory" (memory $0))

test/unit.asm.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ function asm(global, env, buffer) {
3030
var HEAPF32 = new global.Float32Array(buffer);
3131
var HEAPF64 = new global.Float64Array(buffer);
3232

33+
var nonZero = 1337;
34+
3335
function big_negative() {
3436
var temp = 0.0;
3537
temp = +-2147483648;
@@ -785,6 +787,7 @@ function asm(global, env, buffer) {
785787
emterpretify_assertions_safeHeap();
786788
call_emscripten_log();
787789
mod_detectSign(1.0, 2.31, 9.78);
790+
nonZero = nonZero + 1 | 0;
788791
}
789792

790793
function v() {

test/unit.fromasm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
(global $Int (mut i32) (i32.const 0))
2727
(global $Double (mut f64) (f64.const 0))
2828
(global $n (mut i32) (global.get $n$asm2wasm$import))
29+
(global $nonZero (mut i32) (i32.const 1337))
2930
(global $exportedNumber i32 (i32.const 42))
3031
(export "big_negative" (func $big_negative))
3132
(export "pick" (func $big_negative))
@@ -1162,6 +1163,12 @@
11621163
)
11631164
)
11641165
)
1166+
(global.set $nonZero
1167+
(i32.add
1168+
(global.get $nonZero)
1169+
(i32.const 1)
1170+
)
1171+
)
11651172
)
11661173
(func $vi (; 55 ;) (; has Stack IR ;) (param $0 i32)
11671174
(nop)

test/unit.fromasm.clamp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
(global $Int (mut i32) (i32.const 0))
2525
(global $Double (mut f64) (f64.const 0))
2626
(global $n (mut i32) (global.get $n$asm2wasm$import))
27+
(global $nonZero (mut i32) (i32.const 1337))
2728
(global $exportedNumber i32 (i32.const 42))
2829
(export "big_negative" (func $big_negative))
2930
(export "pick" (func $big_negative))
@@ -1238,6 +1239,12 @@
12381239
)
12391240
)
12401241
)
1242+
(global.set $nonZero
1243+
(i32.add
1244+
(global.get $nonZero)
1245+
(i32.const 1)
1246+
)
1247+
)
12411248
)
12421249
(func $vi (; 57 ;) (; has Stack IR ;) (param $0 i32)
12431250
(nop)

test/unit.fromasm.clamp.no-opts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
(global $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
3232
(global $n (mut i32) (global.get $n$asm2wasm$import))
3333
(global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
34+
(global $nonZero (mut i32) (i32.const 1337))
3435
(global $exportedNumber i32 (i32.const 42))
3536
(export "big_negative" (func $big_negative))
3637
(export "pick" (func $exportMe))
@@ -2215,6 +2216,12 @@
22152216
(f64.const 9.78)
22162217
)
22172218
)
2219+
(global.set $nonZero
2220+
(i32.add
2221+
(global.get $nonZero)
2222+
(i32.const 1)
2223+
)
2224+
)
22182225
)
22192226
(func $v (; 83 ;)
22202227
(nop)

test/unit.fromasm.imprecise

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
(global $Int (mut i32) (i32.const 0))
2323
(global $Double (mut f64) (f64.const 0))
2424
(global $n (mut i32) (global.get $n$asm2wasm$import))
25+
(global $nonZero (mut i32) (i32.const 1337))
2526
(global $exportedNumber i32 (i32.const 42))
2627
(export "big_negative" (func $big_negative))
2728
(export "pick" (func $big_negative))
@@ -1141,6 +1142,12 @@
11411142
(f64.const 1)
11421143
)
11431144
)
1145+
(global.set $nonZero
1146+
(i32.add
1147+
(global.get $nonZero)
1148+
(i32.const 1)
1149+
)
1150+
)
11441151
)
11451152
(func $vi (; 54 ;) (; has Stack IR ;) (param $0 i32)
11461153
(nop)

test/unit.fromasm.imprecise.no-opts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
(global $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
3232
(global $n (mut i32) (global.get $n$asm2wasm$import))
3333
(global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
34+
(global $nonZero (mut i32) (i32.const 1337))
3435
(global $exportedNumber i32 (i32.const 42))
3536
(export "big_negative" (func $big_negative))
3637
(export "pick" (func $exportMe))
@@ -2100,6 +2101,12 @@
21002101
(f64.const 9.78)
21012102
)
21022103
)
2104+
(global.set $nonZero
2105+
(i32.add
2106+
(global.get $nonZero)
2107+
(i32.const 1)
2108+
)
2109+
)
21032110
)
21042111
(func $v (; 78 ;)
21052112
(nop)

0 commit comments

Comments
 (0)