diff options
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 29 | ||||
-rw-r--r-- | src/wasm-builder.h | 4 | ||||
-rw-r--r-- | test/lit/ctor-eval/extern.wast | 59 |
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: ) |