Skip to content

Commit 260b8ee

Browse files
authored
[ctor-eval] Eval and store changes to globals (#4430)
This is necessary for being able to optimize real-world code, as it lets us use the stack pointer for example. With this PR we allow changes to globals, and we simply store the final state of the global in the global at the end. Basically the same as we do for memory, but for globals. Remove a test that now fails ("imported2"). Replace it with a nicer test of saving the values of globals. Also add a test for an imported global, which we do not allow (we never did, but I don't see a test for it).
1 parent 8c0f53d commit 260b8ee

13 files changed

+56
-66
lines changed

src/tools/wasm-ctor-eval.cpp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,6 @@ class EvallingGlobalManager {
6262

6363
void seal() { sealed = true; }
6464

65-
// for equality purposes, we just care about the globals
66-
// and whether they have changed
67-
bool operator==(const EvallingGlobalManager& other) {
68-
return globals == other.globals;
69-
}
70-
bool operator!=(const EvallingGlobalManager& other) {
71-
return !(*this == other);
72-
}
73-
7465
Literals& operator[](Name name) {
7566
if (dangerousGlobals.count(name) > 0) {
7667
std::string extra;
@@ -110,6 +101,15 @@ class EvallingGlobalManager {
110101
}
111102

112103
Iterator end() { return Iterator(); }
104+
105+
// Receives a module and applies the state of globals here into the globals
106+
// in that module.
107+
void applyToModule(Module& wasm) {
108+
Builder builder(wasm);
109+
for (const auto& [name, value] : globals) {
110+
wasm.getGlobal(name)->init = builder.makeConstantExpression(value);
111+
}
112+
}
113113
};
114114

115115
class EvallingModuleInstance
@@ -220,6 +220,8 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
220220
if (!memory.empty()) {
221221
applyMemoryToModule();
222222
}
223+
224+
instance->globals.applyToModule(*wasm);
223225
}
224226

225227
void init(Module& wasm_, EvallingModuleInstance& instance_) override {
@@ -499,9 +501,6 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
499501
// TODO: if we knew priorities, we could reorder?
500502
for (auto& ctor : ctors) {
501503
std::cerr << "trying to eval " << ctor << '\n';
502-
// snapshot globals (note that STACKTOP might be modified, but should
503-
// be returned, so that works out)
504-
auto globalsBefore = instance.globals;
505504
Export* ex = wasm.getExportOrNull(ctor);
506505
if (!ex) {
507506
Fatal() << "export not found: " << ctor;
@@ -514,10 +513,6 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
514513
std::cerr << " ...stopping since could not eval: " << fail.why << "\n";
515514
return;
516515
}
517-
if (instance.globals != globalsBefore) {
518-
std::cerr << " ...stopping since globals modified\n";
519-
return;
520-
}
521516
std::cerr << " ...success on " << ctor << ".\n";
522517

523518
// Success, the entire function was evalled! Apply the results of
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
(module
2+
(import "import" "global" (global $imported i32))
3+
(func $test1 (export "test1")
4+
;; This should be safe to eval in theory, but the imported global stops us,
5+
;; so this function will not be optimized out.
6+
;; TODO: perhaps if we never use that global that is ok?
7+
)
8+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(module
2+
(type $none_=>_none (func))
3+
(export "test1" (func $test1))
4+
(func $test1
5+
(nop)
6+
)
7+
)

test/ctor-eval/globals.wast

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(module
2+
(global $g1 (mut i32) (i32.const 10))
3+
(global $g2 (mut i32) (i32.const 20))
4+
(func $test1 (export "test1")
5+
(global.set $g1 (i32.const 30))
6+
(global.set $g2 (i32.const 40))
7+
(global.set $g1 (i32.const 50)) ;; this overrides the previous 30
8+
)
9+
(func $keepalive (export "keepalive") (result i32)
10+
;; Keep the globals alive so we can see their values.
11+
(i32.add
12+
(global.get $g1)
13+
(global.get $g2)
14+
)
15+
)
16+
)

test/ctor-eval/globals.wast.ctors

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test1

test/ctor-eval/globals.wast.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(module
2+
(type $none_=>_i32 (func (result i32)))
3+
(global $g1 (mut i32) (i32.const 50))
4+
(global $g2 (mut i32) (i32.const 40))
5+
(export "keepalive" (func $keepalive))
6+
(func $keepalive (result i32)
7+
(i32.add
8+
(global.get $g1)
9+
(global.get $g2)
10+
)
11+
)
12+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test1

0 commit comments

Comments
 (0)