Title: [217060] trunk
Revision
217060
Author
[email protected]
Date
2017-05-18 12:38:10 -0700 (Thu, 18 May 2017)

Log Message

WebAssembly: perform stack checks
https://bugs.webkit.org/show_bug.cgi?id=165546
<rdar://problem/29760307>

Reviewed by Filip Pizlo.

JSTests:

* wasm.yaml:
* wasm/function-tests/factorial.js:
* wasm/function-tests/float-sub.js:
* wasm/function-tests/stack-overflow.js: Added.
(import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
(import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.assertOverflows):
(assertOverflows.makeInstance):
(assertOverflows.makeInstance2):
(assertOverflows.assertThrows):
(assertOverflows):
(assertThrows.test.makeSignature):
(assertThrows.test.makeInstance):
(assertThrows.test):
(assertThrows):

Source/_javascript_Core:

This patch adds stack checks to wasm. It implements it by storing the stack
bounds on the Context.
        
Stack checking works as normal, except we do a small optimization for terminal
nodes in the call tree (nodes that don't make any calls). These nodes will
only do a stack check if their frame size is beyond 1024 bytes. Otherwise,
it's assumed the parent that called them did their stack check for them.
This is because all things that make calls make sure to do an extra 1024
bytes whenever doing a stack check.
        
We also take into account stack size for potential JS calls when doing
stack checks since our JS stubs don't do this on their own. Each frame
will ensure it does a stack check large enough for any potential JS call
stubs it'll execute.
        
Surprisingly, this patch is neutral on WasmBench and TitzerBench.

* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LowLevelInterpreter.asm:
* runtime/Error.cpp:
(JSC::createRangeError):
(JSC::addErrorInfoAndGetBytecodeOffset):
I fixed a bug here where we assumed that the first frame that has line
and column info would be in our stack trace. This is not correct
since we limit our stack trace size. If everything in our limited
size stack trace is Wasm, then we won't have any frames with line
and column info.
* runtime/Error.h:
* runtime/ExceptionHelpers.cpp:
(JSC::createStackOverflowError):
* runtime/ExceptionHelpers.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::webAssemblyToJSCalleeStructure):
* runtime/JSType.h:
* runtime/Options.h: I've added a new option that controls
whether or not we use fast TLS for the wasm context.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
* wasm/WasmBinding.cpp:
(JSC::Wasm::wasmToWasm):
* wasm/WasmContext.cpp:
(JSC::Wasm::loadContext):
(JSC::Wasm::storeContext):
* wasm/WasmContext.h:
(JSC::Wasm::useFastTLSForContext):
* wasm/WasmExceptionType.h:
* wasm/WasmMemoryInformation.h:
(JSC::Wasm::PinnedRegisterInfo::toSave):
* wasm/WasmThunks.cpp:
(JSC::Wasm::throwExceptionFromWasmThunkGenerator):
(JSC::Wasm::throwStackOverflowFromWasmThunkGenerator):
(JSC::Wasm::Thunks::stub):
* wasm/WasmThunks.h:
* wasm/js/JSWebAssemblyInstance.h:
(JSC::JSWebAssemblyInstance::offsetOfCachedStackLimit):
(JSC::JSWebAssemblyInstance::cachedStackLimit):
(JSC::JSWebAssemblyInstance::setCachedStackLimit):
* wasm/js/JSWebAssemblyModule.cpp:
(JSC::JSWebAssemblyModule::finishCreation):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
* wasm/js/WebAssemblyToJSCallee.cpp: Make this a descendent of object.
This is needed for correctness because we may call into JS,
and then the first JS frame could stack overflow. When it stack
overflows, it rolls back one frame to the wasm->js call stub with
the wasm->js callee. It gets the lexical global object from this
frame, meaning it gets the global object from the callee. Therefore,
we must make it an object since all objects have global objects.
(JSC::WebAssemblyToJSCallee::create):
* wasm/js/WebAssemblyToJSCallee.h:

Tools:

Add some new testing modes for using and not using fast TLS wasm contexts.

* Scripts/run-jsc-stress-tests:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (217059 => 217060)


--- trunk/JSTests/ChangeLog	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/JSTests/ChangeLog	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1,3 +1,26 @@
+2017-05-18  Saam Barati  <[email protected]>
+
+        WebAssembly: perform stack checks
+        https://bugs.webkit.org/show_bug.cgi?id=165546
+        <rdar://problem/29760307>
+
+        Reviewed by Filip Pizlo.
+
+        * wasm.yaml:
+        * wasm/function-tests/factorial.js:
+        * wasm/function-tests/float-sub.js:
+        * wasm/function-tests/stack-overflow.js: Added.
+        (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+        (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.assertOverflows):
+        (assertOverflows.makeInstance):
+        (assertOverflows.makeInstance2):
+        (assertOverflows.assertThrows):
+        (assertOverflows):
+        (assertThrows.test.makeSignature):
+        (assertThrows.test.makeInstance):
+        (assertThrows.test):
+        (assertThrows):
+
 2017-05-18  Keith Miller  <[email protected]>
 
         WebAssembly API: test with neutered inputs

Modified: trunk/JSTests/wasm/function-tests/factorial.js (217059 => 217060)


--- trunk/JSTests/wasm/function-tests/factorial.js	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/JSTests/wasm/function-tests/factorial.js	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1,30 +1,36 @@
+import * as assert from '../assert.js'
 import Builder from '../Builder.js'
 
 const b = new Builder();
 b.Type().End()
+    .Import().End()
     .Function().End()
+    .Export()
+        .Function("fac")
+    .End()
     .Code()
-    .Function({ params: ["i32"], ret: "i32" }, [])
-    .GetLocal(0)
-    .I32Const(0)
-    .I32Eq()
-    .If("void", b =>
-        b.I32Const(1)
-        .Return()
-       )
-        .GetLocal(0)
-    .GetLocal(0)
-    .I32Const(1)
-    .I32Sub()
-    .Call(0)
-    .I32Mul()
-    .Return()
+        .Function("fac", { params: ["i32"], ret: "i32" })
+            .GetLocal(0)
+            .I32Const(0)
+            .I32Eq()
+            .If("void", b =>
+                b.I32Const(1)
+                .Return()
+               )
+                .GetLocal(0)
+            .GetLocal(0)
+            .I32Const(1)
+            .I32Sub()
+            .Call(0)
+            .I32Mul()
+            .Return()
+        .End()
     .End()
 
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 1, [[{type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
-                                       [{type: "i32", value: 1 }, [{ type: "i32", value: 1 }]],
-                                       [{type: "i32", value: 2 }, [{ type: "i32", value: 2 }]],
-                                       [{type: "i32", value: 24 }, [{ type: "i32", value: 4 }]],
-                                      ]);
+const m = new WebAssembly.Module(b.WebAssembly().get());
+const fac = (new WebAssembly.Instance(m)).exports.fac;
+assert.eq(fac(0), 1);
+assert.eq(fac(1), 1);
+assert.eq(fac(2), 2);
+assert.eq(fac(4), 24);
+assert.throws(() => fac(1e7), RangeError, "Maximum call stack size exceeded.");

Modified: trunk/JSTests/wasm/function-tests/float-sub.js (217059 => 217060)


--- trunk/JSTests/wasm/function-tests/float-sub.js	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/JSTests/wasm/function-tests/float-sub.js	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1,10 +1,15 @@
+import * as assert from '../assert.js'
 import Builder from '../Builder.js'
 
 const b = new Builder();
 b.Type().End()
     .Function().End()
+    .Export()
+        .Function("foo")
+        .Function("bar")
+    .End()
     .Code()
-    .Function({ params: ["f32", "f32"], ret: "f32" }, [])
+    .Function("bar", { params: ["f32", "f32"], ret: "f32" }, [])
     .GetLocal(0)
     .GetLocal(1)
     .F32Sub()
@@ -11,20 +16,27 @@
     .Return()
     .End()
 
-    .Function({ params: ["f32", "f32"], ret: "f32" }, [])
+    .Function("foo", { params: ["f32", "f32"], ret: "f32" }, [])
     .GetLocal(0)
     .GetLocal(1)
     .Call(0)
     .Return()
     .End()
+    .End()
 
 const bin = b.WebAssembly()
 bin.trim();
-testWasmModuleFunctions(bin.get(), 2,
-                        [[{type: "f32", value: -1.5 }, [{ type: "f32", value: 0 }, { type: "f32", value: 1.5 }]],
-                         [{type: "f32", value: 87.6234 }, [{ type: "f32", value: 100.1234 }, { type: "f32", value: 12.5 }]]
-                        ],
-                        [[{type: "f32", value: -1.5 }, [{ type: "f32", value: 0 }, { type: "f32", value: 1.5 }]],
-                         [{type: "f32", value: 87.6234 }, [{ type: "f32", value: 100.1234 }, { type: "f32", value: 12.5 }]]
-                        ]
-                       );
+const instance = new WebAssembly.Instance(new WebAssembly.Module(bin.get()));
+
+let x = new Float32Array(3);
+x[0] = 0;
+x[1] = 1.5;
+x[2] = x[0] - x[1];
+assert.eq(instance.exports.bar(x[0], x[1]), x[2]);
+assert.eq(instance.exports.foo(x[0], x[1]), x[2]);
+
+x[0] = 100.1234
+x[1] = 12.5;
+x[2] = x[0] - x[1];
+assert.eq(instance.exports.bar(x[0], x[1]), x[2]);
+assert.eq(instance.exports.foo(x[0], x[1]), x[2]);

Added: trunk/JSTests/wasm/function-tests/stack-overflow.js (0 => 217060)


--- trunk/JSTests/wasm/function-tests/stack-overflow.js	                        (rev 0)
+++ trunk/JSTests/wasm/function-tests/stack-overflow.js	2017-05-18 19:38:10 UTC (rev 217060)
@@ -0,0 +1,221 @@
+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+{
+    function makeInstance() {
+        const tableDescription = {initial: 1, element: "anyfunc"};
+        const builder = new Builder()
+            .Type()
+                .Func(["i32"], "void")
+            .End()
+            .Import()
+                .Table("imp", "table", tableDescription)
+            .End()
+            .Function().End()
+            .Export()
+                .Function("foo")
+            .End()
+            .Code()
+                .Function("foo", 0 /*['i32'] => 'void'*/)
+                    .GetLocal(0) // parameter to call
+                    .GetLocal(0) // call index
+                    .CallIndirect(0, 0) // calling function of type ['i32'] => 'i32'
+                    .Return()
+                .End()
+            .End();
+
+
+        const bin = builder.WebAssembly().get();
+        const module = new WebAssembly.Module(bin);
+        const table = new WebAssembly.Table(tableDescription);
+        return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
+    }
+
+    const {instance: i1, table: t1} = makeInstance();
+    const {instance: i2, table: t2} = makeInstance();
+    t2.set(0, i1.exports.foo);
+    t1.set(0, i2.exports.foo);
+
+    function assertOverflows(instance) {
+        let stack;
+        try {
+            instance.exports.foo(0)
+        } catch(e) {
+            stack = e.stack;
+        }
+        stack = stack.split("\n");
+        assert.truthy(stack.length > 50);
+        for (let i = 0; i < 50; ++i) {
+            let item = stack[stack.length - i - 1];
+            assert.eq(item, "wasm function: 0@[wasm code]");
+        } 
+    }
+    assertOverflows(i1);
+    assertOverflows(i2);
+
+}
+
+{
+    function makeInstance() {
+        const tableDescription = {initial: 1, element: "anyfunc"};
+        const builder = new Builder()
+            .Type()
+                .Func([], "void")
+            .End()
+            .Import()
+                .Table("imp", "table", tableDescription)
+            .End()
+            .Function().End()
+            .Export()
+                .Function("foo")
+            .End()
+            .Code()
+                .Function("foo", {params:["i32"], ret:"void"})
+                    .GetLocal(0) // parameter to call
+                    .GetLocal(0) // call index
+                    .CallIndirect(0, 0) // calling function of type [] => 'void'
+                    .Return()
+                .End()
+            .End();
+
+
+        const bin = builder.WebAssembly().get();
+        const module = new WebAssembly.Module(bin);
+        const table = new WebAssembly.Table(tableDescription);
+        return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
+    }
+
+    function makeInstance2(f) {
+        const builder = new Builder()
+            .Type()
+            .End()
+            .Import()
+                .Function("imp", "f", {params:['i32'], ret:"void"})
+            .End()
+            .Function().End()
+            .Export()
+                .Function("foo")
+            .End()
+            .Code()
+                .Function("foo", {params: [], ret: "void" })
+                    .I32Const(0)
+                    .Call(0)
+                    .Return()
+                .End()
+            .End();
+
+
+        const bin = builder.WebAssembly().get();
+        const module = new WebAssembly.Module(bin);
+        return new WebAssembly.Instance(module, {imp: {f}});
+    }
+
+    const {instance: i1, table: t1} = makeInstance();
+    const foo = i1.exports.foo;
+    const i2 = makeInstance2(i1.exports.foo);
+    t1.set(0, i2.exports.foo);
+
+    function assertThrows(instance) {
+        let stack;
+        try {
+            instance.exports.foo();
+        } catch(e) {
+            stack = e.stack;
+        }
+        assert.truthy(stack);
+
+        stack = stack.split("\n");
+        assert.truthy(stack.length > 50);
+        const _oneString_ = "wasm function: 1@[wasm code]";
+        const zeroString = "wasm function: 0@[wasm code]";
+        let currentIndex = stack[stack.length - 1] === oneString ? 1 : 0;
+        for (let i = 0; i < 50; ++i) {
+            let item = stack[stack.length - 1 - i];
+            if (currentIndex === 1) {
+                assert.eq(item, oneString);
+                currentIndex = 0;
+            } else {
+                assert.eq(currentIndex, 0);
+                assert.eq(item, zeroString);
+                currentIndex = 1;
+            }
+        }
+    }
+
+    for (let i = 0; i < 20; ++i) {
+        assertThrows(i2);
+        assertThrows(i1);
+    }
+
+    for (let i = 0; i < 20; ++i) {
+        assertThrows(i1);
+        assertThrows(i2);
+    }
+}
+
+{
+    function test(numArgs) {
+        function makeSignature() {
+            let args = [];
+            for (let i = 0; i < numArgs; ++i) {
+                args.push("i32");
+            }
+            return {params: args};
+        }
+        function makeInstance(f) {
+            let builder = new Builder()
+                .Type()
+                    .Func([], "void")
+                .End()
+                .Import()
+                    .Function("imp", "f", makeSignature())
+                .End()
+                .Function().End()
+                .Export()
+                    .Function("foo")
+                .End()
+                .Code()
+                    .Function("foo", {params:[], ret:"void"});
+            for (let i = 0; i < numArgs; ++i) {
+                builder = builder.I32Const(i);
+            }
+
+            builder = builder.Call(0).Return().End().End();
+            const bin = builder.WebAssembly().get();
+            const module = new WebAssembly.Module(bin);
+            return new WebAssembly.Instance(module, {imp: {f}});
+        }
+
+        function f(...args) {
+            assert.eq(args.length, numArgs);
+            for (let i = 0; i < args.length; ++i)
+                assert.eq(args[i], i);
+
+            instance.exports.foo();
+        }
+        let instance = makeInstance(f);
+
+        let stack;
+        try {
+            instance.exports.foo();
+        } catch(e) {
+            stack = e.stack;
+        }
+        assert.truthy(stack.split("\n").length > 25);
+    }
+
+    for (let i = 0; i < 70; ++i) {
+        let r = Math.random() * 1000 | 0;
+        test(r);
+    }
+
+    test(20);
+    test(20);
+    test(1000);
+    test(2);
+    test(1);
+    test(0);
+    test(700);
+    test(433);
+    test(42);
+}

Modified: trunk/JSTests/wasm.yaml (217059 => 217060)


--- trunk/JSTests/wasm.yaml	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/JSTests/wasm.yaml	2017-05-18 19:38:10 UTC (rev 217060)
@@ -56,10 +56,10 @@
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/call.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/call_indirect.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/comments.wast.js
   cmd: runWebAssemblySpecTest :normal
@@ -86,7 +86,7 @@
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/fac.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/float_literals.wast.js
   cmd: runWebAssemblySpecTest :normal
@@ -167,7 +167,7 @@
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/skip-stack-guard-page.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/stack.wast.js
   cmd: runWebAssemblySpecTest :normal

Modified: trunk/Source/_javascript_Core/ChangeLog (217059 => 217060)


--- trunk/Source/_javascript_Core/ChangeLog	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1,3 +1,89 @@
+2017-05-18  Saam Barati  <[email protected]>
+
+        WebAssembly: perform stack checks
+        https://bugs.webkit.org/show_bug.cgi?id=165546
+        <rdar://problem/29760307>
+
+        Reviewed by Filip Pizlo.
+
+        This patch adds stack checks to wasm. It implements it by storing the stack
+        bounds on the Context.
+        
+        Stack checking works as normal, except we do a small optimization for terminal
+        nodes in the call tree (nodes that don't make any calls). These nodes will
+        only do a stack check if their frame size is beyond 1024 bytes. Otherwise,
+        it's assumed the parent that called them did their stack check for them.
+        This is because all things that make calls make sure to do an extra 1024
+        bytes whenever doing a stack check.
+        
+        We also take into account stack size for potential JS calls when doing
+        stack checks since our JS stubs don't do this on their own. Each frame
+        will ensure it does a stack check large enough for any potential JS call
+        stubs it'll execute.
+        
+        Surprisingly, this patch is neutral on WasmBench and TitzerBench.
+
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/Error.cpp:
+        (JSC::createRangeError):
+        (JSC::addErrorInfoAndGetBytecodeOffset):
+        I fixed a bug here where we assumed that the first frame that has line
+        and column info would be in our stack trace. This is not correct
+        since we limit our stack trace size. If everything in our limited
+        size stack trace is Wasm, then we won't have any frames with line
+        and column info.
+        * runtime/Error.h:
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::createStackOverflowError):
+        * runtime/ExceptionHelpers.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::webAssemblyToJSCalleeStructure):
+        * runtime/JSType.h:
+        * runtime/Options.h: I've added a new option that controls
+        whether or not we use fast TLS for the wasm context.
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        * wasm/WasmBinding.cpp:
+        (JSC::Wasm::wasmToWasm):
+        * wasm/WasmContext.cpp:
+        (JSC::Wasm::loadContext):
+        (JSC::Wasm::storeContext):
+        * wasm/WasmContext.h:
+        (JSC::Wasm::useFastTLSForContext):
+        * wasm/WasmExceptionType.h:
+        * wasm/WasmMemoryInformation.h:
+        (JSC::Wasm::PinnedRegisterInfo::toSave):
+        * wasm/WasmThunks.cpp:
+        (JSC::Wasm::throwExceptionFromWasmThunkGenerator):
+        (JSC::Wasm::throwStackOverflowFromWasmThunkGenerator):
+        (JSC::Wasm::Thunks::stub):
+        * wasm/WasmThunks.h:
+        * wasm/js/JSWebAssemblyInstance.h:
+        (JSC::JSWebAssemblyInstance::offsetOfCachedStackLimit):
+        (JSC::JSWebAssemblyInstance::cachedStackLimit):
+        (JSC::JSWebAssemblyInstance::setCachedStackLimit):
+        * wasm/js/JSWebAssemblyModule.cpp:
+        (JSC::JSWebAssemblyModule::finishCreation):
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+        * wasm/js/WebAssemblyToJSCallee.cpp: Make this a descendent of object.
+        This is needed for correctness because we may call into JS,
+        and then the first JS frame could stack overflow. When it stack
+        overflows, it rolls back one frame to the wasm->js call stub with
+        the wasm->js callee. It gets the lexical global object from this
+        frame, meaning it gets the global object from the callee. Therefore,
+        we must make it an object since all objects have global objects.
+        (JSC::WebAssemblyToJSCallee::create):
+        * wasm/js/WebAssemblyToJSCallee.h:
+
 2017-05-18  Keith Miller  <[email protected]>
 
         WebAssembly API: test with neutered inputs

Modified: trunk/Source/_javascript_Core/llint/LLIntData.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/llint/LLIntData.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/llint/LLIntData.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -156,21 +156,21 @@
     
     STATIC_ASSERT(StringType == 6);
     STATIC_ASSERT(SymbolType == 7);
-    STATIC_ASSERT(ObjectType == 24);
-    STATIC_ASSERT(FinalObjectType == 25);
-    STATIC_ASSERT(JSFunctionType == 27);
-    STATIC_ASSERT(ArrayType == 35);
-    STATIC_ASSERT(DerivedArrayType == 36);
-    STATIC_ASSERT(ProxyObjectType == 54);
-    STATIC_ASSERT(Int8ArrayType == 37);
-    STATIC_ASSERT(Int16ArrayType == 38);
-    STATIC_ASSERT(Int32ArrayType == 39);
-    STATIC_ASSERT(Uint8ArrayType == 40);
-    STATIC_ASSERT(Uint8ClampedArrayType == 41);
-    STATIC_ASSERT(Uint16ArrayType == 42);
-    STATIC_ASSERT(Uint32ArrayType == 43);
-    STATIC_ASSERT(Float32ArrayType == 44);
-    STATIC_ASSERT(Float64ArrayType == 45);
+    STATIC_ASSERT(ObjectType == 23);
+    STATIC_ASSERT(FinalObjectType == 24);
+    STATIC_ASSERT(JSFunctionType == 26);
+    STATIC_ASSERT(ArrayType == 34);
+    STATIC_ASSERT(DerivedArrayType == 35);
+    STATIC_ASSERT(ProxyObjectType == 53);
+    STATIC_ASSERT(Int8ArrayType == 36);
+    STATIC_ASSERT(Int16ArrayType == 37);
+    STATIC_ASSERT(Int32ArrayType == 38);
+    STATIC_ASSERT(Uint8ArrayType == 39);
+    STATIC_ASSERT(Uint8ClampedArrayType == 40);
+    STATIC_ASSERT(Uint16ArrayType == 41);
+    STATIC_ASSERT(Uint32ArrayType == 42);
+    STATIC_ASSERT(Float32ArrayType == 43);
+    STATIC_ASSERT(Float64ArrayType == 44);
     STATIC_ASSERT(MasqueradesAsUndefined == 1);
     STATIC_ASSERT(ImplementsDefaultHasInstance == 2);
     STATIC_ASSERT(FirstConstantRegisterIndex == 0x40000000);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (217059 => 217060)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-05-18 19:38:10 UTC (rev 217060)
@@ -345,24 +345,24 @@
 # Type constants.
 const StringType = 6
 const SymbolType = 7
-const ObjectType = 24
-const FinalObjectType = 25
-const JSFunctionType = 27
-const ArrayType = 35
-const DerivedArrayType = 36
-const ProxyObjectType = 54
+const ObjectType = 23
+const FinalObjectType = 24
+const JSFunctionType = 26
+const ArrayType = 34
+const DerivedArrayType = 35
+const ProxyObjectType = 53
 
 # The typed array types need to be numbered in a particular order because of the manually written
 # switch statement in get_by_val and put_by_val.
-const Int8ArrayType = 37
-const Int16ArrayType = 38
-const Int32ArrayType = 39
-const Uint8ArrayType = 40
-const Uint8ClampedArrayType = 41
-const Uint16ArrayType = 42
-const Uint32ArrayType = 43
-const Float32ArrayType = 44
-const Float64ArrayType = 45
+const Int8ArrayType = 36
+const Int16ArrayType = 37
+const Int32ArrayType = 38
+const Uint8ArrayType = 39
+const Uint8ClampedArrayType = 40
+const Uint16ArrayType = 41
+const Uint32ArrayType = 42
+const Float32ArrayType = 43
+const Float64ArrayType = 44
 
 const FirstArrayType = Int8ArrayType
 const LastArrayType = Float64ArrayType

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -60,8 +60,13 @@
 
 JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return createRangeError(exec, globalObject, message, appender);
+}
+
+JSObject* createRangeError(ExecState* exec, JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
+{
     ASSERT(!message.isEmpty());
-    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     return ErrorInstance::create(exec, globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
@@ -182,7 +187,7 @@
             callFrame = functor.foundCallFrame();
             unsigned stackIndex = functor.index();
             *bytecodeOffset = 0;
-            if (stackTrace.at(stackIndex).hasBytecodeOffset())
+            if (stackIndex < stackTrace.size() && stackTrace.at(stackIndex).hasBytecodeOffset())
                 *bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset();
         }
         
@@ -268,6 +273,11 @@
     return createRangeError(exec, message, nullptr);
 }
 
+JSObject* createRangeError(ExecState* exec, JSGlobalObject* globalObject, const String& message)
+{
+    return createRangeError(exec, globalObject, message, nullptr);
+}
+
 JSObject* createReferenceError(ExecState* exec, const String& message)
 {
     return createReferenceError(exec, message, nullptr);

Modified: trunk/Source/_javascript_Core/runtime/Error.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/Error.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/Error.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -52,6 +52,7 @@
 JSObject* createError(ExecState*, const String&, ErrorInstance::SourceAppender);
 JSObject* createEvalError(ExecState*, const String&, ErrorInstance::SourceAppender);
 JSObject* createRangeError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createRangeError(ExecState*, JSGlobalObject*, const String&, ErrorInstance::SourceAppender);
 JSObject* createReferenceError(ExecState*, const String&, ErrorInstance::SourceAppender);
 JSObject* createSyntaxError(ExecState*, const String&, ErrorInstance::SourceAppender);
 JSObject* createTypeError(ExecState*, const String&, ErrorInstance::SourceAppender, RuntimeType);
@@ -62,6 +63,7 @@
 JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createEvalError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, JSGlobalObject*, const String&);
 JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*);

Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -69,9 +69,14 @@
 
 JSObject* createStackOverflowError(ExecState* exec)
 {
-    return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded."));
+    return createStackOverflowError(exec, exec->lexicalGlobalObject());
 }
 
+JSObject* createStackOverflowError(ExecState* exec, JSGlobalObject* globalObject)
+{
+    return createRangeError(exec, globalObject, ASCIILiteral("Maximum call stack size exceeded."));
+}
+
 JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
 {
     if (exec->propertyNames().isPrivateName(ident)) {

Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -43,6 +43,7 @@
 JS_EXPORT_PRIVATE bool isTerminatedExecutionException(VM&, Exception*);
 JS_EXPORT_PRIVATE JSObject* createError(ExecState*, JSValue, const String&, ErrorInstance::SourceAppender);
 JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*);
+JSObject* createStackOverflowError(ExecState*, JSGlobalObject*);
 JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
 JSObject* createTDZError(ExecState*);
 JSObject* createNotAnObjectError(ExecState*, JSValue);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -163,6 +163,7 @@
 #include "WeakMapPrototype.h"
 #include "WeakSetConstructor.h"
 #include "WeakSetPrototype.h"
+#include "WebAssemblyToJSCallee.h"
 #include <wtf/RandomNumber.h>
 
 #if ENABLE(INTL)
@@ -887,6 +888,7 @@
         m_webAssemblyModuleRecordStructure.set(vm, this, WebAssemblyModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
         m_webAssemblyFunctionStructure.set(vm, this, WebAssemblyFunction::createStructure(vm, this, m_functionPrototype.get()));
         m_webAssemblyWrapperFunctionStructure.set(vm, this, WebAssemblyWrapperFunction::createStructure(vm, this, m_functionPrototype.get()));
+        m_webAssemblyToJSCalleeStructure.set(vm, this, WebAssemblyToJSCallee::createStructure(vm, this, jsNull()));
         auto* webAssembly = JSWebAssembly::create(vm, this, m_webAssemblyStructure.get());
         putDirectWithoutTransition(vm, Identifier::fromString(exec, "WebAssembly"), webAssembly, DontEnum);
 
@@ -1270,6 +1272,7 @@
     visitor.append(thisObject->m_webAssemblyModuleRecordStructure);
     visitor.append(thisObject->m_webAssemblyFunctionStructure);
     visitor.append(thisObject->m_webAssemblyWrapperFunctionStructure);
+    visitor.append(thisObject->m_webAssemblyToJSCalleeStructure);
     FOR_EACH_WEBASSEMBLY_CONSTRUCTOR_TYPE(VISIT_SIMPLE_TYPE)
 #endif // ENABLE(WEBASSEMBLY)
 

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -351,6 +351,7 @@
     WriteBarrier<Structure> m_webAssemblyModuleRecordStructure;
     WriteBarrier<Structure> m_webAssemblyFunctionStructure;
     WriteBarrier<Structure> m_webAssemblyWrapperFunctionStructure;
+    WriteBarrier<Structure> m_webAssemblyToJSCalleeStructure;
     FOR_EACH_WEBASSEMBLY_CONSTRUCTOR_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE)
 #endif // ENABLE(WEBASSEMBLY)
 
@@ -621,6 +622,7 @@
     Structure* webAssemblyModuleRecordStructure() const { return m_webAssemblyModuleRecordStructure.get(); }
     Structure* webAssemblyFunctionStructure() const { return m_webAssemblyFunctionStructure.get(); }
     Structure* webAssemblyWrapperFunctionStructure() const { return m_webAssemblyWrapperFunctionStructure.get(); }
+    Structure* webAssemblyToJSCalleeStructure() const { return m_webAssemblyToJSCalleeStructure.get(); }
 #endif // ENABLE(WEBASSEMBLY)
 
     JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);

Modified: trunk/Source/_javascript_Core/runtime/JSType.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/JSType.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/JSType.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -53,8 +53,6 @@
     JSSourceCodeType,
     JSScriptFetcherType,
 
-    WebAssemblyToJSCalleeType,
-
     // The ObjectType value must come before any JSType that is a subclass of JSObject.
     ObjectType,
     FinalObjectType,
@@ -101,7 +99,9 @@
 
     ClonedArgumentsType,
 
-    LastJSCObjectType = ClonedArgumentsType,
+    WebAssemblyToJSCalleeType,
+
+    LastJSCObjectType = WebAssemblyToJSCalleeType,
     MaxJSType = 0b11111111,
 };
 

Modified: trunk/Source/_javascript_Core/runtime/Options.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/Options.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -455,6 +455,7 @@
     v(bool, crashIfWebAssemblyCantFastMemory, false, Normal, "If true, we will crash if we can't obtain fast memory for wasm.") \
     v(unsigned, webAssemblyFastMemoryPreallocateCount, 0, Normal, "WebAssembly fast memories can be pre-allocated at program startup and remain cached to avoid fragmentation leading to bounds-checked memory. This number is an upper bound on initial allocation as well as total count of fast memories. Zero means no pre-allocation, no caching, and no limit to the number of runtime allocations.") \
     v(bool, useWebAssemblyFastTLS, true, Normal, "If true, we will try to use fast thread-local storage if available on the current platform.") \
+    v(bool, useFastTLSForWasmContext, true, Normal, "If true (and fast TLS is enabled), we will store context in fast TLS. If false, we will pin it to a register.") \
     v(bool, useCallICsForWebAssemblyToJSCalls, true, Normal, "If true, we will use CallLinkInfo to inline cache Wasm to JS calls.")
 
 

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -239,7 +239,6 @@
     programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
     functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
 #if ENABLE(WEBASSEMBLY)
-    webAssemblyToJSCalleeStructure.set(*this, WebAssemblyToJSCallee::createStructure(*this, 0, jsNull()));
     webAssemblyCodeBlockStructure.set(*this, JSWebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
 #endif
     moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));

Modified: trunk/Source/_javascript_Core/runtime/VM.h (217059 => 217060)


--- trunk/Source/_javascript_Core/runtime/VM.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -321,7 +321,6 @@
     Strong<Structure> programExecutableStructure;
     Strong<Structure> functionExecutableStructure;
 #if ENABLE(WEBASSEMBLY)
-    Strong<Structure> webAssemblyToJSCalleeStructure;
     Strong<Structure> webAssemblyCodeBlockStructure;
 #endif
     Strong<Structure> moduleProgramExecutableStructure;

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -267,6 +267,8 @@
     GPRReg m_memorySizeGPR { InvalidGPRReg };
     GPRReg m_wasmContextGPR;
     Value* m_instanceValue; // FIXME: make this lazy https://bugs.webkit.org/show_bug.cgi?id=169792
+    bool m_makesCalls { false };
+    uint32_t m_maxNumJSCallArguments { 0 };
 };
 
 // Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3.
@@ -381,9 +383,52 @@
 
     wasmCallingConvention().setupFrameInPrologue(&compilation->wasmCalleeMoveLocation, m_proc, Origin(), m_currentBlock);
 
+    m_instanceValue = materializeWasmContext(m_currentBlock);
+
+    {
+        B3::Value* framePointer = m_currentBlock->appendNew<B3::Value>(m_proc, B3::FramePointer, Origin());
+        B3::PatchpointValue* stackOverflowCheck = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
+        stackOverflowCheck->appendSomeRegister(framePointer);
+        stackOverflowCheck->appendSomeRegister(m_instanceValue);
+        stackOverflowCheck->clobber(RegisterSet::macroScratchRegisters());
+        stackOverflowCheck->numGPScratchRegisters = 2;
+        stackOverflowCheck->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            GPRReg fp = params[0].gpr();
+            GPRReg context = params[1].gpr();
+            GPRReg scratch1 = params.gpScratch(0);
+            GPRReg scratch2 = params.gpScratch(1);
+
+            const Checked<int32_t> wasmFrameSize = params.proc().frameSize();
+            const unsigned minimumParentCheckSize = WTF::roundUpToMultipleOf(stackAlignmentBytes(), 1024);
+            const unsigned extraFrameSize = WTF::roundUpToMultipleOf(stackAlignmentBytes(), std::max<uint32_t>(
+                // This allows us to elide stack checks for functions that are terminal nodes in the call
+                // tree, (e.g they don't make any calls) and have a small enough frame size. This works by
+                // having any such terminal node have its parent caller include some extra size in its
+                // own check for it. The goal here is twofold:
+                // 1. Emit less code.
+                // 2. Try to speed things up by skipping stack checks.
+                minimumParentCheckSize,
+                // This allows us to elide stack checks in the Wasm -> JS call IC stub. Since these will
+                // spill all arguments to the stack, we ensure that a stack check here covers the
+                // stack that such a stub would use.
+                (Checked<uint32_t>(m_maxNumJSCallArguments) * sizeof(Register) + jscCallingConvention().headerSizeInBytes()).unsafeGet()
+            ));
+            const int32_t checkSize = m_makesCalls ? (wasmFrameSize + extraFrameSize).unsafeGet() : wasmFrameSize.unsafeGet();
+            // This allows leaf functions to not do stack checks if their frame size is within
+            // certain limits since their caller would have already done the check.
+            if (m_makesCalls || wasmFrameSize >= minimumParentCheckSize) {
+                jit.loadPtr(CCallHelpers::Address(context, Context::offsetOfCachedStackLimit()), scratch2);
+                jit.addPtr(CCallHelpers::TrustedImm32(-checkSize), fp, scratch1);
+                auto overflow = jit.branchPtr(CCallHelpers::Below, scratch1, scratch2);
+                jit.addLinkTask([overflow] (LinkBuffer& linkBuffer) {
+                    linkBuffer.link(overflow, CodeLocationLabel(Thunks::singleton().stub(throwStackOverflowFromWasmThunkGenerator).code()));
+                });
+            }
+        });
+    }
+
     m_currentBlock = emitTierUpCheck(m_currentBlock, TierUpCount::functionEntryDecrement(), Origin());
-
-    m_instanceValue = materializeWasmContext(m_currentBlock);
 }
 
 void B3IRGenerator::restoreWebAssemblyGlobalState(const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
@@ -998,10 +1043,14 @@
 {
     ASSERT(signature.argumentCount() == args.size());
 
+    m_makesCalls = true;
+
     Type returnType = signature.returnType();
     Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls = &m_unlinkedWasmToWasmCalls;
 
     if (m_info.isImportedFunctionFromFunctionIndexSpace(functionIndex)) {
+        m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
+
         // FIXME imports can be linked here, instead of generating a patchpoint, because all import stubs are generated before B3 compilation starts. https://bugs.webkit.org/show_bug.cgi?id=166462
         Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfImportFunction(functionIndex)));
         Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, safeCast<int32_t>(JSCell::typeInfoTypeOffset()));
@@ -1017,7 +1066,9 @@
                 patchpoint->effects.writesPinned = true;
                 patchpoint->effects.readsPinned = true;
                 // We need to clobber all potential pinned registers since we might be leaving the instance.
-                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
+                // We pessimistically assume we could be calling to something that is bounds checking.
+                // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181
+                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
                 patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
                     AllowMacroScratchRegisterUsage allowScratch(jit);
                     CCallHelpers::Call call = jit.threadSafePatchableNearCall();
@@ -1043,7 +1094,9 @@
                 patchpoint->effects.readsPinned = true;
                 patchpoint->append(jumpDestination, ValueRep::SomeRegister);
                 // We need to clobber all potential pinned registers since we might be leaving the instance.
-                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
+                // We pessimistically assume we could be calling to something that is bounds checking.
+                // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181
+                patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
                 patchpoint->setGenerator([returnType] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
                     AllowMacroScratchRegisterUsage allowScratch(jit);
                     jit.call(params[returnType == Void ? 0 : 1].gpr());
@@ -1088,6 +1141,12 @@
     ExpressionType calleeIndex = args.takeLast();
     ASSERT(signature.argumentCount() == args.size());
 
+    m_makesCalls = true;
+    // Note: call indirect can call either WebAssemblyFunction or WebAssemblyWrapperFunction. Because
+    // WebAssemblyWrapperFunction is like calling into JS, we conservatively assume all call indirects
+    // can be to JS for our stack check calculation.
+    m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
+
     ExpressionType callableFunctionBuffer;
     ExpressionType jsFunctionBuffer;
     ExpressionType callableFunctionBufferSize;
@@ -1168,14 +1227,17 @@
         patchpoint->clobber(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
         patchpoint->clobber(RegisterSet::macroScratchRegisters());
         patchpoint->append(newContext, ValueRep::SomeRegister);
+        patchpoint->append(m_instanceValue, ValueRep::SomeRegister);
         patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
             GPRReg newContext = params[0].gpr();
+            GPRReg oldContext = params[1].gpr();
             const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
             const auto& sizeRegs = pinnedRegs.sizeRegisters;
             GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
             ASSERT(newContext != baseMemory);
-
+            jit.loadPtr(CCallHelpers::Address(oldContext, Context::offsetOfCachedStackLimit()), baseMemory);
+            jit.storePtr(baseMemory, CCallHelpers::Address(newContext, Context::offsetOfCachedStackLimit()));
             jit.storeWasmContext(newContext);
             jit.loadPtr(CCallHelpers::Address(newContext, Context::offsetOfMemory()), baseMemory); // JSWebAssemblyMemory*.
             ASSERT(sizeRegs.size() == 1);
@@ -1200,7 +1262,11 @@
             patchpoint->effects.writesPinned = true;
             patchpoint->effects.readsPinned = true;
             // We need to clobber all potential pinned registers since we might be leaving the instance.
-            patchpoint->clobberLate(PinnedRegisterInfo::get().toSave());
+            // We pessimistically assume we're always calling something that is bounds checking so
+            // because the wasm->wasm thunk unconditionally overrides the size registers.
+            // FIXME: We should not have to do this, but the wasm->wasm stub assumes it can
+            // use all the pinned registers as scratch: https://bugs.webkit.org/show_bug.cgi?id=172181
+            patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
 
             patchpoint->append(calleeCode, ValueRep::SomeRegister);
             patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {

Modified: trunk/Source/_javascript_Core/wasm/WasmBinding.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmBinding.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmBinding.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -36,6 +36,7 @@
 #include "LinkBuffer.h"
 #include "NativeErrorConstructor.h"
 #include "WasmCallingConvention.h"
+#include "WasmContext.h"
 #include "WasmExceptionType.h"
 
 namespace JSC { namespace Wasm {
@@ -608,23 +609,29 @@
     JIT jit;
 
     GPRReg scratch = GPRInfo::nonPreservedNonArgumentGPR;
+    GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
+    ASSERT(baseMemory != scratch);
+    const auto& sizeRegs = pinnedRegs.sizeRegisters;
+    ASSERT(sizeRegs.size() >= 1);
+    ASSERT(sizeRegs[0].sizeRegister != baseMemory);
+    ASSERT(sizeRegs[0].sizeRegister != scratch);
+    GPRReg sizeRegAsScratch = sizeRegs[0].sizeRegister;
 
+    static_assert(std::is_same<Context, JSWebAssemblyInstance>::value, "This is assumed in the code below.");
     // B3's call codegen ensures that the JSCell is a WebAssemblyFunction.
-    materializeImportJSCell(jit, importIndex, scratch);
+    jit.loadWasmContext(sizeRegAsScratch); // Old Instance*
+    jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfImportFunction(importIndex)), scratch);
 
     // Get the callee's WebAssembly.Instance and set it as WasmContext. The caller will take care of restoring its own Instance.
-    GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-    ASSERT(baseMemory != scratch);
     jit.loadPtr(JIT::Address(scratch, WebAssemblyFunction::offsetOfInstance()), baseMemory); // Instance*.
     jit.storeWasmContext(baseMemory);
 
+    jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfCachedStackLimit()), sizeRegAsScratch);
+    jit.storePtr(sizeRegAsScratch, JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfCachedStackLimit()));
+
     // FIXME the following code assumes that all WebAssembly.Instance have the same pinned registers. https://bugs.webkit.org/show_bug.cgi?id=162952
     // Set up the callee's baseMemory register as well as the memory size registers.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory); // JSWebAssemblyMemory*.
-    const auto& sizeRegs = pinnedRegs.sizeRegisters;
-    ASSERT(sizeRegs.size() >= 1);
-    ASSERT(sizeRegs[0].sizeRegister != baseMemory);
-    ASSERT(sizeRegs[0].sizeRegister != scratch);
     ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); // WasmMemory::void*.

Modified: trunk/Source/_javascript_Core/wasm/WasmContext.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmContext.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmContext.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -40,7 +40,6 @@
     if (useFastTLSForContext())
         return bitwise_cast<Context*>(_pthread_getspecific_direct(WTF_WASM_CONTEXT_KEY));
 #endif
-    // FIXME: Save this state elsewhere to allow PIC. https://bugs.webkit.org/show_bug.cgi?id=169773
     return vm.wasmContext;
 }
 
@@ -50,8 +49,9 @@
     if (useFastTLSForContext())
         _pthread_setspecific_direct(WTF_WASM_CONTEXT_KEY, bitwise_cast<void*>(context));
 #endif
-    // FIXME: Save this state elsewhere to allow PIC. https://bugs.webkit.org/show_bug.cgi?id=169773
     vm.wasmContext = context;
+    if (context)
+        context->setCachedStackLimit(vm.softStackLimit());
 }
 
 } } // namespace JSC::Wasm

Modified: trunk/Source/_javascript_Core/wasm/WasmContext.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmContext.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmContext.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -51,7 +51,9 @@
 
 inline bool useFastTLSForContext()
 {
-    return useFastTLS();
+    if (useFastTLS())
+        return Options::useFastTLSForWasmContext();
+    return false;
 }
 
 Context* loadContext(VM&);

Modified: trunk/Source/_javascript_Core/wasm/WasmExceptionType.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmExceptionType.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmExceptionType.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -39,7 +39,8 @@
     macro(OutOfBoundsTrunc, "Out of bounds Trunc operation") \
     macro(Unreachable, "Unreachable code should not be executed") \
     macro(DivisionByZero, "Division by zero") \
-    macro(IntegerOverflow, "Integer overflow")
+    macro(IntegerOverflow, "Integer overflow") \
+    macro(StackOverflow, "Stack overflow")
 
 enum class ExceptionType : uint32_t {
 #define MAKE_ENUM(enumName, error) enumName,

Modified: trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmMemoryInformation.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -48,7 +48,7 @@
     static const PinnedRegisterInfo& get();
     PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg);
 
-    RegisterSet toSave(MemoryMode mode = MemoryMode::BoundsChecking) const
+    RegisterSet toSave(MemoryMode mode) const
     {
         RegisterSet result;
         result.set(baseMemoryPointer);

Modified: trunk/Source/_javascript_Core/wasm/WasmThunks.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmThunks.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmThunks.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -40,7 +40,7 @@
 
 namespace JSC { namespace Wasm {
 
-MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator()
+MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(const AbstractLocker&)
 {
     CCallHelpers jit;
 
@@ -62,8 +62,11 @@
             auto throwScope = DECLARE_THROW_SCOPE(*vm);
             JSGlobalObject* globalObject = wasmContext->globalObject();
 
-            JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(
-                exec, *vm, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
+            JSObject* error; 
+            if (type == ExceptionType::StackOverflow)
+                error = createStackOverflowError(exec, globalObject);
+            else
+                error = JSWebAssemblyRuntimeError::create(exec, *vm, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
             throwException(exec, throwScope, error);
         }
 
@@ -86,6 +89,18 @@
     return FINALIZE_CODE(linkBuffer, ("Throw exception from Wasm"));
 }
 
+MacroAssemblerCodeRef throwStackOverflowFromWasmThunkGenerator(const AbstractLocker& locker)
+{
+    CCallHelpers jit;
+
+    jit.move(GPRInfo::callFrameRegister, MacroAssembler::stackPointerRegister);
+    jit.move(CCallHelpers::TrustedImm32(static_cast<uint32_t>(ExceptionType::StackOverflow)), GPRInfo::argumentGPR1);
+    auto jumpToExceptionHandler = jit.jump();
+    LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
+    linkBuffer.link(jumpToExceptionHandler, CodeLocationLabel(Thunks::singleton().stub(locker, throwExceptionFromWasmThunkGenerator).code()));
+    return FINALIZE_CODE(linkBuffer, ("Throw stack overflow from Wasm"));
+}
+
 static Thunks* thunks;
 void Thunks::initialize()
 {
@@ -101,12 +116,22 @@
 MacroAssemblerCodeRef Thunks::stub(ThunkGenerator generator)
 {
     auto locker = holdLock(m_lock);
+    return stub(locker, generator);
+}
 
+MacroAssemblerCodeRef Thunks::stub(const AbstractLocker& locker, ThunkGenerator generator)
+{
     ASSERT(!!generator);
-    auto addResult = m_stubs.add(generator, MacroAssemblerCodeRef());
-    if (addResult.isNewEntry)
-        addResult.iterator->value = generator();
-    return addResult.iterator->value;
+    {
+        auto addResult = m_stubs.add(generator, MacroAssemblerCodeRef());
+        if (!addResult.isNewEntry)
+            return addResult.iterator->value;
+    }
+
+    MacroAssemblerCodeRef code = generator(locker);
+    // We specifically don't use the iterator here to allow generator to recursively change m_stubs.
+    m_stubs.set(generator, code);
+    return code;
 }
 
 MacroAssemblerCodeRef Thunks::existingStub(ThunkGenerator generator)

Modified: trunk/Source/_javascript_Core/wasm/WasmThunks.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/WasmThunks.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/WasmThunks.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -31,9 +31,10 @@
 
 namespace JSC { namespace Wasm {
 
-MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator();
+MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(const AbstractLocker&);
+MacroAssemblerCodeRef throwStackOverflowFromWasmThunkGenerator(const AbstractLocker&);
 
-typedef MacroAssemblerCodeRef (*ThunkGenerator)();
+typedef MacroAssemblerCodeRef (*ThunkGenerator)(const AbstractLocker&);
 
 class Thunks {
 public:
@@ -41,6 +42,7 @@
     static Thunks& singleton();
 
     MacroAssemblerCodeRef stub(ThunkGenerator);
+    MacroAssemblerCodeRef stub(const AbstractLocker&, ThunkGenerator);
     MacroAssemblerCodeRef existingStub(ThunkGenerator);
 
 private:

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -73,11 +73,15 @@
     static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
     static ptrdiff_t offsetOfVM() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_vm); }
     static ptrdiff_t offsetOfCodeBlock() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_codeBlock); }
+    static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_cachedStackLimit); }
     static size_t offsetOfImportFunctions() { return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSCell>)>(sizeof(JSWebAssemblyInstance)); }
     static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfImportFunctions() + importFunctionNum * sizeof(sizeof(WriteBarrier<JSCell>)); }
 
     WebAssemblyToJSCallee* webAssemblyToJSCallee() { return m_callee.get(); }
 
+    void* cachedStackLimit() const { return m_cachedStackLimit; }
+    void setCachedStackLimit(void* limit) { m_cachedStackLimit = limit; }
+
 protected:
     JSWebAssemblyInstance(VM&, Structure*, unsigned numImportFunctions);
     void finishCreation(VM&, JSWebAssemblyModule*, JSModuleNamespaceObject*);
@@ -101,6 +105,7 @@
     WriteBarrier<JSWebAssemblyTable> m_table;
     WriteBarrier<WebAssemblyToJSCallee> m_callee;
     MallocPtr<uint64_t> m_globals;
+    void* m_cachedStackLimit { bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) };
     unsigned m_numImportFunctions;
 };
 

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyModule.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -82,7 +82,7 @@
     }
 
     m_exportSymbolTable.set(vm, this, exportSymbolTable);
-    m_callee.set(vm, this, WebAssemblyToJSCallee::create(vm, vm.webAssemblyToJSCalleeStructure.get(), this));
+    m_callee.set(vm, this, WebAssemblyToJSCallee::create(vm, this));
 }
 
 void JSWebAssemblyModule::destroy(JSCell* cell)

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -128,6 +128,15 @@
 
     // FIXME Do away with this entire function, and only use the entrypoint generated by B3. https://bugs.webkit.org/show_bug.cgi?id=166486
     Wasm::Context* prevWasmContext = Wasm::loadContext(vm);
+    {
+        // We do the stack check here for the wrapper function because we don't
+        // want to emit a stack check inside every wrapper function.
+        const intptr_t sp = bitwise_cast<intptr_t>(&sp); // A proxy for the current stack pointer.
+        const intptr_t frameSize = (boxedArgs.size() + CallFrame::headerSizeInRegisters) * sizeof(Register);
+        const intptr_t stackSpaceUsed = 2 * frameSize; // We're making two calls. One to the wrapper, and one to the actual wasm code.
+        if (UNLIKELY((sp - stackSpaceUsed) < bitwise_cast<intptr_t>(vm.softStackLimit())))
+            return JSValue::encode(throwException(exec, scope, createStackOverflowError(exec)));
+    }
     Wasm::storeContext(vm, wasmContext);
     ASSERT(wasmFunction->instance());
     ASSERT(wasmFunction->instance() == Wasm::loadContext(vm));
@@ -135,7 +144,14 @@
     // We need to make sure this is in a register or on the stack since it's stored in Vector<JSValue>.
     // This probably isn't strictly necessary, since the WebAssemblyFunction* should keep the instance
     // alive. But it's good hygiene.
-    wasmContext->use(); 
+    wasmContext->use();
+    if (prevWasmContext != wasmContext) {
+        // This is just for some extra safety instead of leaving a cached
+        // value in there. If we ever forget to set the value to be a real
+        // bounds, this will force every stack overflow check to immediately
+        // fire.
+        wasmContext->setCachedStackLimit(bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()));
+    }
     Wasm::storeContext(vm, prevWasmContext);
     RETURN_IF_EXCEPTION(scope, { });
 

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.cpp (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.cpp	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.cpp	2017-05-18 19:38:10 UTC (rev 217060)
@@ -33,10 +33,11 @@
 
 namespace JSC {
 
-const ClassInfo WebAssemblyToJSCallee::s_info = { "WebAssemblyToJSCallee", nullptr, 0, CREATE_METHOD_TABLE(WebAssemblyToJSCallee) };
+const ClassInfo WebAssemblyToJSCallee::s_info = { "WebAssemblyToJSCallee", &Base::s_info, 0, CREATE_METHOD_TABLE(WebAssemblyToJSCallee) };
 
-WebAssemblyToJSCallee* WebAssemblyToJSCallee::create(VM& vm, Structure* structure, JSWebAssemblyModule* module)
+WebAssemblyToJSCallee* WebAssemblyToJSCallee::create(VM& vm, JSWebAssemblyModule* module)
 {
+    Structure* structure = module->globalObject()->webAssemblyToJSCalleeStructure();
     WebAssemblyToJSCallee* callee = new (NotNull, allocateCell<WebAssemblyToJSCallee>(vm.heap)) WebAssemblyToJSCallee(vm, structure);
     callee->finishCreation(vm, module);
     return callee;

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.h (217059 => 217060)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.h	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyToJSCallee.h	2017-05-18 19:38:10 UTC (rev 217060)
@@ -27,18 +27,18 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "JSCell.h"
+#include "JSObject.h"
 
 namespace JSC {
 
 class JSWebAssemblyModule;
 
-class WebAssemblyToJSCallee final : public JSCell {
+class WebAssemblyToJSCallee final : public JSNonFinalObject {
 public:
-    typedef JSCell Base;
-    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+    using Base = JSNonFinalObject;
+    static const unsigned StructureFlags = Base::StructureFlags;
 
-    static WebAssemblyToJSCallee* create(VM&, Structure*, JSWebAssemblyModule*);
+    static WebAssemblyToJSCallee* create(VM&, JSWebAssemblyModule*);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_EXPORT_INFO;

Modified: trunk/Tools/ChangeLog (217059 => 217060)


--- trunk/Tools/ChangeLog	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Tools/ChangeLog	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1,3 +1,15 @@
+2017-05-18  Saam Barati  <[email protected]>
+
+        WebAssembly: perform stack checks
+        https://bugs.webkit.org/show_bug.cgi?id=165546
+        <rdar://problem/29760307>
+
+        Reviewed by Filip Pizlo.
+
+        Add some new testing modes for using and not using fast TLS wasm contexts.
+
+        * Scripts/run-jsc-stress-tests:
+
 2017-05-18  Daniel Bates  <[email protected]>
 
         REGRESSION (r209608): Cross-origin plugin document opened in child window blocked by parent

Modified: trunk/Tools/Scripts/run-jsc-stress-tests (217059 => 217060)


--- trunk/Tools/Scripts/run-jsc-stress-tests	2017-05-18 19:29:32 UTC (rev 217059)
+++ trunk/Tools/Scripts/run-jsc-stress-tests	2017-05-18 19:38:10 UTC (rev 217060)
@@ -1199,9 +1199,10 @@
     prepareExtraAbsoluteFiles(WASMTESTS_PATH, ["wasm.json"])
     prepareExtraRelativeFiles(modules.map { |f| "../" + f }, $collection)
     run("default-wasm", "-m", *FTL_OPTIONS)
-    run("wasm-no-cjit", "-m", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
+    run("wasm-no-cjit-yes-tls-context", "-m", "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
     run("wasm-eager-jettison", "-m", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
     run("wasm-no-call-ic", "-m", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
+    run("wasm-no-tls-context", "-m", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
 end
 
 def runWebAssemblyEmscripten(mode)
@@ -1214,9 +1215,10 @@
     wasm = $benchmark.to_s.sub! '.js', '.wasm'
     prepareExtraRelativeFiles([Pathname('..') + wasm], $collection)
     run("default-wasm", *FTL_OPTIONS)
-    run("wasm-no-cjit", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
+    run("wasm-no-cjit-yes-tls-context", "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
     run("wasm-eager-jettison", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
     run("wasm-no-call-ic", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
+    run("wasm-no-tls-context", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
 end
 
 def runWebAssemblySpecTest(mode)
@@ -1236,9 +1238,10 @@
     prepareExtraRelativeFiles(harness.map { |f| "../../spec-harness/" + f }, $collection)
 
     runWithOutputHandler("default-wasm", noisyOutputHandler, "../spec-harness.js", *FTL_OPTIONS)
-    runWithOutputHandler("wasm-no-cjit", noisyOutputHandler, "../spec-harness.js", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
+    runWithOutputHandler("wasm-no-cjit-yes-tls-context", noisyOutputHandler, "../spec-harness.js",  "--useFastTLSForWasmContext=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS))
     runWithOutputHandler("wasm-eager-jettison", noisyOutputHandler, "../spec-harness.js", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
     runWithOutputHandler("wasm-no-call-ic", noisyOutputHandler, "../spec-harness.js", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
+    runWithOutputHandler("wasm-no-tls-context", noisyOutputHandler, "../spec-harness.js", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
 end
 
 def runChakra(mode, exception, baselineFile, extraFiles)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to