diff options
author | Alon Zakai <azakai@google.com> | 2022-01-11 10:02:02 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-11 10:02:02 -0800 |
commit | 8faada66b4b175596db39a8762b7bdc687f101cf (patch) | |
tree | cda6eb1cbf733d2c20e5153e64ba129ea7bbeffc /test/ctor-eval/partial.wast | |
parent | 7796031f0ab4fb785fbc4335bdd211421b9e79b6 (diff) | |
download | binaryen-8faada66b4b175596db39a8762b7bdc687f101cf.tar.gz binaryen-8faada66b4b175596db39a8762b7bdc687f101cf.tar.bz2 binaryen-8faada66b4b175596db39a8762b7bdc687f101cf.zip |
[ctor-eval] Partial evaluation (#4438)
This lets us eval part of a function but not all, which is necessary to handle
real-world things like __wasm_call_ctors in LLVM output, as that is the
single ctor that is exported and it has calls to the actual ctors.
To do so, we look for a toplevel block and execute its items one by one, in
a FunctionScope. If we stop in the middle, then we are performing a partial
eval. In that case, we only remove the parts of the function that we removed,
and we also serialize the locals whose values we read from the
FunctionScope.
For example, consider this:
function foo() {
return 10;
}
function __wasm_call_ctors() {
var x;
x = foo();
x++;
// We stop evalling here.
import1();
import2(x);
}
We can eval x = foo() and x++, but we must stop evalling when
we reach the first of those imports. The partially-evalled function
then looks like this:
function __wasm_call_ctors() {
var x;
x = 11;
import1();
import2(x);
}
That is, we evalled two lines of executing code and simply removed
them, and then we wrote out the value of the local at that point, and then
the rest of the code in the function is as it used to be.
Diffstat (limited to 'test/ctor-eval/partial.wast')
-rw-r--r-- | test/ctor-eval/partial.wast | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/test/ctor-eval/partial.wast b/test/ctor-eval/partial.wast new file mode 100644 index 000000000..bbff880e7 --- /dev/null +++ b/test/ctor-eval/partial.wast @@ -0,0 +1,30 @@ +(module + (import "import" "import" (func $import)) + + (memory 256 256) + (data (i32.const 10) "_________________") + + (export "test1" $test1) + + ;; Use the function in an additional export. We should still get the same + ;; results if we call this one, so it should point to identical contents as + ;; earlier + (export "keepalive" $test1) + + (func $test1 + ;; A safe store, should alter memory + (i32.store8 (i32.const 12) (i32.const 115)) + + ;; A call to an import, which prevents evalling. + (call $import) + + ;; Another safe store, but the import call before us will stop our evalling. + ;; As a result we will only partially eval this function, applying only + ;; the first store. + ;; + ;; After optimization, the test1 export will point to a function that does + ;; not have the first store anymore. It will contain just the call to the + ;; import and then this second store. + (i32.store8 (i32.const 13) (i32.const 114)) + ) +) |