+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
--- /dev/null
+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);
+ }
+}
// 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");
}
}
-*/
b3/B3CheckValue.cpp
b3/B3Common.cpp
b3/B3Commutativity.cpp
+ b3/B3Compile.cpp
b3/B3Compilation.cpp
b3/B3Const32Value.cpp
b3/B3Const64Value.cpp
+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
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 */,
#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()
{
}
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(); }
--- /dev/null
+/*
+ * 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)
+
--- /dev/null
+/*
+ * 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)
#include "B3BasicBlockInlines.h"
#include "B3CCallValue.h"
#include "B3Compilation.h"
+#include "B3Compile.h"
#include "B3ComputeDivisionMagic.h"
#include "B3Const32Value.h"
#include "B3ConstPtrValue.h"
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>
#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>
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)
MacroAssemblerCodeRef randomThunkGenerator(VM*);
MacroAssemblerCodeRef truncThunkGenerator(VM*);
-MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm);
+MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM*);
+
+#if ENABLE(WEBASSEMBLY)
+MacroAssemblerCodeRef throwExceptionFromWasmThunkGenerator(VM*);
+#endif
}
#endif // ENABLE(JIT)
#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>
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);
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)
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());
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);
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);
});
}
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);
});
}
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);
});
}
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();
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;
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;
}
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);
}
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);
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);
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);
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);
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);
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;
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);
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;
--- /dev/null
+/*
+ * 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)