summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/wasm-ctor-eval.cpp29
-rw-r--r--src/wasm-builder.h4
-rw-r--r--test/lit/ctor-eval/extern.wast59
3 files changed, 88 insertions, 4 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 00bceac8f..195a5350f 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -572,13 +572,28 @@ public:
// If |possibleDefiningGlobal| is provided, it is the name of a global that we
// are in the init expression of, and which can be reused as defining global,
// if the other conditions are suitable.
- Expression* getSerialization(const Literal& value,
+ Expression* getSerialization(Literal value,
Name possibleDefiningGlobal = Name()) {
Builder builder(*wasm);
+ // If this is externalized then we want to inspect the inner data, handle
+ // that, and emit a ref.externalize around it as needed. To simplify the
+ // logic here, we save the original (possible externalized) value, and then
+ // look at the internals from here on out.
+ Literal original = value;
+ if (value.type.isRef() && value.type.getHeapType() == HeapType::ext) {
+ value = value.internalize();
+
+ // We cannot serialize truly external things, only data and i31s.
+ assert(value.isData() || value.type.getHeapType() == HeapType::i31);
+ }
+
+ // GC data (structs and arrays) must be handled with the special global-
+ // creating logic later down. But MVP types as well as i31s (even
+ // externalized i31s) can be handled by the general makeConstantExpression
+ // logic (which knows how to handle externalization, for i31s).
if (!value.isData()) {
- // This can be handled normally.
- return builder.makeConstantExpression(value);
+ return builder.makeConstantExpression(original);
}
// This is GC data, which we must handle in a more careful way.
@@ -637,7 +652,13 @@ public:
// Refer to this GC allocation by reading from the global that is
// designated to contain it.
- return builder.makeGlobalGet(definingGlobal, value.type);
+ Expression* ret = builder.makeGlobalGet(definingGlobal, value.type);
+ if (original != value) {
+ // The original is externalized.
+ assert(original.type.getHeapType() == HeapType::ext);
+ ret = builder.makeRefAs(ExternExternalize, ret);
+ }
+ return ret;
}
Expression* getSerialization(const Literals& values,
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index cbdd7abf7..8b34d6933 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -1155,6 +1155,10 @@ public:
}
return makeStringConst(string);
}
+ if (type.isRef() && type.getHeapType() == HeapType::ext) {
+ return makeRefAs(ExternExternalize,
+ makeConstantExpression(value.internalize()));
+ }
TODO_SINGLE_COMPOUND(type);
WASM_UNREACHABLE("unsupported constant expression");
}
diff --git a/test/lit/ctor-eval/extern.wast b/test/lit/ctor-eval/extern.wast
new file mode 100644
index 000000000..1bd738380
--- /dev/null
+++ b/test/lit/ctor-eval/extern.wast
@@ -0,0 +1,59 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; RUN: wasm-ctor-eval %s --ctors=test1,test2 --kept-exports=test1,test2 --quiet -all -S -o - | filecheck %s
+
+(module
+ ;; CHECK: (type $array (array (mut i8)))
+ (type $array (array (mut i8)))
+
+ ;; CHECK: (type $none_=>_externref (func (result externref)))
+
+ ;; CHECK: (global $ctor-eval$global (ref $array) (array.new_fixed $array
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: ))
+
+ ;; CHECK: (export "test1" (func $test1_0))
+ (export "test1" (func $test1))
+ ;; CHECK: (export "test2" (func $test2_0))
+ (export "test2" (func $test2))
+
+ (func $test1 (result externref)
+ ;; This will remain almost the same, even though we eval it, since the
+ ;; serialization of an externalized i31 is what is written here. But the add
+ ;; will be evalled out.
+ (extern.externalize
+ (i31.new
+ (i32.add
+ (i32.const 41)
+ (i32.const 1)
+ )
+ )
+ )
+ )
+
+ (func $test2 (result externref)
+ ;; This will be evalled into an externalization of a global.get.
+ (extern.externalize
+ (array.new_fixed $array
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ )
+)
+
+;; CHECK: (func $test1_0 (type $none_=>_externref) (result externref)
+;; CHECK-NEXT: (extern.externalize
+;; CHECK-NEXT: (i31.new
+;; CHECK-NEXT: (i32.const 42)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: )
+;; CHECK-NEXT: )
+
+;; CHECK: (func $test2_0 (type $none_=>_externref) (result externref)
+;; CHECK-NEXT: (extern.externalize
+;; CHECK-NEXT: (global.get $ctor-eval$global)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: )