diff options
author | Alon Zakai <azakai@google.com> | 2022-02-03 14:23:49 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-03 22:23:49 +0000 |
commit | 880c765ab9a4124f708da57329dcbe07c1ca9fa3 (patch) | |
tree | 0b2d7f53b816155253e6fa469ca9e58f8e5c7f56 /test/ctor-eval/gc-2.wast | |
parent | e6f15747d1e3557cfff87c3149e91e3dbd0ff6c7 (diff) | |
download | binaryen-880c765ab9a4124f708da57329dcbe07c1ca9fa3.tar.gz binaryen-880c765ab9a4124f708da57329dcbe07c1ca9fa3.tar.bz2 binaryen-880c765ab9a4124f708da57329dcbe07c1ca9fa3.zip |
[Wasm GC] [ctor-eval] Evaluate and serialize GC data (#4491)
This ended up simpler than I thought. We can simply emit global and
local data as we go, creating globals as necessary to contain GC data,
and referring to them using global.get later. That will ensure that
data identity works (things referring to the same object in the interpreter
will refer to the same object when the wasm is loaded). In more detail,
each live GC item is created in a "defining global", a global that is
immutable and of the precise type of that data. Then we just read from
that location in any place that wants to refer to that data. That is,
something like
function foo() {
var x = Bar(10);
var y = Bar(20);
var z = x;
z.value++; // first object now contains 11
...
}
will be evalled into something like
var define$0 = Bar(11); // note the ++ has taken effect here
var define$1 = Bar(20);
function foo() {
var x = define$0;
var y = define$1;
var z = define$0;
...
}
This PR should handle everything but "cycles", that is, GC data that at
runtime ends up forming a loop. Leaving that for later work (not sure
how urgent it is to fix).
Diffstat (limited to 'test/ctor-eval/gc-2.wast')
-rw-r--r-- | test/ctor-eval/gc-2.wast | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/test/ctor-eval/gc-2.wast b/test/ctor-eval/gc-2.wast new file mode 100644 index 000000000..fed45abac --- /dev/null +++ b/test/ctor-eval/gc-2.wast @@ -0,0 +1,54 @@ +(module + (type $struct (struct_subtype (field i32) data)) + + (import "import" "import" (func $import (param anyref))) + + ;; This struct is created in an immutable global, but it has the wrong type. + ;; We will create a new defining global for it that has the proper type, and + ;; read from it here. (This is necessary as when the global is used elsewhere + ;; we want to get the right type from the global.get.) + (global $global1 (ref any) + (struct.new $struct + (i32.const 1337) + ) + ) + + ;; Test reordering of globals. This global will be written a value that is + ;; actually defined after it. To handle that, we must create it earlier than + ;; this global. + (global $global2 (mut (ref null $struct)) + (ref.null $struct) + ) + + ;; This global is perfect to be a defining global (immutable, right type), but + ;; because of an earlier use, we will end up defining it earlier on, and + ;; reading it here. + (global $global3 (ref $struct) + (struct.new $struct + (i32.const 9999) + ) + ) + + (func "test1" + (global.set $global2 + (global.get $global3) + ) + ) + + (func "keepalive" (result i32) + (select + (struct.get $struct 0 + (ref.cast_static $struct + (global.get $global1) + ) + ) + (struct.get $struct 0 + (global.get $global2) + ) + (struct.get $struct 0 + (global.get $global3) + ) + ) + ) +) + |