WebAssembly: WasmB3IRGenerator should throw exceptions instead of crash
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Dec 2016 19:24:06 +0000 (19:24 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Dec 2016 19:24:06 +0000 (19:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165834

Reviewed by Keith Miller.

JSTests:

* wasm/function-tests/exceptions.js: Added.
(import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
* wasm/function-tests/table-basic.js:
(i.i.42.throw.new.Error):

Source/JavaScriptCore:

This patch generalizes how we throw exceptions in the Wasm::B3IRGenerator.
There are still places where we need to throw exceptions and we don't, but
this patch removes most of those places inside the IR generator. There are
still a few places we need to throw exceptions inside the IR generator, like
div/mod by 0. Those will be done in a separate patch. Also, there are
still some stubs we need to throw exceptions from; those will also be
done in a separate patch.

All exceptions thrown from Wasm share a common stub. The ABI for the stub
is to move the Wasm::ExceptionType into argGPR1 and jump to the stub.
The stub will then throw an exception with an error message tailored
to the particular Wasm::ExceptionType failure.

This patch also refactors B3::Compilation. Before, B3::Compilation(VM, Procedure)
constructor would compile a B3 function. This patch makes B3::Compilation a simple
tuple that keeps the necessary bits of B3 function alive in order to be runnable.
There is a new function that actually does the compilation for you. It is:
Compilation B3::compile(VM&, Procedure&)
The reason for this change is that I'm now using B3::Compilation(CodeRef, OpaqueByproducts)
constructor in Wasm code. It is weird to have a class both have a
constructor that instantiates the tuple, and another that performs the
compilation and then instantiates the tuple. It's more straight
forward if Compilation's job wasn't to actually do the compilation
but just to hold the necessary bits to keep a compiled B3 alive.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/B3Compilation.cpp:
(JSC::B3::Compilation::Compilation):
* b3/B3Compilation.h:
* b3/B3Compile.cpp: Added.
(JSC::B3::compile):
* b3/B3Compile.h: Added.
* b3/testb3.cpp:
(JSC::B3::compile):
* jit/ThunkGenerators.cpp:
(JSC::throwExceptionFromWasmThunkGenerator):
* jit/ThunkGenerators.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::emitExceptionCheck):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile):
* wasm/WasmExceptionType.h: Added.
(JSC::Wasm::errorMessageForExceptionType):

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

15 files changed:
JSTests/ChangeLog
JSTests/wasm/function-tests/exceptions.js [new file with mode: 0644]
JSTests/wasm/function-tests/table-basic.js
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/b3/B3Compilation.cpp
Source/JavaScriptCore/b3/B3Compilation.h
Source/JavaScriptCore/b3/B3Compile.cpp [new file with mode: 0644]
Source/JavaScriptCore/b3/B3Compile.h [new file with mode: 0644]
Source/JavaScriptCore/b3/testb3.cpp
Source/JavaScriptCore/jit/ThunkGenerators.cpp
Source/JavaScriptCore/jit/ThunkGenerators.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmExceptionType.h [new file with mode: 0644]

index b7c2146..e308467 100644 (file)
@@ -1,3 +1,15 @@
+2016-12-16  Saam Barati  <sbarati@apple.com>
+
+        WebAssembly: WasmB3IRGenerator should throw exceptions instead of crash
+        https://bugs.webkit.org/show_bug.cgi?id=165834
+
+        Reviewed by Keith Miller.
+
+        * wasm/function-tests/exceptions.js: Added.
+        (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+        * wasm/function-tests/table-basic.js:
+        (i.i.42.throw.new.Error):
+
 2016-12-16  Keith Miller  <keith_miller@apple.com>
 
         i64.eqz should use an Int64 zero
diff --git a/JSTests/wasm/function-tests/exceptions.js b/JSTests/wasm/function-tests/exceptions.js
new file mode 100644 (file)
index 0000000..952513f
--- /dev/null
@@ -0,0 +1,67 @@
+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", "i32"], "i32")
+            .Func(["i32"], "i32")
+        .End()
+        .Import()
+            .Table("imp", "table", tableDescription)
+        .End()
+        .Function().End()
+        .Export()
+            .Function("foo")
+            .Function("bar")
+        .End()
+        .Code()
+            .Function("foo", 0 /*['i32', 'i32'] => 'i32'*/)
+                .GetLocal(1) // parameter to call
+                .GetLocal(0) // call index
+                .CallIndirect(1, 0) // calling function of type ['i32'] => 'i32'
+                .Return()
+            .End()
+            .Function("bar", 1 /*['i32'] => 'i32'*/)
+                .GetLocal(0)
+                .I32Const(42)
+                .I32Add()
+                .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, table} = makeInstance();
+    const foo = instance.exports.foo;
+    const bar = instance.exports.bar;
+    assert.eq(table.get(0), null);
+
+    for (let i = 0; i < 1000; i++) {
+        assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a null table entry");
+    }
+
+    table.set(0, foo);
+    assert.eq(table.get(0), foo);
+
+    for (let i = 0; i < 1000; i++) {
+        assert.throws(() => foo(1 + i, i), WebAssembly.RuntimeError, "Out of bounds call_indirect");
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
+    }
+
+    table.set(0, bar);
+    assert.eq(table.get(0), bar);
+    for (let i = 0; i < 25; i++) {
+        assert.eq(foo(0, i), i + 42);
+    }
+}
index 537b1fe..2de8c7d 100644 (file)
@@ -53,15 +53,12 @@ function makeInstance() {
 // FIXME: make this work cross module. The reason it doesn't
 // now is that we don't unique Signature*.
 // https://bugs.webkit.org/show_bug.cgi?id=165511
-/*
 {
     const {instance, table} = makeInstance();
     const foo = instance.exports.foo;
-    //table.set(0, makeInstance().instance.exports.bar); // Cross instance function.
+    table.set(0, makeInstance().instance.exports.bar); // Cross instance function.
 
     for (let i = 0; i < 1000; i++) {
-        if (foo(0, i) !== i + 42)
-            throw new Error("Bad call indirect");
+        assert.throws(() => foo(0, i), WebAssembly.RuntimeError, "call_indirect to a signature that does not match");
     }
 }
-*/
index c73298a..0c7aac6 100644 (file)
@@ -116,6 +116,7 @@ set(JavaScriptCore_SOURCES
     b3/B3CheckValue.cpp
     b3/B3Common.cpp
     b3/B3Commutativity.cpp
+    b3/B3Compile.cpp
     b3/B3Compilation.cpp
     b3/B3Const32Value.cpp
     b3/B3Const64Value.cpp
index 9a73a37..f91d71e 100644 (file)
@@ -1,3 +1,56 @@
+2016-12-16  Saam Barati  <sbarati@apple.com>
+
+        WebAssembly: WasmB3IRGenerator should throw exceptions instead of crash
+        https://bugs.webkit.org/show_bug.cgi?id=165834
+
+        Reviewed by Keith Miller.
+
+        This patch generalizes how we throw exceptions in the Wasm::B3IRGenerator.
+        There are still places where we need to throw exceptions and we don't, but
+        this patch removes most of those places inside the IR generator. There are
+        still a few places we need to throw exceptions inside the IR generator, like
+        div/mod by 0. Those will be done in a separate patch. Also, there are
+        still some stubs we need to throw exceptions from; those will also be
+        done in a separate patch.
+
+        All exceptions thrown from Wasm share a common stub. The ABI for the stub
+        is to move the Wasm::ExceptionType into argGPR1 and jump to the stub.
+        The stub will then throw an exception with an error message tailored
+        to the particular Wasm::ExceptionType failure.
+
+        This patch also refactors B3::Compilation. Before, B3::Compilation(VM, Procedure)
+        constructor would compile a B3 function. This patch makes B3::Compilation a simple 
+        tuple that keeps the necessary bits of B3 function alive in order to be runnable.
+        There is a new function that actually does the compilation for you. It is:
+        Compilation B3::compile(VM&, Procedure&)
+        The reason for this change is that I'm now using B3::Compilation(CodeRef, OpaqueByproducts)
+        constructor in Wasm code. It is weird to have a class both have a
+        constructor that instantiates the tuple, and another that performs the
+        compilation and then instantiates the tuple. It's more straight
+        forward if Compilation's job wasn't to actually do the compilation
+        but just to hold the necessary bits to keep a compiled B3 alive.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/B3Compilation.cpp:
+        (JSC::B3::Compilation::Compilation):
+        * b3/B3Compilation.h:
+        * b3/B3Compile.cpp: Added.
+        (JSC::B3::compile):
+        * b3/B3Compile.h: Added.
+        * b3/testb3.cpp:
+        (JSC::B3::compile):
+        * jit/ThunkGenerators.cpp:
+        (JSC::throwExceptionFromWasmThunkGenerator):
+        * jit/ThunkGenerators.h:
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        (JSC::Wasm::B3IRGenerator::emitExceptionCheck):
+        (JSC::Wasm::createJSToWasmWrapper):
+        (JSC::Wasm::parseAndCompile):
+        * wasm/WasmExceptionType.h: Added.
+        (JSC::Wasm::errorMessageForExceptionType):
+
 2016-12-16  Keith Miller  <keith_miller@apple.com>
 
         i64.eqz should use an Int64 zero
index 2d92577..87deb6b 100644 (file)
                53FA2AE11CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FA2AE01CF37F3F0022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                53FA2AE31CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FA2AE21CF380390022711D /* LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp */; };
                53FD04D31D7AB277003287D3 /* WasmCallingConvention.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */; };
-               53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; };
+               53FD04D41D7AB291003287D3 /* WasmCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */; settings = {ATTRIBUTES = (Private, ); }; };
                53FF7F991DBFCD9000A26CCC /* WasmValidate.h in Headers */ = {isa = PBXBuildFile; fileRef = 53FF7F981DBFCD9000A26CCC /* WasmValidate.h */; };
                53FF7F9B1DBFD2B900A26CCC /* WasmValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53FF7F9A1DBFD2B900A26CCC /* WasmValidate.cpp */; };
                5B70CFDE1DB69E6600EC23F9 /* JSAsyncFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B70CFD81DB69E5C00EC23F9 /* JSAsyncFunction.h */; };
                7905BB691D12050E0019FE57 /* InlineAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 7905BB671D12050E0019FE57 /* InlineAccess.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79160DBD1C8E3EC8008C085A /* ProxyRevoke.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79160DBB1C8E3EC8008C085A /* ProxyRevoke.cpp */; };
                79160DBE1C8E3EC8008C085A /* ProxyRevoke.h in Headers */ = {isa = PBXBuildFile; fileRef = 79160DBC1C8E3EC8008C085A /* ProxyRevoke.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7919B7801E03559C005BEED8 /* B3Compile.h in Headers */ = {isa = PBXBuildFile; fileRef = 7919B77F1E03559C005BEED8 /* B3Compile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79233C2B1D34715700C5A834 /* JITMathIC.h in Headers */ = {isa = PBXBuildFile; fileRef = 79233C291D34715700C5A834 /* JITMathIC.h */; settings = {ATTRIBUTES = (Private, ); }; };
                792CB3491C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */; };
                792CB34A1C4EED5C00D13AF3 /* PCToCodeOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                795B19971D78BE3500262FA0 /* MapBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 795B19951D78BE3500262FA0 /* MapBase.cpp */; };
                795B19981D78BE3500262FA0 /* MapBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 795B19961D78BE3500262FA0 /* MapBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               795F099D1E03600500BBE37F /* B3Compile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 795F099C1E03600500BBE37F /* B3Compile.cpp */; };
                7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                796FB43A1DFF8C3F0039C95D /* JSWebAssemblyHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; };
                797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; };
                79CFC6F01C33B10000C768EA /* LLIntPCRanges.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79D5CD5A1C1106A900CECA07 /* SamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */; };
                79D5CD5B1C1106A900CECA07 /* SamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 79D5CD591C1106A900CECA07 /* SamplingProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               79DAE27A1E03C82200B526AA /* WasmExceptionType.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DAE2791E03C82200B526AA /* WasmExceptionType.h */; };
                79DFCBDB1D88C59600527D03 /* HasOwnPropertyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79E423E21DEE65320078D355 /* JSWebAssemblyCallee.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79E423E01DEE65320078D355 /* JSWebAssemblyCallee.cpp */; };
                79E423E31DEE65320078D355 /* JSWebAssemblyCallee.h in Headers */ = {isa = PBXBuildFile; fileRef = 79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7905BB671D12050E0019FE57 /* InlineAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineAccess.h; sourceTree = "<group>"; };
                79160DBB1C8E3EC8008C085A /* ProxyRevoke.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyRevoke.cpp; sourceTree = "<group>"; };
                79160DBC1C8E3EC8008C085A /* ProxyRevoke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProxyRevoke.h; sourceTree = "<group>"; };
+               7919B77F1E03559C005BEED8 /* B3Compile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3Compile.h; path = b3/B3Compile.h; sourceTree = "<group>"; };
                79233C291D34715700C5A834 /* JITMathIC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITMathIC.h; sourceTree = "<group>"; };
                792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCToCodeOriginMap.cpp; sourceTree = "<group>"; };
                792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCToCodeOriginMap.h; sourceTree = "<group>"; };
                795B19951D78BE3500262FA0 /* MapBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapBase.cpp; sourceTree = "<group>"; };
                795B19961D78BE3500262FA0 /* MapBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapBase.h; sourceTree = "<group>"; };
+               795F099C1E03600500BBE37F /* B3Compile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Compile.cpp; path = b3/B3Compile.cpp; sourceTree = "<group>"; };
                796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
                796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSWebAssemblyHelpers.h; path = js/JSWebAssemblyHelpers.h; sourceTree = "<group>"; };
                797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; };
                79CFC6EF1C33B10000C768EA /* LLIntPCRanges.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntPCRanges.h; path = llint/LLIntPCRanges.h; sourceTree = "<group>"; };
                79D5CD581C1106A900CECA07 /* SamplingProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingProfiler.cpp; sourceTree = "<group>"; };
                79D5CD591C1106A900CECA07 /* SamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingProfiler.h; sourceTree = "<group>"; };
+               79DAE2791E03C82200B526AA /* WasmExceptionType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmExceptionType.h; sourceTree = "<group>"; };
                79DFCBDA1D88C59600527D03 /* HasOwnPropertyCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HasOwnPropertyCache.h; sourceTree = "<group>"; };
                79E423E01DEE65320078D355 /* JSWebAssemblyCallee.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSWebAssemblyCallee.cpp; path = js/JSWebAssemblyCallee.cpp; sourceTree = "<group>"; };
                79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSWebAssemblyCallee.h; path = js/JSWebAssemblyCallee.h; sourceTree = "<group>"; };
                                0FEC84C01BDACDAC0080FF74 /* B3Common.h */,
                                0FEC84C11BDACDAC0080FF74 /* B3Commutativity.cpp */,
                                0FEC84C21BDACDAC0080FF74 /* B3Commutativity.h */,
+                               7919B77F1E03559C005BEED8 /* B3Compile.h */,
+                               795F099C1E03600500BBE37F /* B3Compile.cpp */,
                                0F338DFF1BF0276C0013C88F /* B3Compilation.cpp */,
                                0F338E001BF0276C0013C88F /* B3Compilation.h */,
                                0F86AE1F1C5311C5006BE8EC /* B3ComputeDivisionMagic.h */,
                                AD4B1DF81DF244D70071AE32 /* WasmBinding.h */,
                                53FD04D11D7AB187003287D3 /* WasmCallingConvention.cpp */,
                                53FD04D21D7AB187003287D3 /* WasmCallingConvention.h */,
+                               79DAE2791E03C82200B526AA /* WasmExceptionType.h */,
                                AD2FCC321DC4045300B3E736 /* WasmFormat.cpp */,
                                7BC547D21B69599B00959B58 /* WasmFormat.h */,
                                53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */,
                                52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */,
                                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */,
                                BC18C4050E16F5CD00B34460 /* FunctionPrototype.h in Headers */,
+                               7919B7801E03559C005BEED8 /* B3Compile.h in Headers */,
                                62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */,
                                FEA0C4031CDD7D1D00481991 /* FunctionWhitelist.h in Headers */,
                                2AACE63D18CA5A0300ED0191 /* GCActivityCallback.h in Headers */,
                                0F0332C418B01763005F979A /* GetByIdVariant.h in Headers */,
                                7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */,
                                14AD910E1DCA92940014F9FE /* GlobalCodeBlock.h in Headers */,
+                               79DAE27A1E03C82200B526AA /* WasmExceptionType.h in Headers */,
                                0F24E54417EA9F5900ABB217 /* GPRInfo.h in Headers */,
                                142E3134134FF0A600AFADB5 /* Handle.h in Headers */,
                                C283190016FE4B7D00157BFD /* HandleBlock.h in Headers */,
                                0FB17662196B8F9E0091052A /* DFGPureValue.cpp in Sources */,
                                0F3A1BF91A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp in Sources */,
                                0F2FCCFB18A60070001A27F8 /* DFGSafepoint.cpp in Sources */,
+                               795F099D1E03600500BBE37F /* B3Compile.cpp in Sources */,
                                86EC9DD21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp in Sources */,
                                86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */,
                                86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */,
index 48d1f77..9e20a6b 100644 (file)
 
 #if ENABLE(B3_JIT)
 
-#include "B3Generate.h"
 #include "B3OpaqueByproducts.h"
-#include "B3Procedure.h"
-#include "B3TimingScope.h"
 #include "CCallHelpers.h"
-#include "JSCInlines.h"
-#include "LinkBuffer.h"
 
 namespace JSC { namespace B3 {
 
-Compilation::Compilation(VM& vm, Procedure& proc, unsigned optLevel)
-{
-    TimingScope timingScope("Compilation");
-    
-    prepareForGeneration(proc, optLevel);
-    
-    CCallHelpers jit(&vm);
-    generate(proc, jit);
-    LinkBuffer linkBuffer(vm, jit, nullptr);
-
-    m_codeRef = FINALIZE_CODE(linkBuffer, ("B3::Compilation"));
-    m_byproducts = proc.releaseByproducts();
-}
-
 Compilation::Compilation(MacroAssemblerCodeRef codeRef, std::unique_ptr<OpaqueByproducts> byproducts)
     : m_codeRef(codeRef)
     , m_byproducts(WTFMove(byproducts))
 {
 }
 
+Compilation::Compilation(Compilation&& other)
+    : m_codeRef(WTFMove(other.m_codeRef))
+    , m_byproducts(WTFMove(other.m_byproducts))
+{
+}
+
 Compilation::~Compilation()
 {
 }
index 3d5e239..7398652 100644 (file)
@@ -40,25 +40,16 @@ namespace B3 {
 class OpaqueByproducts;
 class Procedure;
 
-// This is a fool-proof API for compiling a Procedure to code and then running that code. You compile
-// a Procedure using this API by doing:
-//
-// std::unique_ptr<Compilation> compilation = std::make_unique<Compilation>(vm, proc);
-//
-// Then you keep the Compilation object alive for as long as you want to be able to run the code. If
-// this API feels too high-level, you can use B3::generate() directly.
+// This class is a way to keep the result of a B3 compilation alive
+// and runnable.
 
 class Compilation {
     WTF_MAKE_NONCOPYABLE(Compilation);
     WTF_MAKE_FAST_ALLOCATED;
 
 public:
-    JS_EXPORT_PRIVATE Compilation(VM&, Procedure&, unsigned optLevel = 1);
-
-    // This constructor allows you to manually create a Compilation. It's currently only used by test
-    // code. Probably best to keep it that way.
     JS_EXPORT_PRIVATE Compilation(MacroAssemblerCodeRef, std::unique_ptr<OpaqueByproducts>);
-    
+    JS_EXPORT_PRIVATE Compilation(Compilation&&);
     JS_EXPORT_PRIVATE ~Compilation();
 
     MacroAssemblerCodePtr code() const { return m_codeRef.code(); }
diff --git a/Source/JavaScriptCore/b3/B3Compile.cpp b/Source/JavaScriptCore/b3/B3Compile.cpp
new file mode 100644 (file)
index 0000000..980390a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "B3Compile.h"
+
+#if ENABLE(B3_JIT)
+
+#include "B3Generate.h"
+#include "B3OpaqueByproducts.h"
+#include "B3Procedure.h"
+#include "B3TimingScope.h"
+#include "CCallHelpers.h"
+#include "JSCInlines.h"
+#include "LinkBuffer.h"
+
+namespace JSC { namespace B3 {
+
+Compilation compile(VM& vm, Procedure& proc, unsigned optLevel)
+{
+    TimingScope timingScope("Compilation");
+    
+    prepareForGeneration(proc, optLevel);
+    
+    CCallHelpers jit(&vm);
+    generate(proc, jit);
+    LinkBuffer linkBuffer(vm, jit, nullptr);
+
+    return Compilation(FINALIZE_CODE(linkBuffer, ("B3::Compilation")), proc.releaseByproducts());
+}
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
+
diff --git a/Source/JavaScriptCore/b3/B3Compile.h b/Source/JavaScriptCore/b3/B3Compile.h
new file mode 100644 (file)
index 0000000..37db160
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#if ENABLE(B3_JIT)
+
+#include "B3Compilation.h"
+
+namespace JSC {
+
+class VM;
+
+namespace B3 {
+
+class Procedure;
+
+// This is a fool-proof API for compiling a Procedure to code and then running that code. You compile
+// a Procedure using this API by doing:
+//
+// Compilation compilation = B3::compile(vm, proc);
+//
+// Then you keep the Compilation object alive for as long as you want to be able to run the code.
+// If this API feels too high-level, you can use B3::generate() directly.
+
+JS_EXPORT_PRIVATE Compilation compile(VM&, Procedure&, unsigned optLevel = 1);
+
+} } // namespace JSC::B3
+
+#endif // ENABLE(B3_JIT)
index 562ac86..6ffbfe5 100644 (file)
@@ -33,6 +33,7 @@
 #include "B3BasicBlockInlines.h"
 #include "B3CCallValue.h"
 #include "B3Compilation.h"
+#include "B3Compile.h"
 #include "B3ComputeDivisionMagic.h"
 #include "B3Const32Value.h"
 #include "B3ConstPtrValue.h"
@@ -118,7 +119,7 @@ VM* vm;
 
 std::unique_ptr<Compilation> compile(Procedure& procedure, unsigned optLevel = 1)
 {
-    return std::make_unique<Compilation>(*vm, procedure, optLevel);
+    return std::make_unique<Compilation>(B3::compile(*vm, procedure, optLevel));
 }
 
 template<typename T, typename... Arguments>
index 7a11ea6..95551c8 100644 (file)
 
 #include "CodeBlock.h"
 #include "DFGSpeculativeJIT.h"
+#include "JITExceptions.h"
 #include "JITOperations.h"
 #include "JSArray.h"
 #include "JSBoundFunction.h"
 #include "MathCommon.h"
 #include "MaxFrameExtentForSlowPathCall.h"
 #include "JSCInlines.h"
+#include "JSWebAssemblyInstance.h"
+#include "JSWebAssemblyRuntimeError.h"
 #include "SpecializedThunkJIT.h"
+#include "WasmExceptionType.h"
 #include <wtf/InlineASM.h>
 #include <wtf/StringPrintStream.h>
 #include <wtf/text/StringImpl.h>
@@ -1126,6 +1130,47 @@ MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm)
         linkBuffer, ("Specialized thunk for bound function calls with no arguments"));
 }
 
+#if ENABLE(WEBASSEMBLY)
+MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(VM* vm)
+{
+    CCallHelpers jit(vm);
+
+    // The thing that jumps here must move ExceptionType into the argumentGPR1 and jump here.
+    // We're allowed to use temp registers here, but not callee saves.
+    {
+        RegisterSet usedRegisters = RegisterSet::stubUnavailableRegisters();
+        usedRegisters.set(GPRInfo::argumentGPR1);
+        jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(usedRegisters);
+    }
+
+    jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    CCallHelpers::Call call = jit.call();
+    jit.jumpToExceptionHandler();
+
+    void (*throwWasmException)(ExecState*, Wasm::ExceptionType) = [] (ExecState* exec, Wasm::ExceptionType type) {
+        VM* vm = &exec->vm();
+        NativeCallFrameTracer tracer(vm, exec);
+
+        {
+            auto throwScope = DECLARE_THROW_SCOPE(*vm);
+            JSGlobalObject* globalObject = vm->topJSWebAssemblyInstance->globalObject();
+
+            JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(
+                exec, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
+            throwException(exec, throwScope, error);
+        }
+
+        genericUnwind(vm, exec);
+        ASSERT(!!vm->callFrameForCatch);
+    };
+
+    LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID);
+    linkBuffer.link(call, throwWasmException);
+    return FINALIZE_CODE(
+        linkBuffer, ("Throw exception from Wasm"));
+}
+#endif // ENABLE(WEBASSEMBLY)
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
index 63e882a..90740c0 100644 (file)
@@ -63,7 +63,11 @@ MacroAssemblerCodeRef imulThunkGenerator(VM*);
 MacroAssemblerCodeRef randomThunkGenerator(VM*);
 MacroAssemblerCodeRef truncThunkGenerator(VM*);
 
-MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm);
+MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM*);
+
+#if ENABLE(WEBASSEMBLY)
+MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(VM*);
+#endif
 
 }
 #endif // ENABLE(JIT)
index c2de9b3..801869a 100644 (file)
 
 #include "B3BasicBlockInlines.h"
 #include "B3CCallValue.h"
+#include "B3Compile.h"
 #include "B3ConstPtrValue.h"
 #include "B3FixSSA.h"
+#include "B3Generate.h"
 #include "B3StackmapGenerationParams.h"
 #include "B3SwitchValue.h"
 #include "B3Validate.h"
 #include "B3VariableValue.h"
 #include "B3WasmAddressValue.h"
 #include "B3WasmBoundsCheckValue.h"
-#include "ExceptionScope.h"
-#include "FrameTracers.h"
-#include "JITExceptions.h"
 #include "JSCInlines.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyModule.h"
 #include "JSWebAssemblyRuntimeError.h"
 #include "VirtualRegister.h"
 #include "WasmCallingConvention.h"
+#include "WasmExceptionType.h"
 #include "WasmFunctionParser.h"
 #include "WasmMemory.h"
 #include <wtf/Optional.h>
@@ -197,6 +197,8 @@ public:
 
     void dump(const Vector<ControlEntry>& controlStack, const ExpressionList& expressionStack);
 
+    void emitExceptionCheck(CCallHelpers&, ExceptionType);
+
 private:
     ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
     ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
@@ -217,7 +219,6 @@ private:
     GPRReg m_memorySizeGPR;
     Value* m_zeroValues[numTypes];
     Value* m_instanceValue;
-
 };
 
 B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
@@ -254,33 +255,7 @@ B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
         m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
             ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
-            jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
-
-            jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-
-            CCallHelpers::Call call = jit.call();
-            jit.jumpToExceptionHandler();
-
-            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-                void (*throwMemoryException)(ExecState*) = [] (ExecState* exec) {
-                    VM* vm = &exec->vm();
-                    NativeCallFrameTracer tracer(vm, exec);
-
-                    {
-                        auto throwScope = DECLARE_THROW_SCOPE(*vm);
-                        JSGlobalObject* globalObject = vm->topJSWebAssemblyInstance->globalObject();
-
-                        JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(
-                            exec, globalObject->WebAssemblyRuntimeErrorStructure(), "Out of bounds memory access");
-                        throwException(exec, throwScope, error);
-                    }
-
-                    genericUnwind(vm, exec);
-                    ASSERT(!!vm->callFrameForCatch);
-                };
-
-                linkBuffer.link(call, throwMemoryException);
-            });
+            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
         });
 
         B3::PatchpointValue* foo = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
@@ -296,6 +271,17 @@ B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
         m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), &m_vm.topJSWebAssemblyInstance));
 }
 
+void B3IRGenerator::emitExceptionCheck(CCallHelpers& jit, ExceptionType type)
+{
+    jit.move(CCallHelpers::TrustedImm32(static_cast<uint32_t>(type)), GPRInfo::argumentGPR1);
+    auto jumpToExceptionStub = jit.jump();
+
+    VM* vm = &m_vm;
+    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+        linkBuffer.link(jumpToExceptionStub, CodeLocationLabel(vm->getCTIStub(throwExceptionFromWasmThunkGenerator).code()));
+    });
+}
+
 Value* B3IRGenerator::zeroForType(Type type)
 {
     ASSERT(type != Void);
@@ -739,8 +725,8 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
         CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
             m_currentBlock->appendNew<Value>(m_proc, AboveEqual, Origin(), calleeIndex, callableFunctionBufferSize));
 
-        check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
-            jit.breakpoint();
+        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsCallIndirect);
         });
     }
 
@@ -758,8 +744,8 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
                 calleeSignature, 
                 m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), 0)));
 
-        check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
-            jit.breakpoint();
+        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            this->emitExceptionCheck(jit, ExceptionType::NullTableEntry);
         });
     }
 
@@ -769,8 +755,8 @@ auto B3IRGenerator::addCallIndirect(const Signature* signature, Vector<Expressio
         CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
             m_currentBlock->appendNew<Value>(m_proc, NotEqual, Origin(), calleeSignature, expectedSignature));
 
-        check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
-            jit.breakpoint();
+        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            this->emitExceptionCheck(jit, ExceptionType::BadSignature);
         });
     }
 
@@ -831,7 +817,7 @@ void B3IRGenerator::dump(const Vector<ControlEntry>& controlStack, const Express
     dataLogLn("\n");
 }
 
-static std::unique_ptr<Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFunction& function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
+static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFunction& function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
 {
     Procedure proc;
     BasicBlock* block = proc.addBlock();
@@ -840,19 +826,23 @@ static std::unique_ptr<Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFu
 
     jscCallingConvention().setupFrameInPrologue(&function.jsToWasmCalleeMoveLocation, proc, origin, block);
 
-    Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin);
-    Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, origin, CallFrameSlot::argumentCount * sizeof(Register));
-    Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, origin,
-        block->appendNew<Value>(proc, Add, origin, framePointer, offSetOfArgumentCount));
+    if (!ASSERT_DISABLED) {
+        // This should be guaranteed by our JS wrapper that handles calls to us.
+        // Just prevent against crazy when ASSERT is enabled.
+        Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin);
+        Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, origin, CallFrameSlot::argumentCount * sizeof(Register));
+        Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, origin,
+            block->appendNew<Value>(proc, Add, origin, framePointer, offSetOfArgumentCount));
 
-    Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->arguments.size());
+        Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, origin, signature->arguments.size());
 
-    CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, origin,
-        block->appendNew<Value>(proc, Above, origin, expectedArgumentCount, argumentCount));
+        CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, origin,
+            block->appendNew<Value>(proc, Above, origin, expectedArgumentCount, argumentCount));
 
-    argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
-    });
+        argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+            jit.breakpoint();
+        });
+    }
 
     // Move memory values to the approriate places, if needed.
     Value* baseMemory = nullptr;
@@ -912,7 +902,7 @@ static std::unique_ptr<Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFu
         RELEASE_ASSERT_NOT_REACHED();
     }
 
-    auto jsEntrypoint = std::make_unique<Compilation>(vm, proc);
+    auto jsEntrypoint = std::make_unique<Compilation>(B3::compile(vm, proc));
     function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters();
     return jsEntrypoint;
 }
@@ -935,8 +925,9 @@ Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm,
     if (verbose)
         dataLog("Post SSA: ", procedure);
 
-    result->wasmEntrypoint.compilation = std::make_unique<Compilation>(vm, procedure, optLevel);
+    result->wasmEntrypoint.compilation = std::make_unique<B3::Compilation>(B3::compile(vm, procedure, optLevel));
     result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+
     result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory);
     return WTFMove(result);
 }
@@ -1093,8 +1084,8 @@ auto B3IRGenerator::addOp<OpType::I32TruncSF64>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1116,8 +1107,8 @@ auto B3IRGenerator::addOp<OpType::I32TruncSF32>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1140,8 +1131,8 @@ auto B3IRGenerator::addOp<OpType::I32TruncUF64>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1163,8 +1154,8 @@ auto B3IRGenerator::addOp<OpType::I32TruncUF32>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int32, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1186,8 +1177,8 @@ auto B3IRGenerator::addOp<OpType::I64TruncSF64>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1209,8 +1200,8 @@ auto B3IRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
 
     Value* constant;
@@ -1251,8 +1242,8 @@ auto B3IRGenerator::addOp<OpType::I64TruncSF32>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterEqual, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
     PatchpointValue* patchpoint = m_currentBlock->appendNew<PatchpointValue>(m_proc, Int64, Origin());
     patchpoint->append(arg, ValueRep::SomeRegister);
@@ -1274,8 +1265,8 @@ auto B3IRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionTy
         m_currentBlock->appendNew<Value>(m_proc, GreaterThan, Origin(), arg, min));
     outOfBounds = m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), outOfBounds, zeroForType(I32));
     CheckValue* trap = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(), outOfBounds);
-    trap->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
-        jit.breakpoint();
+    trap->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTrunc);
     });
 
     Value* constant;
diff --git a/Source/JavaScriptCore/wasm/WasmExceptionType.h b/Source/JavaScriptCore/wasm/WasmExceptionType.h
new file mode 100644 (file)
index 0000000..c5979c0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+namespace JSC {
+
+namespace Wasm {
+
+#define FOR_EACH_EXCEPTION(macro) \
+    macro(OutOfBoundsMemoryAccess,  "Out of bounds memory access") \
+    macro(OutOfBoundsCallIndirect, "Out of bounds call_indirect") \
+    macro(NullTableEntry,  "call_indirect to a null table entry") \
+    macro(BadSignature, "call_indirect to a signature that does not match") \
+    macro(OutOfBoundsTrunc, "Out of bounds Trunc operation") \
+
+enum class ExceptionType : uint32_t {
+#define MAKE_ENUM(enumName, error) enumName,
+    FOR_EACH_EXCEPTION(MAKE_ENUM)
+#undef MAKE_ENUM
+};
+
+ALWAYS_INLINE const char* errorMessageForExceptionType(ExceptionType type)
+{
+    switch (type) {
+#define SWITCH_CASE(enumName, error) \
+    case ExceptionType::enumName: return error;
+
+    FOR_EACH_EXCEPTION(SWITCH_CASE)
+#undef SWITCH_CASE
+    }
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)