OSR entry into wasm misses some contexts
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Sep 2019 20:32:56 +0000 (20:32 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Sep 2019 20:32:56 +0000 (20:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201569

Reviewed by Yusuke Suzuki.

JSTests:

Add a new harness and wast and the generated wasm file for
testing. The idea long term is to make it easy to test by creating
a C file and converting it to a wast then modify that to produce a
test.

* wasm.yaml:
* wasm/wast-tests/harness.js: Added.
(async.runWasmFile):
* wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm: Added.
* wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wast: Added.
* wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm: Added.
* wasm/wast-tests/osr-entry-inner-loop-branch-above.wast: Added.
* wasm/wast-tests/osr-entry-inner-loop.wasm: Added.
* wasm/wast-tests/osr-entry-inner-loop.wast: Added.
* wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm: Added.
* wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wast: Added.

Source/JavaScriptCore:

This patch fixes an issue where we could fail to capture some of
our contexts when OSR entering into wasm code. Before we would
only capture the state of the block immediately surrounding the
entrance loop block header. We actually need to capture all
enclosed stacks.

Additionally, we don't need to use variables for all the captured
values. We can use a Phi and insert an upsilon just below the
captured value.

* interpreter/CallFrame.h:
* jsc.cpp:
(GlobalObject::finishCreation):
(functionCallerIsOMGCompiled):
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::emitEntryTierUpCheck):
(JSC::Wasm::AirIRGenerator::emitLoopTierUpCheck):
(JSC::Wasm::AirIRGenerator::addLoop):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::createStack):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::addConstant):
(JSC::Wasm::B3IRGenerator::emitEntryTierUpCheck):
(JSC::Wasm::B3IRGenerator::emitLoopTierUpCheck):
(JSC::Wasm::B3IRGenerator::addLoop):
(JSC::Wasm::B3IRGenerator::addEndToUnreachable):
(JSC::Wasm::dumpExpressionStack):
(JSC::Wasm::B3IRGenerator::dump):
(JSC::Wasm::B3IRGenerator::Stack::Stack): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::append): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::takeLast): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::last): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::size const): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::isEmpty const): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::convertToExpressionList): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::at const): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::variableAt const): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::shrink): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::swap): Deleted.
(JSC::Wasm::B3IRGenerator::Stack::dump const): Deleted.
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser::controlStack):

Tools:

Add new test harness mode for tests created from wast files.

* Scripts/run-jsc-stress-tests:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249661 268f45cc-cd09-0410-ab3c-d52691b4dbfc

20 files changed:
JSTests/ChangeLog
JSTests/wasm.yaml
JSTests/wasm/wast-tests/harness.js [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wast [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wast [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop.wasm [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-inner-loop.wast [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm [new file with mode: 0644]
JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wast [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/interpreter/CallFrame.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmFunctionParser.h
Source/JavaScriptCore/wasm/WasmOpcodeOrigin.cpp
Tools/ChangeLog
Tools/Scripts/run-jsc-stress-tests

index 9701b6f..10cc460 100644 (file)
@@ -1,3 +1,27 @@
+2019-09-07  Keith Miller  <keith_miller@apple.com>
+
+        OSR entry into wasm misses some contexts
+        https://bugs.webkit.org/show_bug.cgi?id=201569
+
+        Reviewed by Yusuke Suzuki.
+
+        Add a new harness and wast and the generated wasm file for
+        testing. The idea long term is to make it easy to test by creating
+        a C file and converting it to a wast then modify that to produce a
+        test.
+
+        * wasm.yaml:
+        * wasm/wast-tests/harness.js: Added.
+        (async.runWasmFile):
+        * wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm: Added.
+        * wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wast: Added.
+        * wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm: Added.
+        * wasm/wast-tests/osr-entry-inner-loop-branch-above.wast: Added.
+        * wasm/wast-tests/osr-entry-inner-loop.wasm: Added.
+        * wasm/wast-tests/osr-entry-inner-loop.wast: Added.
+        * wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm: Added.
+        * wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wast: Added.
+
 2019-09-09  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Promise resolve/reject functions should be created more efficiently
index f8711f7..697f12a 100644 (file)
@@ -21,8 +21,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-- path: wasm/self-test/
-  cmd: runWebAssemblySuite unless parseRunCommands
+- path: wasm/wast-tests/
+  cmd: runWebAssemblyWithHarness
 - path: wasm/js-api/
   cmd: runWebAssemblySuite unless parseRunCommands
 - path: wasm/noJIT/
@@ -43,6 +43,8 @@
   cmd: runWebAssemblySuite unless parseRunCommands
 - path: wasm/modules/
   cmd: runWebAssembly unless parseRunCommands
+- path: wasm/self-test/
+  cmd: runWebAssemblySuite unless parseRunCommands
 
 - path: wasm/spec-tests/address.wast.js
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/modules/run-from-wasm.wasm
   cmd: runWebAssembly
+
diff --git a/JSTests/wasm/wast-tests/harness.js b/JSTests/wasm/wast-tests/harness.js
new file mode 100644 (file)
index 0000000..20f86e5
--- /dev/null
@@ -0,0 +1,22 @@
+asyncTestStart(1);
+let context = {
+    env: globalThis,
+};
+
+globalThis.__linear_memory = new WebAssembly.Memory({ initial: 1 });
+
+async function runWasmFile(filePath) {
+    let blob = readFile(filePath, "binary");
+    let compiled;
+    try {
+        compiled = await WebAssembly.instantiate(blob, context);
+        compiled.instance.exports.test();
+    } catch (e) {
+        print(e);
+        throw e;
+    }
+    asyncTestPassed();
+}
+
+for (wasmFile of arguments)
+    runWasmFile(wasmFile);
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm
new file mode 100644 (file)
index 0000000..29df625
Binary files /dev/null and b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wasm differ
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wast b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above-no-consts.wast
new file mode 100644 (file)
index 0000000..c4e5b2d
--- /dev/null
@@ -0,0 +1,65 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) 0))
+  (import "env" "callerIsOMGCompiled" (func (;0;) (type 1)))
+  (func (export "test") (type 0) (param i32) (result i32)
+    (local i32 i32 i32 i32)
+    get_local 0
+    get_local 0
+    i32.load
+    set_local 1
+    i32.const 2
+    set_local 2
+    i32.const 0
+    set_local 3
+    loop  ;; label = @1
+      i32.const 0
+      set_local 4
+      get_local 1
+      get_local 2
+      if i32
+        get_local 2
+      else
+        get_local 2
+      end
+      block  ;; label = @2
+        call 0
+        br_if 0 (;@2;)
+        i32.const 0
+        set_local 4
+        loop  ;; label = @3
+          get_local 0
+          get_local 0
+          i32.load
+          i32.const 3
+          i32.mul
+          i32.store
+          get_local 4
+          i32.const 1
+          i32.add
+          set_local 4
+          call 0
+          i32.eqz
+          br_if 0 (;@3;)
+        end
+      end
+      i32.add
+      set_local 2
+      get_local 0
+      i32.load
+      set_local 1
+      get_local 3
+      i32.const 1
+      i32.add
+      tee_local 3
+      i32.const 20
+      i32.ne
+      br_if 0 (;@1;)
+    end
+    get_local 1
+    get_local 2
+    i32.add
+    i32.add
+    get_local 4
+    i32.add))
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm
new file mode 100644 (file)
index 0000000..26022be
Binary files /dev/null and b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wasm differ
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wast b/JSTests/wasm/wast-tests/osr-entry-inner-loop-branch-above.wast
new file mode 100644 (file)
index 0000000..416471f
--- /dev/null
@@ -0,0 +1,80 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) 0))
+  (import "env" "callerIsOMGCompiled" (func (;0;) (type 1)))
+  (func (export "test") (type 0) (param i32) (result i32)
+    (local i32 i32 i32 i32)
+    get_local 0
+    get_local 0
+    i32.load
+    set_local 1
+    i32.const 2
+    set_local 2
+    i32.const 0
+    set_local 3
+    loop  ;; label = @1
+      ;; add a bunch of values so there is a bigger stack here than in the if block.
+      i32.const 1
+      get_local 1
+      f32.const 3
+      get_local 3
+      i64.const 4
+
+      ;; real program
+      i32.const 0
+      set_local 4
+      get_local 1
+      get_local 2
+      if i32
+        get_local 2
+      else
+        get_local 2
+      end
+      block  ;; label = @2
+        call 0
+        br_if 0 (;@2;)
+        i32.const 0
+        set_local 4
+        loop  ;; label = @3
+          get_local 0
+          get_local 0
+          i32.load
+          i32.const 3
+          i32.mul
+          i32.store
+          get_local 4
+          i32.const 1
+          i32.add
+          set_local 4
+          call 0
+          i32.eqz
+          br_if 0 (;@3;)
+        end
+      end
+      i32.add
+      set_local 2
+      get_local 0
+      i32.load
+      set_local 1
+      get_local 3
+      i32.const 1
+      i32.add
+      tee_local 3
+      i32.const 20
+      i32.ne
+      br_if 0 (;@1;)
+
+      ;; drop our extra values so we can compile
+      drop
+      drop
+      drop
+      drop
+      drop
+    end
+    get_local 1
+    get_local 2
+    i32.add
+    i32.add
+    get_local 4
+    i32.add))
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop.wasm b/JSTests/wasm/wast-tests/osr-entry-inner-loop.wasm
new file mode 100644 (file)
index 0000000..c6fce76
Binary files /dev/null and b/JSTests/wasm/wast-tests/osr-entry-inner-loop.wasm differ
diff --git a/JSTests/wasm/wast-tests/osr-entry-inner-loop.wast b/JSTests/wasm/wast-tests/osr-entry-inner-loop.wast
new file mode 100644 (file)
index 0000000..04188d0
--- /dev/null
@@ -0,0 +1,60 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) 0))
+  (import "env" "callerIsOMGCompiled" (func (;0;) (type 1)))
+  (func (export "test") (type 0) (param i32) (result i32)
+    (local i32 i32 i32 i32)
+    get_local 0
+    get_local 0
+    i32.load
+    set_local 1
+    i32.const 2
+    set_local 2
+    i32.const 0
+    set_local 3
+    loop  ;; label = @1
+      i32.const 0
+      set_local 4
+      get_local 1
+      get_local 2
+      block  ;; label = @2
+        call 0
+        br_if 0 (;@2;)
+        i32.const 0
+        set_local 4
+        loop  ;; label = @3
+          get_local 0
+          get_local 0
+          i32.load
+          i32.const 3
+          i32.mul
+          i32.store
+          get_local 4
+          i32.const 1
+          i32.add
+          set_local 4
+          call 0
+          i32.eqz
+          br_if 0 (;@3;)
+        end
+      end
+      i32.add
+      set_local 2
+      get_local 0
+      i32.load
+      set_local 1
+      get_local 3
+      i32.const 1
+      i32.add
+      tee_local 3
+      i32.const 20
+      i32.ne
+      br_if 0 (;@1;)
+    end
+    get_local 1
+    get_local 2
+    i32.add
+    i32.add
+    get_local 4
+    i32.add))
diff --git a/JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm b/JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm
new file mode 100644 (file)
index 0000000..62617de
Binary files /dev/null and b/JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wasm differ
diff --git a/JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wast b/JSTests/wasm/wast-tests/osr-entry-multiple-enclosed-contexts.wast
new file mode 100644 (file)
index 0000000..6c10fe6
--- /dev/null
@@ -0,0 +1,47 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) 0))
+  (import "env" "callerIsOMGCompiled" (func (;0;) (type 1)))
+  (func (export "test") (type 0) (param i32) (result i32)
+    (local i32 i32 i32 i32)
+    get_local 0
+    i32.load
+    i32.const 2
+    i32.add
+    call 0
+    set_local 2
+    get_local 0
+    i32.load
+    set_local 3
+    i32.const 0
+    set_local 4
+    block  ;; label = @1
+      get_local 2
+      br_if 0 (;@1;)
+      i32.const 0
+      set_local 4
+      loop  ;; label = @2
+        get_local 0
+        get_local 3
+        i32.const 3
+        i32.mul
+        i32.store
+        get_local 4
+        i32.const 1
+        i32.add
+        set_local 4
+        call 0
+        set_local 2
+        get_local 0
+        i32.load
+        set_local 3
+        get_local 2
+        i32.eqz
+        br_if 0 (;@2;)
+      end
+    end
+    get_local 4
+    i32.add
+    get_local 3
+    i32.add))
index eec9153..1aac23a 100644 (file)
@@ -1,3 +1,54 @@
+2019-09-07  Keith Miller  <keith_miller@apple.com>
+
+        OSR entry into wasm misses some contexts
+        https://bugs.webkit.org/show_bug.cgi?id=201569
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch fixes an issue where we could fail to capture some of
+        our contexts when OSR entering into wasm code. Before we would
+        only capture the state of the block immediately surrounding the
+        entrance loop block header. We actually need to capture all
+        enclosed stacks.
+
+        Additionally, we don't need to use variables for all the captured
+        values. We can use a Phi and insert an upsilon just below the
+        captured value.
+
+        * interpreter/CallFrame.h:
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        (functionCallerIsOMGCompiled):
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+        (JSC::Wasm::AirIRGenerator::emitEntryTierUpCheck):
+        (JSC::Wasm::AirIRGenerator::emitLoopTierUpCheck):
+        (JSC::Wasm::AirIRGenerator::addLoop):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::createStack):
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        (JSC::Wasm::B3IRGenerator::addConstant):
+        (JSC::Wasm::B3IRGenerator::emitEntryTierUpCheck):
+        (JSC::Wasm::B3IRGenerator::emitLoopTierUpCheck):
+        (JSC::Wasm::B3IRGenerator::addLoop):
+        (JSC::Wasm::B3IRGenerator::addEndToUnreachable):
+        (JSC::Wasm::dumpExpressionStack):
+        (JSC::Wasm::B3IRGenerator::dump):
+        (JSC::Wasm::B3IRGenerator::Stack::Stack): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::append): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::takeLast): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::last): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::size const): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::isEmpty const): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::convertToExpressionList): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::at const): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::variableAt const): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::shrink): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::swap): Deleted.
+        (JSC::Wasm::B3IRGenerator::Stack::dump const): Deleted.
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser::controlStack):
+
 2019-09-09  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Promise resolve/reject functions should be created more efficiently
index a46703d..dd200e1 100644 (file)
@@ -132,7 +132,7 @@ namespace JSC  {
 
         JSGlobalObject* wasmAwareLexicalGlobalObject(VM&);
 
-        bool isAnyWasmCallee();
+        JS_EXPORT_PRIVATE bool isAnyWasmCallee();
 
         // Global object in which the currently executing code was defined.
         // Differs from VM::vmEntryGlobalObject() during function calls across web browser frames.
index 6c9c476..927c75c 100644 (file)
@@ -27,6 +27,7 @@
 #include "BuiltinNames.h"
 #include "ButterflyInlines.h"
 #include "BytecodeCacheError.h"
+#include "CallFrameInlines.h"
 #include "CatchScope.h"
 #include "CodeBlock.h"
 #include "CodeCache.h"
@@ -320,6 +321,7 @@ static EncodedJSValue JSC_HOST_CALL functionNoFTL(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionNoOSRExitFuzzing(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionOptimizeNextInvocation(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCallerIsOMGCompiled(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionReoptimizationRetryCount(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState*);
@@ -541,6 +543,7 @@ protected:
         addFunction(vm, "noFTL", functionNoFTL, 1);
         addFunction(vm, "noOSRExitFuzzing", functionNoOSRExitFuzzing, 1);
         addFunction(vm, "numberOfDFGCompiles", functionNumberOfDFGCompiles, 1);
+        addFunction(vm, "callerIsOMGCompiled", functionCallerIsOMGCompiled, 0);
         addFunction(vm, "jscOptions", functionJSCOptions, 0);
         addFunction(vm, "optimizeNextInvocation", functionOptimizeNextInvocation, 1);
         addFunction(vm, "reoptimizationRetryCount", functionReoptimizationRetryCount, 1);
@@ -1727,6 +1730,31 @@ EncodedJSValue JSC_HOST_CALL functionNumberOfDFGCompiles(ExecState* exec)
     return JSValue::encode(numberOfDFGCompiles(exec));
 }
 
+EncodedJSValue JSC_HOST_CALL functionCallerIsOMGCompiled(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (!Options::useBBQTierUpChecks())
+        return JSValue::encode(jsBoolean(true));
+
+    CallerFunctor wasmToJSFrame;
+    StackVisitor::visit(exec, &vm, wasmToJSFrame);
+    if (!wasmToJSFrame.callerFrame()->isAnyWasmCallee())
+        return throwVMError(exec, scope, "caller is not a wasm->js import function");
+
+    // We have a wrapper frame that we generate for imports. If we ever can direct call from wasm we would need to change this.
+    ASSERT(!wasmToJSFrame.callerFrame()->callee().isWasm());
+    CallerFunctor wasmFrame;
+    StackVisitor::visit(wasmToJSFrame.callerFrame(), &vm, wasmFrame);
+    ASSERT(wasmFrame.callerFrame()->callee().isWasm());
+#if ENABLE(WEBASSEMBLY)
+    auto mode = wasmFrame.callerFrame()->callee().asWasmCallee()->compilationMode();
+    return JSValue::encode(jsBoolean(mode == Wasm::CompilationMode::OMGMode || mode == Wasm::CompilationMode::OMGForOSREntryMode));
+#endif
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 Message::Message(ArrayBufferContents&& contents, int32_t index)
     : m_contents(WTFMove(contents))
     , m_index(index)
index fa15ec8..c8664fa 100644 (file)
@@ -591,8 +591,8 @@ private:
 
     void emitThrowException(CCallHelpers&, ExceptionType);
 
-    void emitEntryTierUpCheck(int32_t incrementCount, B3::Origin);
-    void emitLoopTierUpCheck(int32_t incrementCount, const Stack&, uint32_t, uint32_t, B3::Origin);
+    void emitEntryTierUpCheck();
+    void emitLoopTierUpCheck(uint32_t loopIndex);
 
     void emitWriteBarrierForJSWrapper();
     ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
@@ -852,7 +852,7 @@ AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& pro
         }
     });
 
-    emitEntryTierUpCheck(TierUpCount::functionEntryIncrement(), B3::Origin());
+    emitEntryTierUpCheck();
 }
 
 void AirIRGenerator::restoreWebAssemblyGlobalState(RestoreCachedStackLimit restoreCachedStackLimit, const MemoryInformation& memory, TypedTmp instance, BasicBlock* block)
@@ -1603,10 +1603,8 @@ auto AirIRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero,
     return { };
 }
 
-void AirIRGenerator::emitEntryTierUpCheck(int32_t incrementCount, B3::Origin origin)
+void AirIRGenerator::emitEntryTierUpCheck()
 {
-    UNUSED_PARAM(origin);
-
     if (!m_tierUp)
         return;
 
@@ -1624,7 +1622,7 @@ void AirIRGenerator::emitEntryTierUpCheck(int32_t incrementCount, B3::Origin ori
     patch->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
         AllowMacroScratchRegisterUsage allowScratch(jit);
 
-        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(incrementCount), CCallHelpers::Address(params[0].gpr()));
+        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(TierUpCount::functionEntryIncrement()), CCallHelpers::Address(params[0].gpr()));
         CCallHelpers::Label tierUpResume = jit.label();
 
         params.addLatePath([=] (CCallHelpers& jit) {
@@ -1650,9 +1648,10 @@ void AirIRGenerator::emitEntryTierUpCheck(int32_t incrementCount, B3::Origin ori
     emitPatchpoint(patch, Tmp(), countdownPtr);
 }
 
-void AirIRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& expressionStack, uint32_t loopIndex, uint32_t outerLoopIndex, B3::Origin origin)
+void AirIRGenerator::emitLoopTierUpCheck(uint32_t loopIndex)
 {
-    UNUSED_PARAM(origin);
+    uint32_t outerLoopIndex = this->outerLoopIndex();
+    m_outerLoops.append(loopIndex);
 
     if (!m_tierUp)
         return;
@@ -1680,14 +1679,16 @@ void AirIRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& ex
     Vector<ConstrainedTmp> patchArgs;
     patchArgs.append(countdownPtr);
 
-    Vector<B3::Type> types;
-    for (auto& local : m_locals) {
+    for (auto& local : m_locals)
         patchArgs.append(ConstrainedTmp(local, B3::ValueRep::ColdAny));
-        types.append(toB3Type(local.type()));
-    }
-    for (auto& expression : expressionStack) {
-        patchArgs.append(ConstrainedTmp(expression, B3::ValueRep::ColdAny));
-        types.append(toB3Type(expression.type()));
+    for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
+        ExpressionList& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
+        for (auto& value : expressionStack)
+            patchArgs.append(ConstrainedTmp(value, B3::ValueRep::ColdAny));
+
+        const auto& results = m_parser->controlStack()[controlIndex].controlData.result;
+        for (auto& value : results)
+            patchArgs.append(ConstrainedTmp(value, B3::ValueRep::ColdAny));
     }
 
     TierUpCount::TriggerReason* forceEntryTrigger = &(m_tierUp->osrEntryTriggers().last());
@@ -1696,12 +1697,13 @@ void AirIRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& ex
     patch->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
         AllowMacroScratchRegisterUsage allowScratch(jit);
         CCallHelpers::Jump forceOSREntry = jit.branchTest8(CCallHelpers::NonZero, CCallHelpers::AbsoluteAddress(forceEntryTrigger));
-        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(incrementCount), CCallHelpers::Address(params[0].gpr()));
+        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(TierUpCount::loopIncrement()), CCallHelpers::Address(params[0].gpr()));
         MacroAssembler::Label tierUpResume = jit.label();
 
         OSREntryData& osrEntryData = m_tierUp->addOSREntryData(m_functionIndex, loopIndex);
-        for (unsigned index = 0; index < types.size(); ++index)
-            osrEntryData.values().constructAndAppend(params[index + 1], types[index]);
+        // First argument is the countdown location.
+        for (unsigned index = 1; index < params.value()->numChildren(); ++index)
+            osrEntryData.values().constructAndAppend(params[index], params.value()->child(index)->type());
         OSREntryData* osrEntryDataPtr = &osrEntryData;
 
         params.addLatePath([=] (CCallHelpers& jit) {
@@ -1718,7 +1720,7 @@ void AirIRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& ex
     emitPatchpoint(patch, Tmp(), WTFMove(patchArgs));
 }
 
-AirIRGenerator::ControlData AirIRGenerator::addLoop(Type signature, const Stack& expressionStack, uint32_t loopIndex)
+AirIRGenerator::ControlData AirIRGenerator::addLoop(Type signature, const Stack&, uint32_t loopIndex)
 {
     BasicBlock* body = m_code.addBlock();
     BasicBlock* continuation = m_code.addBlock();
@@ -1726,10 +1728,8 @@ AirIRGenerator::ControlData AirIRGenerator::addLoop(Type signature, const Stack&
     append(Jump);
     m_currentBlock->setSuccessors(body);
 
-    uint32_t outerLoopIndex = this->outerLoopIndex();
-    m_outerLoops.append(loopIndex);
     m_currentBlock = body;
-    emitLoopTierUpCheck(TierUpCount::loopIncrement(), expressionStack, loopIndex, outerLoopIndex, origin());
+    emitLoopTierUpCheck(loopIndex);
 
     return ControlData(origin(), signature, tmpForType(signature), BlockType::Loop, continuation, body);
 }
index 80e8488..b167df5 100644 (file)
@@ -161,107 +161,8 @@ public:
     typedef Value* ExpressionType;
     typedef Vector<ExpressionType, 1> ExpressionList;
 
-    friend class Stack;
-    class Stack {
-    public:
-        Stack(B3IRGenerator* generator)
-            : m_generator(generator)
-        {
-        }
-
-        void append(ExpressionType expression)
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode) {
-                Variable* variable = m_generator->m_proc.addVariable(expression->type());
-                m_generator->m_currentBlock->appendNew<VariableValue>(m_generator->m_proc, Set, m_generator->origin(), variable, expression);
-                m_stack.append(variable);
-                return;
-            }
-            m_data.append(expression);
-        }
-
-        ExpressionType takeLast()
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode)
-                return m_generator->m_currentBlock->appendNew<VariableValue>(m_generator->m_proc, B3::Get, m_generator->origin(), m_stack.takeLast());
-            return m_data.takeLast();
-        }
-
-        ExpressionType last()
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode)
-                return m_generator->m_currentBlock->appendNew<VariableValue>(m_generator->m_proc, B3::Get, m_generator->origin(), m_stack.last());
-            return m_data.last();
-        }
-
-        unsigned size() const
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode)
-                return m_stack.size();
-            return m_data.size();
-        }
-        bool isEmpty() const { return size() == 0; }
-
-        ExpressionList convertToExpressionList()
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode) {
-                ExpressionList results;
-                for (unsigned i = 0; i < m_stack.size(); ++i)
-                    results.append(at(i));
-                return results;
-            }
-            return m_data;
-        }
-
-        ExpressionType at(unsigned i) const
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode)
-                return m_generator->m_currentBlock->appendNew<VariableValue>(m_generator->m_proc, B3::Get, m_generator->origin(), m_stack.at(i));
-            return m_data.at(i);
-        }
-
-        Variable* variableAt(unsigned i) const
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode)
-                return m_stack.at(i);
-            return nullptr;
-        }
-
-        void shrink(unsigned i)
-        {
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode) {
-                m_stack.shrink(i);
-                return;
-            }
-            m_data.shrink(i);
-        }
-
-        void swap(Stack& stack)
-        {
-            std::swap(m_generator, stack.m_generator);
-            m_data.swap(stack.m_data);
-            m_stack.swap(stack.m_stack);
-        }
-
-        void dump() const
-        {
-            CommaPrinter comma(", ", "");
-            dataLog(comma, "ExpressionStack:");
-            if (m_generator->m_compilationMode == CompilationMode::OMGForOSREntryMode) {
-                for (const auto& variable : m_stack)
-                    dataLog(comma, *variable);
-                return;
-            }
-            for (const auto& expression : m_data)
-                dataLog(comma, *expression);
-        }
-
-    private:
-        B3IRGenerator* m_generator { nullptr };
-        ExpressionList m_data;
-        Vector<Variable*> m_stack;
-    };
-    Stack createStack() { return Stack(this); }
+    using Stack = ExpressionList;
+    Stack createStack() { return { }; }
 
     using ControlType = ControlData;
     using ResultList = ControlData::ResultList;
@@ -351,8 +252,8 @@ public:
 private:
     void emitExceptionCheck(CCallHelpers&, ExceptionType);
 
-    void emitEntryTierUpCheck(int32_t incrementCount, B3::Origin);
-    void emitLoopTierUpCheck(int32_t incrementCount, const Stack&, uint32_t, uint32_t, B3::Origin);
+    void emitEntryTierUpCheck();
+    void emitLoopTierUpCheck(uint32_t loopIndex);
 
     void emitWriteBarrierForJSWrapper();
     ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
@@ -584,7 +485,7 @@ B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure
         });
     }
 
-    emitEntryTierUpCheck(TierUpCount::functionEntryIncrement(), Origin());
+    emitEntryTierUpCheck();
 
     if (m_compilationMode == CompilationMode::OMGForOSREntryMode)
         m_currentBlock = m_proc.addBlock();
@@ -1187,18 +1088,19 @@ auto B3IRGenerator::addSelect(ExpressionType condition, ExpressionType nonZero,
 
 B3IRGenerator::ExpressionType B3IRGenerator::addConstant(Type type, uint64_t value)
 {
+
     return constant(toB3Type(type), value);
 }
 
-void B3IRGenerator::emitEntryTierUpCheck(int32_t incrementCount, Origin origin)
+void B3IRGenerator::emitEntryTierUpCheck()
 {
     if (!m_tierUp)
         return;
 
     ASSERT(m_tierUp);
-    Value* countDownLocation = constant(pointerType(), reinterpret_cast<uint64_t>(&m_tierUp->m_counter), origin);
+    Value* countDownLocation = constant(pointerType(), reinterpret_cast<uint64_t>(&m_tierUp->m_counter), Origin());
 
-    PatchpointValue* patch = m_currentBlock->appendNew<PatchpointValue>(m_proc, B3::Void, origin);
+    PatchpointValue* patch = m_currentBlock->appendNew<PatchpointValue>(m_proc, B3::Void, Origin());
     Effects effects = Effects::none();
     // FIXME: we should have a more precise heap range for the tier up count.
     effects.reads = B3::HeapRange::top();
@@ -1209,7 +1111,7 @@ void B3IRGenerator::emitEntryTierUpCheck(int32_t incrementCount, Origin origin)
     patch->append(countDownLocation, ValueRep::SomeRegister);
     patch->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
         AllowMacroScratchRegisterUsage allowScratch(jit);
-        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(incrementCount), CCallHelpers::Address(params[0].gpr()));
+        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(TierUpCount::functionEntryIncrement()), CCallHelpers::Address(params[0].gpr()));
         CCallHelpers::Label tierUpResume = jit.label();
 
         params.addLatePath([=] (CCallHelpers& jit) {
@@ -1233,13 +1135,15 @@ void B3IRGenerator::emitEntryTierUpCheck(int32_t incrementCount, Origin origin)
     });
 }
 
-void B3IRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& expressionStack, uint32_t loopIndex, uint32_t outerLoopIndex, B3::Origin origin)
+void B3IRGenerator::emitLoopTierUpCheck(uint32_t loopIndex)
 {
+    uint32_t outerLoopIndex = this->outerLoopIndex();
+    m_outerLoops.append(loopIndex);
+
     if (!m_tierUp)
         return;
 
-    ASSERT(m_tierUp);
-
+    Origin origin = this->origin();
     ASSERT(m_tierUp->osrEntryTriggers().size() == loopIndex);
     m_tierUp->osrEntryTriggers().append(TierUpCount::TriggerReason::DontTrigger);
     m_tierUp->outerLoops().append(outerLoopIndex);
@@ -1247,16 +1151,14 @@ void B3IRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& exp
     Value* countDownLocation = constant(pointerType(), reinterpret_cast<uint64_t>(&m_tierUp->m_counter), origin);
 
     Vector<ExpressionType> stackmap;
-    Vector<B3::Type> types;
     for (auto& local : m_locals) {
         ExpressionType result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, origin, local);
         stackmap.append(result);
-        types.append(result->type());
     }
-    for (unsigned i = 0; i < expressionStack.size(); ++i) {
-        ExpressionType result = expressionStack.at(i);
-        stackmap.append(result);
-        types.append(result->type());
+    for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
+        auto& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
+        for (Value* value : expressionStack)
+            stackmap.append(value);
     }
 
     PatchpointValue* patch = m_currentBlock->appendNew<PatchpointValue>(m_proc, B3::Void, origin);
@@ -1281,12 +1183,13 @@ void B3IRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& exp
     patch->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
         AllowMacroScratchRegisterUsage allowScratch(jit);
         CCallHelpers::Jump forceOSREntry = jit.branchTest8(CCallHelpers::NonZero, CCallHelpers::AbsoluteAddress(forceEntryTrigger));
-        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(incrementCount), CCallHelpers::Address(params[0].gpr()));
+        CCallHelpers::Jump tierUp = jit.branchAdd32(CCallHelpers::PositiveOrZero, CCallHelpers::TrustedImm32(TierUpCount::loopIncrement()), CCallHelpers::Address(params[0].gpr()));
         MacroAssembler::Label tierUpResume = jit.label();
 
         OSREntryData& osrEntryData = m_tierUp->addOSREntryData(m_functionIndex, loopIndex);
-        for (unsigned index = 0; index < types.size(); ++index)
-            osrEntryData.values().constructAndAppend(params[index + 1], types[index]);
+        // First argument is the countdown location.
+        for (unsigned i = 1; i < params.value()->numChildren(); ++i)
+            osrEntryData.values().constructAndAppend(params[i], params.value()->child(i)->type());
         OSREntryData* osrEntryDataPtr = &osrEntryData;
 
         params.addLatePath([=] (CCallHelpers& jit) {
@@ -1301,49 +1204,69 @@ void B3IRGenerator::emitLoopTierUpCheck(int32_t incrementCount, const Stack& exp
     });
 }
 
-B3IRGenerator::ControlData B3IRGenerator::addLoop(Type signature, const Stack& stack, uint32_t loopIndex)
+B3IRGenerator::ControlData B3IRGenerator::addLoop(Type signature, const Stack&, uint32_t loopIndex)
 {
     BasicBlock* body = m_proc.addBlock();
     BasicBlock* continuation = m_proc.addBlock();
 
     m_currentBlock->appendNewControlValue(m_proc, Jump, origin(), body);
     if (loopIndex == m_loopIndexForOSREntry) {
+        dataLogLnIf(WasmB3IRGeneratorInternal::verbose, "Setting up for OSR entry");
         m_currentBlock = m_rootBlock;
-        m_osrEntryScratchBufferSize = m_locals.size() + stack.size();
         Value* pointer = m_rootBlock->appendNew<ArgumentRegValue>(m_proc, Origin(), GPRInfo::argumentGPR0);
 
-        auto loadFromScratchBuffer = [&] (B3::Type type, unsigned index) {
-            size_t offset = sizeof(uint64_t) * index;
-            switch (type.kind()) {
-            case B3::Int32:
-                return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), pointer, offset);
-            case B3::Int64:
-                return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, B3::Int64, origin(), pointer, offset);
-            case B3::Float:
-                return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, B3::Float, origin(), pointer, offset);
-            case B3::Double:
-                return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, B3::Double, origin(), pointer, offset);
-            default:
-                RELEASE_ASSERT_NOT_REACHED();
-                break;
-            }
+        unsigned indexInBuffer = 0;
+        auto loadFromScratchBuffer = [&] (B3::Type type) {
+            size_t offset = sizeof(uint64_t) * indexInBuffer++;
+            RELEASE_ASSERT(type.isNumeric());
+            return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, type, origin(), pointer, offset);
         };
 
-        unsigned indexInBuffer = 0;
         for (auto& local : m_locals)
-            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, loadFromScratchBuffer(local->type(), indexInBuffer++));
-        for (unsigned i = 0; i < stack.size(); ++i) {
-            auto* variable = stack.variableAt(i);
-            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), variable, loadFromScratchBuffer(variable->type(), indexInBuffer++));
+            m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, loadFromScratchBuffer(local->type()));
+
+        for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
+            const auto& data = m_parser->controlStack()[controlIndex].controlData;
+            auto& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
+
+            // For each stack entry enclosed by this loop we need to replace the value with a phi so we can fill it on OSR entry.
+            BasicBlock* sourceBlock = nullptr;
+            unsigned blockIndex = 0;
+            B3::InsertionSet insertionSet(m_proc);
+            for (unsigned i = 0; i < expressionStack.size(); i++) {
+                auto* value = expressionStack[i];
+                if (value->isConstant())
+                    continue;
+
+                if (value->owner != sourceBlock) {
+                    insertionSet.execute(sourceBlock);
+                    ASSERT(insertionSet.isEmpty());
+                    dataLogLnIf(WasmB3IRGeneratorInternal::verbose && sourceBlock, "Executed insertion set into: ", *sourceBlock);
+                    blockIndex = 0;
+                    sourceBlock = value->owner;
+                }
+
+                while (sourceBlock->at(blockIndex++) != value)
+                    ASSERT(blockIndex < sourceBlock->size());
+                ASSERT(sourceBlock->at(blockIndex - 1) == value);
+
+                auto* phi = data.continuation->appendNew<Value>(m_proc, Phi,  value->type(), value->origin());
+                expressionStack[i] = phi;
+                m_currentBlock->appendNew<UpsilonValue>(m_proc, value->origin(), loadFromScratchBuffer(value->type()), phi);
+
+                auto* sourceUpsilon = m_proc.add<UpsilonValue>(value->origin(), value, phi);
+                insertionSet.insertValue(blockIndex, sourceUpsilon);
+            }
+            insertionSet.execute(sourceBlock);
         }
+
+        m_osrEntryScratchBufferSize = indexInBuffer;
         m_currentBlock->appendNewControlValue(m_proc, Jump, origin(), body);
         body->addPredecessor(m_currentBlock);
     }
 
-    uint32_t outerLoopIndex = this->outerLoopIndex();
-    m_outerLoops.append(loopIndex);
     m_currentBlock = body;
-    emitLoopTierUpCheck(TierUpCount::loopIncrement(), stack, loopIndex, outerLoopIndex, origin());
+    emitLoopTierUpCheck(loopIndex);
 
     return ControlData(m_proc, origin(), signature, BlockType::Loop, continuation, body);
 }
@@ -1467,7 +1390,7 @@ auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry) -> PartialResult
 
     // TopLevel does not have any code after this so we need to make sure we emit a return here.
     if (data.type() == BlockType::TopLevel)
-        return addReturn(entry.controlData, entry.enclosedExpressionStack.convertToExpressionList());
+        return addReturn(entry.controlData, entry.enclosedExpressionStack);
 
     return { };
 }
@@ -1739,6 +1662,13 @@ void B3IRGenerator::unifyValuesWithBlock(const Stack& resultStack, const ResultL
         unify(result[result.size() - 1 - i], resultStack.at(resultStack.size() - 1 - i));
 }
 
+static void dumpExpressionStack(const CommaPrinter& comma, const B3IRGenerator::ExpressionList& expressionStack)
+{
+    dataLog(comma, "ExpressionStack:");
+    for (const auto& expression : expressionStack)
+        dataLog(comma, *expression);
+}
+
 void B3IRGenerator::dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack)
 {
     dataLogLn("Constants:");
@@ -1752,7 +1682,8 @@ void B3IRGenerator::dump(const Vector<ControlEntry>& controlStack, const Stack*
     ASSERT(controlStack.size());
     for (size_t i = controlStack.size(); i--;) {
         dataLog("  ", controlStack[i].controlData, ": ");
-        expressionStack->dump();
+        CommaPrinter comma(", ", "");
+        dumpExpressionStack(comma, *expressionStack);
         expressionStack = &controlStack[i].enclosedExpressionStack;
         dataLogLn();
     }
index a138410..72fdaff 100644 (file)
@@ -60,6 +60,8 @@ public:
     OpType currentOpcode() const { return m_currentOpcode; }
     size_t currentOpcodeStartingOffset() const { return m_currentOpcodeStartingOffset; }
 
+    Vector<ControlEntry>& controlStack() { return m_controlStack; }
+
 private:
     static const bool verbose = false;
 
index c7ffc5d..b6c5c27 100644 (file)
@@ -32,7 +32,7 @@ namespace JSC { namespace Wasm {
 
 void OpcodeOrigin::dump(PrintStream& out) const
 {
-    out.print("{opcode: ", makeString(opcode()), ", location: ", location(), "}");
+    out.print("{opcode: ", makeString(opcode()), ", location: ", RawPointer(reinterpret_cast<void*>(location())), "}");
 }
 
 } } // namespace JSC::Wasm
index c778c06..1462a6f 100644 (file)
@@ -1,3 +1,14 @@
+2019-09-07  Keith Miller  <keith_miller@apple.com>
+
+        OSR entry into wasm misses some contexts
+        https://bugs.webkit.org/show_bug.cgi?id=201569
+
+        Reviewed by Yusuke Suzuki.
+
+        Add new test harness mode for tests created from wast files.
+
+        * Scripts/run-jsc-stress-tests:
+
 2019-09-09  Daniel Bates  <dabates@apple.com>
 
         Remove all selection view animations before dumping results
index a389ca0..c420889 100755 (executable)
@@ -1114,6 +1114,36 @@ def runWebAssemblySuite(*optionalTestSpecificOptions)
     end
 end
 
+def runHarnessTest(kind, *options)
+    wasmFiles = allWasmFiles($collection)
+    wasmFiles.each {
+        | file |
+        basename = file.basename.to_s
+        addRunCommand("(" + basename + ")-" + kind, [pathToVM.to_s] + $testSpecificRequiredOptions + options + [$benchmark.to_s, "--", basename], silentOutputHandler, simpleErrorHandler)
+    }
+end
+
+def runWebAssemblyWithHarness(*optionalTestSpecificOptions)
+    raise unless $benchmark.to_s =~ /harness\.m?js/
+    return if !$jitTests
+    return if !$isFTLPlatform
+
+    wasmFiles = allWasmFiles($collection)
+    prepareExtraRelativeFiles(wasmFiles.map { |f| f.basename }, $collection)
+
+    runHarnessTest("default-wasm", *(FTL_OPTIONS + optionalTestSpecificOptions))
+    if $mode != "quick"
+        runHarnessTest("wasm-no-cjit-yes-tls-context", "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-eager", *(FTL_OPTIONS + EAGER_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-eager-jettison", "--forceCodeBlockToJettisonDueToOldAge=true", *(FTL_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-no-call-ic", "--useCallICsForWebAssemblyToJSCalls=false", *(FTL_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-no-tls-context", "--useFastTLSForWasmContext=false", *(FTL_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-slow-memory", "--useWebAssemblyFastMemory=false", *(FTL_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-no-air", "--wasmBBQUsesAir=false", *(FTL_OPTIONS + optionalTestSpecificOptions))
+        runHarnessTest("wasm-collect-continuously", "--collectContinuously=true", *(FTL_OPTIONS + optionalTestSpecificOptions)) if shouldCollectContinuously?
+    end
+end
+
 def runWebAssemblyEmscripten(mode)
     case mode
     when :skip
@@ -1483,6 +1513,21 @@ def skip
     puts "Skipping #{$collectionName}/#{$benchmark}"
 end
 
+def allWasmFiles(path)
+    if path.file?
+        [path]
+    else
+        result = []
+        Dir.foreach(path) {
+            | filename |
+            next unless filename =~ /\.m?wasm$/
+            next unless (path + filename).file?
+            result << path + filename
+        }
+        result
+    end
+end
+
 def allJSFiles(path)
     if path.file?
         [path]