diff options
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 30 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input-gc.wast | 33 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input-gc.wast.ctors | 1 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input-gc.wast.out | 19 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast | 13 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast.ctors | 2 | ||||
-rw-r--r-- | test/ctor-eval/ignore-external-input.wast.out | 8 | ||||
-rw-r--r-- | test/ctor-eval/params.wast | 4 |
8 files changed, 95 insertions, 15 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 871d4eac0..f49a54833 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -510,13 +510,30 @@ EvalCtorOutcome evalCtor(EvallingModuleInstance& instance, auto& wasm = instance.wasm; auto* func = wasm.getFunction(funcName); - // We don't know the values of parameters, so give up if there are any. - // TODO: Maybe use ignoreExternalInput? - if (func->getNumParams() > 0) { + // We don't know the values of parameters, so give up if there are any, unless + // we are ignoring them. + if (func->getNumParams() > 0 && !ignoreExternalInput) { std::cout << " ...stopping due to params\n"; + std::cout << RECOMMENDATION "consider --ignore-external-input"; return EvalCtorOutcome(); } + // If there are params, we are ignoring them (or we would have quit earlier); + // set those up with zeros. + // TODO: Have a safer option here, either + // 1. Statically or dynamically stop evalling when a param is actually + // used, or + // 2. Split out --ignore-external-input into separate flags. + LiteralList params; + for (Index i = 0; i < func->getNumParams(); i++) { + auto type = func->getLocalType(i); + if (!LiteralUtils::canMakeZero(type)) { + std::cout << " ...stopping due to non-zeroable param\n"; + return EvalCtorOutcome(); + } + params.push_back(Literal::makeZero(type)); + } + // We want to handle the form of the global constructor function in LLVM. That // looks like this: // @@ -540,7 +557,7 @@ EvalCtorOutcome evalCtor(EvallingModuleInstance& instance, if (auto* block = func->body->dynCast<Block>()) { // Go through the items in the block and try to execute them. We do all this // in a single function scope for all the executions. - EvallingModuleInstance::FunctionScope scope(func, LiteralList()); + EvallingModuleInstance::FunctionScope scope(func, params); EvallingModuleInstance::RuntimeExpressionRunner expressionRunner( instance, scope, instance.maxDepth); @@ -549,7 +566,7 @@ EvalCtorOutcome evalCtor(EvallingModuleInstance& instance, // the same idea as applyToModule() - we must only do it after an entire // atomic "chunk" has been processed, we do not want partial updates from // an item in the block that we only partially evalled. - EvallingModuleInstance::FunctionScope appliedScope(func, LiteralList()); + EvallingModuleInstance::FunctionScope appliedScope(func, params); Literals results; Index successes = 0; @@ -647,9 +664,10 @@ EvalCtorOutcome evalCtor(EvallingModuleInstance& instance, // Otherwise, we don't recognize a pattern that allows us to do partial // evalling. So simply call the entire function at once and see if we can // optimize that. + Literals results; try { - results = instance.callFunction(funcName, LiteralList()); + results = instance.callFunction(funcName, params); } catch (FailToEvalException& fail) { std::cout << " ...stopping since could not eval: " << fail.why << "\n"; return EvalCtorOutcome(); diff --git a/test/ctor-eval/ignore-external-input-gc.wast b/test/ctor-eval/ignore-external-input-gc.wast new file mode 100644 index 000000000..16558336c --- /dev/null +++ b/test/ctor-eval/ignore-external-input-gc.wast @@ -0,0 +1,33 @@ +(module + (global $global1 (mut i32) (i32.const 10)) + (global $global2 (mut i32) (i32.const 20)) + + (func "test1" (param $any (ref null any)) + ;; This is ok to call: when ignoring external input we assume 0 for the + ;; parameters, and this parameter is nullable. + (drop + (local.get $any) + ) + (global.set $global1 + (i32.const 11) + ) + ) + + (func "test2" (param $any (ref any)) + ;; This is *not* ok to call: when ignoring external input we assume 0 for + ;; the parameters, and this parameter is not nullable. + (drop + (local.get $any) + ) + (global.set $global2 + (i32.const 22) + ) + ) + + (func "keepalive" (result i32) + (i32.add + (global.get $global1) + (global.get $global2) + ) + ) +) diff --git a/test/ctor-eval/ignore-external-input-gc.wast.ctors b/test/ctor-eval/ignore-external-input-gc.wast.ctors new file mode 100644 index 000000000..e4b83fcba --- /dev/null +++ b/test/ctor-eval/ignore-external-input-gc.wast.ctors @@ -0,0 +1 @@ +test1,test2 diff --git a/test/ctor-eval/ignore-external-input-gc.wast.out b/test/ctor-eval/ignore-external-input-gc.wast.out new file mode 100644 index 000000000..3e7a8f429 --- /dev/null +++ b/test/ctor-eval/ignore-external-input-gc.wast.out @@ -0,0 +1,19 @@ +(module + (type $ref|any|_=>_none (func (param (ref any)))) + (type $none_=>_i32 (func (result i32))) + (global $global1 (mut i32) (i32.const 11)) + (global $global2 (mut i32) (i32.const 20)) + (export "test2" (func $1)) + (export "keepalive" (func $2)) + (func $1 (param $any (ref any)) + (global.set $global2 + (i32.const 22) + ) + ) + (func $2 (result i32) + (i32.add + (global.get $global1) + (global.get $global2) + ) + ) +) diff --git a/test/ctor-eval/ignore-external-input.wast b/test/ctor-eval/ignore-external-input.wast index 0849c67ab..562011605 100644 --- a/test/ctor-eval/ignore-external-input.wast +++ b/test/ctor-eval/ignore-external-input.wast @@ -8,7 +8,7 @@ (import "wasi_snapshot_preview1" "something_else" (func $wasi_something_else (result i32))) (memory 256 256) - (data (i32.const 0) "aaaaaaaaaaaaaaaaaaaaaaaaaaaa") ;; the final 4 'a's will remain + (data (i32.const 0) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") ;; the final 4 'a's will remain (func "test1" ;; This is ok to call: when ignoring external input we assume there is no @@ -48,6 +48,15 @@ ) ) + (func "test2b" (param $x i32) + ;; This is also ok to call: when ignoring external input we assume the + ;; args are zeros. + (i32.store + (i32.const 24) ;; the result (0) will be written to address 24 + (local.get $x) + ) + ) + (func "test3" ;; This is *not* ok to call, and we will *not* reach the final store after ;; this call. This function will not be evalled and will remain in the @@ -56,7 +65,7 @@ (call $wasi_something_else) ) (i32.store - (i32.const 24) + (i32.const 28) (i32.const 100) ) ) diff --git a/test/ctor-eval/ignore-external-input.wast.ctors b/test/ctor-eval/ignore-external-input.wast.ctors index c7060ede5..7b57e4b82 100644 --- a/test/ctor-eval/ignore-external-input.wast.ctors +++ b/test/ctor-eval/ignore-external-input.wast.ctors @@ -1 +1 @@ -test1,test2,test3 +test1,test2,test2b,test3 diff --git a/test/ctor-eval/ignore-external-input.wast.out b/test/ctor-eval/ignore-external-input.wast.out index f728afd0e..d61f2e6b9 100644 --- a/test/ctor-eval/ignore-external-input.wast.out +++ b/test/ctor-eval/ignore-external-input.wast.out @@ -3,14 +3,14 @@ (type $none_=>_none (func)) (import "wasi_snapshot_preview1" "something_else" (func $wasi_something_else (result i32))) (memory $0 256 256) - (data (i32.const 24) "aaaa") - (export "test3" (func $2)) - (func $2 + (data (i32.const 28) "aaaa") + (export "test3" (func $3)) + (func $3 (drop (call $wasi_something_else) ) (i32.store - (i32.const 24) + (i32.const 28) (i32.const 100) ) ) diff --git a/test/ctor-eval/params.wast b/test/ctor-eval/params.wast index fb70debe5..cb346bb3b 100644 --- a/test/ctor-eval/params.wast +++ b/test/ctor-eval/params.wast @@ -1,7 +1,7 @@ (module (func "test1" (param $x i32) - ;; The presence of params stops us from evalling this function (at least - ;; for now). + ;; The presence of params stops us from evalling this function, at least + ;; not with --ignore-external-input (see ignore-external-input.wast) (nop) ) ) |