Title: [207453] trunk
Revision
207453
Author
keith_mil...@apple.com
Date
2016-10-17 19:02:48 -0700 (Mon, 17 Oct 2016)

Log Message

Add support for WASM Memory.
https://bugs.webkit.org/show_bug.cgi?id=161710

Reviewed by Geoffrey Garen.

JSTests:

Add store and load opcodes to wasm.json. Additionally, add new
enums for those opcodes in the generator.

* stress/wasm/generate-wasmops-header.js:
(const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.LoadOpType):
(const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.StoreOpType):

Source/_javascript_Core:

This patch add initial support for WASM memory operations. First,
it adds the concept of a WASM Module memory management object.
This object currently mmaps a 32-bit address space for WASM use,
although it marks all the memory outside the current breakpoint as
PROT_NONE. For now, we do a range check on each store and load. In
the future, we should change this to be an signal handler that
checks what module the program trapped in.

Additionally, this patch changes the way that our temporary tests
call into WASM code. There is now a true "thunk" that relocates
arguments and calls into WASM. This thunk does not tail call
because we use pinned values to memory base-pointer and
size. We use the new B3 pinned register api to pin the values.

* CMakeLists.txt:
* Configurations/ToolExecutable.xcconfig:
* _javascript_Core.xcodeproj/project.pbxproj:
* testWASM.cpp:
(runWASMTests):
(main):
* wasm/WASMB3IRGenerator.cpp:
(JSC::WASM::createJSWrapper):
(JSC::WASM::parseAndCompile):
* wasm/WASMB3IRGenerator.h:
* wasm/WASMCallingConvention.h:
(JSC::WASM::CallingConvention::iterate):
(JSC::WASM::CallingConvention::setupCall):
(JSC::WASM::nextJSCOffset):
* wasm/WASMFormat.h:
* wasm/WASMFunctionParser.h:
(JSC::WASM::FunctionParser<Context>::parseExpression):
* wasm/WASMMemory.cpp: Copied from Source/_javascript_Core/wasm/WASMPlan.cpp.
(JSC::WASM::Memory::Memory):
* wasm/WASMMemory.h: Copied from Source/_javascript_Core/wasm/WASMModuleParser.h.
(JSC::WASM::Memory::~Memory):
(JSC::WASM::Memory::memory):
(JSC::WASM::Memory::size):
(JSC::WASM::Memory::pinnedRegisters):
(JSC::WASM::Memory::mode):
(JSC::WASM::Memory::growMemory):
(JSC::WASM::Memory::offsetOfSize):
* wasm/WASMModuleParser.cpp:
(JSC::WASM::ModuleParser::parse):
(JSC::WASM::ModuleParser::parseMemory):
* wasm/WASMModuleParser.h:
(JSC::WASM::ModuleParser::functionInformation):
(JSC::WASM::ModuleParser::memory):
* wasm/WASMOps.h:
* wasm/WASMPlan.cpp:
(JSC::WASM::Plan::Plan):
* wasm/WASMPlan.h:
* wasm/WASMSections.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (207452 => 207453)


--- trunk/JSTests/ChangeLog	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/JSTests/ChangeLog	2016-10-18 02:02:48 UTC (rev 207453)
@@ -1,3 +1,17 @@
+2016-10-17  Keith Miller  <keith_mil...@apple.com>
+
+        Add support for WASM Memory.
+        https://bugs.webkit.org/show_bug.cgi?id=161710
+
+        Reviewed by Geoffrey Garen.
+
+        Add store and load opcodes to wasm.json. Additionally, add new
+        enums for those opcodes in the generator.
+
+        * stress/wasm/generate-wasmops-header.js:
+        (const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.LoadOpType):
+        (const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.StoreOpType):
+
 2016-10-17  Saam Barati  <sbar...@apple.com>
 
         Add more tests for the double->String conversion in ValueAdd constant folding

Modified: trunk/JSTests/wasm/generate-wasmops-header.js (207452 => 207453)


--- trunk/JSTests/wasm/generate-wasmops-header.js	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/JSTests/wasm/generate-wasmops-header.js	2016-10-18 02:02:48 UTC (rev 207453)
@@ -36,6 +36,10 @@
     ...opcodeMacroizer(op => op.category === "arithmetic" && op.parameter.length === 1),
     "\n\n#define FOR_EACH_WASM_BINARY_OP(macro)",
     ...opcodeMacroizer(op => (op.category === "arithmetic" || op.category === "comparison") && op.parameter.length === 2),
+    "\n\n#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro)",
+    ...opcodeMacroizer(op => (op.category === "memory" && op.return.length === 1)),
+    "\n\n#define FOR_EACH_WASM_MEMORY_STORE_OP(macro)",
+    ...opcodeMacroizer(op => (op.category === "memory" && op.return.length === 0)),
     "\n\n"].join("");
 
 const opValueSet = new Set(opcodeIterator(op => true, op => opcodes[op].value)());
@@ -94,7 +98,9 @@
     FOR_EACH_WASM_SPECIAL_OP(macro) \\
     FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \\
     FOR_EACH_WASM_UNARY_OP(macro) \\
-    FOR_EACH_WASM_BINARY_OP(macro)
+    FOR_EACH_WASM_BINARY_OP(macro) \\
+    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \\
+    FOR_EACH_WASM_MEMORY_STORE_OP(macro)
 
 #define CREATE_ENUM_VALUE(name, id, b3op) name = id,
 
@@ -118,6 +124,14 @@
     FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
 };
 
+enum class LoadOpType : uint8_t {
+    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
+};
+
+enum class StoreOpType : uint8_t {
+    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
+};
+
 #undef CREATE_ENUM_VALUE
 
 inline bool isControlOp(OpType op)

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (207452 => 207453)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-18 02:02:48 UTC (rev 207453)
@@ -863,6 +863,7 @@
     wasm/JSWASMModule.cpp
     wasm/WASMB3IRGenerator.cpp
     wasm/WASMCallingConvention.cpp
+    wasm/WASMMemory.cpp
     wasm/WASMModuleParser.cpp
     wasm/WASMPlan.cpp
     wasm/WebAssemblyObject.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (207452 => 207453)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-18 02:02:48 UTC (rev 207453)
@@ -1,3 +1,63 @@
+2016-10-17  Keith Miller  <keith_mil...@apple.com>
+
+        Add support for WASM Memory.
+        https://bugs.webkit.org/show_bug.cgi?id=161710
+
+        Reviewed by Geoffrey Garen.
+
+        This patch add initial support for WASM memory operations. First,
+        it adds the concept of a WASM Module memory management object.
+        This object currently mmaps a 32-bit address space for WASM use,
+        although it marks all the memory outside the current breakpoint as
+        PROT_NONE. For now, we do a range check on each store and load. In
+        the future, we should change this to be an signal handler that
+        checks what module the program trapped in.
+
+        Additionally, this patch changes the way that our temporary tests
+        call into WASM code. There is now a true "thunk" that relocates
+        arguments and calls into WASM. This thunk does not tail call
+        because we use pinned values to memory base-pointer and
+        size. We use the new B3 pinned register api to pin the values.
+
+        * CMakeLists.txt:
+        * Configurations/ToolExecutable.xcconfig:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * testWASM.cpp:
+        (runWASMTests):
+        (main):
+        * wasm/WASMB3IRGenerator.cpp:
+        (JSC::WASM::createJSWrapper):
+        (JSC::WASM::parseAndCompile):
+        * wasm/WASMB3IRGenerator.h:
+        * wasm/WASMCallingConvention.h:
+        (JSC::WASM::CallingConvention::iterate):
+        (JSC::WASM::CallingConvention::setupCall):
+        (JSC::WASM::nextJSCOffset):
+        * wasm/WASMFormat.h:
+        * wasm/WASMFunctionParser.h:
+        (JSC::WASM::FunctionParser<Context>::parseExpression):
+        * wasm/WASMMemory.cpp: Copied from Source/_javascript_Core/wasm/WASMPlan.cpp.
+        (JSC::WASM::Memory::Memory):
+        * wasm/WASMMemory.h: Copied from Source/_javascript_Core/wasm/WASMModuleParser.h.
+        (JSC::WASM::Memory::~Memory):
+        (JSC::WASM::Memory::memory):
+        (JSC::WASM::Memory::size):
+        (JSC::WASM::Memory::pinnedRegisters):
+        (JSC::WASM::Memory::mode):
+        (JSC::WASM::Memory::growMemory):
+        (JSC::WASM::Memory::offsetOfSize):
+        * wasm/WASMModuleParser.cpp:
+        (JSC::WASM::ModuleParser::parse):
+        (JSC::WASM::ModuleParser::parseMemory):
+        * wasm/WASMModuleParser.h:
+        (JSC::WASM::ModuleParser::functionInformation):
+        (JSC::WASM::ModuleParser::memory):
+        * wasm/WASMOps.h:
+        * wasm/WASMPlan.cpp:
+        (JSC::WASM::Plan::Plan):
+        * wasm/WASMPlan.h:
+        * wasm/WASMSections.h:
+
 2016-10-17  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: Add toggles for debugger pauses at console.assert failures

Modified: trunk/Source/_javascript_Core/Configurations/ToolExecutable.xcconfig (207452 => 207453)


--- trunk/Source/_javascript_Core/Configurations/ToolExecutable.xcconfig	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/Configurations/ToolExecutable.xcconfig	2016-10-18 02:02:48 UTC (rev 207453)
@@ -31,6 +31,7 @@
 CODE_SIGN_ENTITLEMENTS_ios_testair = entitlements.plist;
 CODE_SIGN_ENTITLEMENTS_ios_testapi = entitlements.plist;
 CODE_SIGN_ENTITLEMENTS_ios_testb3 = entitlements.plist;
+CODE_SIGN_ENTITLEMENTS_ios_testWASM = entitlements.plist;
 CODE_SIGN_ENTITLEMENTS_ios_testRegExp = entitlements.plist;
 
 SKIP_INSTALL = $(SKIP_INSTALL_$(FORCE_TOOL_INSTALL));

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (207452 => 207453)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-18 02:02:48 UTC (rev 207453)
@@ -1216,6 +1216,8 @@
 		534C457C1BC72411007476A7 /* JSTypedArrayViewConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */; };
 		534C457E1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */; };
 		53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 53529A4B1C457B75000B49C6 /* APIUtils.h */; };
+		535557141D9D9EA5006D583B /* WASMMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 535557131D9D9EA5006D583B /* WASMMemory.h */; };
+		535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 535557151D9DFA32006D583B /* WASMMemory.cpp */; };
 		5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
 		5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
 		53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
@@ -3463,6 +3465,8 @@
 		534C457B1BC72411007476A7 /* JSTypedArrayViewConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewConstructor.h; sourceTree = "<group>"; };
 		534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewConstructor.cpp; sourceTree = "<group>"; };
 		53529A4B1C457B75000B49C6 /* APIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIUtils.h; sourceTree = "<group>"; };
+		535557131D9D9EA5006D583B /* WASMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMMemory.h; sourceTree = "<group>"; };
+		535557151D9DFA32006D583B /* WASMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMMemory.cpp; sourceTree = "<group>"; };
 		5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
 		5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
 		53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
@@ -5699,6 +5703,8 @@
 				53F40E901D5903020099A1B6 /* WASMOps.h */,
 				7BC547D21B69599B00959B58 /* WASMFormat.h */,
 				53F40E8A1D5901BB0099A1B6 /* WASMFunctionParser.h */,
+				535557151D9DFA32006D583B /* WASMMemory.cpp */,
+				535557131D9D9EA5006D583B /* WASMMemory.h */,
 				53F40E961D5A7BEC0099A1B6 /* WASMModuleParser.cpp */,
 				53F40E941D5A7AEF0099A1B6 /* WASMModuleParser.h */,
 				531374BE1D5CE95000AF7A0B /* WASMPlan.cpp */,
@@ -7871,6 +7877,7 @@
 				142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */,
 				1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
 				0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,
+				535557141D9D9EA5006D583B /* WASMMemory.h in Headers */,
 				14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
 				0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */,
 				C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */,
@@ -9213,6 +9220,7 @@
 				0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */,
 				0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */,
 				0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */,
+				535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */,
 				0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */,
 				0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */,
 				A78A9774179738B8009DF744 /* DFGFailedFinalizer.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/testWASM.cpp (207452 => 207453)


--- trunk/Source/_javascript_Core/testWASM.cpp	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/testWASM.cpp	2016-10-18 02:02:48 UTC (rev 207453)
@@ -32,7 +32,9 @@
 #include "LLIntThunks.h"
 #include "ProtoCallFrame.h"
 #include "VM.h"
+#include "WASMMemory.h"
 #include "WASMPlan.h"
+
 #include <wtf/DataLog.h>
 #include <wtf/LEBDecoder.h>
 
@@ -242,8 +244,469 @@
 {
     {
         // Generated from:
+        // (module
+        //  (memory 1)
+        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //   (i64.store (get_local $ptr) (get_local $i))
+        //   (return (i64.load (get_local $ptr)))
+        //   )
+        //  )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
+            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+    }
+
+    {
+        // Generated from:
+        // (module
+        //  (memory 1)
+        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //   (i32.store (get_local $ptr) (get_local $i))
+        //   (return (i32.load (get_local $ptr)))
+        //   )
+        //  )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
+            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+    }
+
+    {
+        // Generated from:
         //    (module
-        //     (func (export "dumb-eq") (param $x i32) (param $y i32) (result i32)
+        //     (memory 1)
+        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
+        //      (set_local $i (i32.const 0))
+        //      (block
+        //       (loop
+        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
+        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
+        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
+        //        (br 0)
+        //        )
+        //       )
+        //      (return)
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
+            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
+            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
+            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
+            0x0f, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        unsigned length = 5;
+        unsigned offset = sizeof(uint32_t);
+        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
+        offset /= sizeof(uint32_t);
+        CHECK_EQ(memory[offset - 1], 0u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 100u);
+
+        length = 10;
+        offset = 5 * sizeof(uint32_t);
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
+        offset /= sizeof(uint32_t);
+        CHECK_EQ(memory[offset - 1], 100u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 5u);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
+        //      (set_local $i (i32.const 0))
+        //      (block
+        //       (loop
+        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
+        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
+        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
+        //        (br 0)
+        //        )
+        //       )
+        //      (return)
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
+            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
+            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
+            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        unsigned length = 5;
+        unsigned offset = 1;
+        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
+        CHECK_EQ(memory[offset - 1], 0u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 100u);
+
+        length = 10;
+        offset = 5;
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
+        CHECK_EQ(memory[offset - 1], 100u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 5u);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //      (i32.store8 (get_local $ptr) (get_local $i))
+        //      (return (i32.load8_s (get_local $ptr)))
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
+            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "i32_load8_s") (param $i i32) (result i32)
+        //      (i32.store8 (i32.const 8) (get_local $i))
+        //      (return (i32.load8_s (i32.const 8)))
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
+            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
+            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
+            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
+            0x20, 0x00, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
+    }
+
+    {
+        // Generated from:
+        // (module
+        //  (memory 1)
+        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //   (i32.store (get_local $ptr) (get_local $i))
+        //   (return (i32.load (get_local $ptr)))
+        //   )
+        //  )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
+            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-12), box(plan.memory->size() - sizeof(uint64_t)) }), -12);
+    }
+
+    {
+        // Generated from:
+        // (module
+        //  (memory 1)
+        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //   (i32.store (get_local $ptr) (get_local $i))
+        //   (return (i32.load (get_local $ptr)))
+        //   )
+        //  )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
+            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
+        //      (set_local $i (i32.const 0))
+        //      (block
+        //       (loop
+        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
+        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
+        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
+        //        (br 0)
+        //        )
+        //       )
+        //      (return)
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
+            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
+            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
+            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
+            0x0f, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        unsigned length = 5;
+        unsigned offset = sizeof(uint32_t);
+        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
+        offset /= sizeof(uint32_t);
+        CHECK_EQ(memory[offset - 1], 0u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 100u);
+
+        length = 10;
+        offset = 5 * sizeof(uint32_t);
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
+        offset /= sizeof(uint32_t);
+        CHECK_EQ(memory[offset - 1], 100u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 5u);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
+        //      (set_local $i (i32.const 0))
+        //      (block
+        //       (loop
+        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
+        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
+        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
+        //        (br 0)
+        //        )
+        //       )
+        //      (return)
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
+            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
+            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
+            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        unsigned length = 5;
+        unsigned offset = 1;
+        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
+        CHECK_EQ(memory[offset - 1], 0u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 100u);
+
+        length = 10;
+        offset = 5;
+        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
+        CHECK_EQ(memory[offset - 1], 100u);
+        CHECK_EQ(memory[offset + length], 0u);
+        for (unsigned i = 0; i < length; ++i)
+            CHECK_EQ(memory[i + offset], 5u);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
+        //      (i32.store8 (get_local $ptr) (get_local $i))
+        //      (return (i32.load8_s (get_local $ptr)))
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
+            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
+            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
+            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
+            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+        ASSERT(plan.memory->size());
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (memory 1)
+        //     (func (export "i32_load8_s") (param $i i32) (result i32)
+        //      (i32.store8 (i32.const 8) (get_local $i))
+        //      (return (i32.load8_s (i32.const 8)))
+        //      )
+        //     )
+        Vector<uint8_t> vector = {
+            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
+            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
+            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
+            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
+            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
+            0x20, 0x00, 0x00, 0x09, 0x0f
+        };
+
+        Plan plan(*vm, vector);
+        if (plan.result.size() != 1 || !plan.result[0]) {
+            dataLogLn("Module failed to compile correctly.");
+            CRASH();
+        }
+
+        // Test this doesn't crash.
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
+    }
+
+    {
+        // Generated from:
+        //    (module
+        //     (func "dumb-eq" (param $x i32) (param $y i32) (result i32)
         //      (if (i32.eq (get_local $x) (get_local $y))
         //       (then (br 0))
         //       (else (return (i32.const 1))))
@@ -265,14 +728,14 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 1);
     }
 
     {
@@ -306,14 +769,14 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
     }
 
 
@@ -333,7 +796,7 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { }), 5);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 5);
     }
 
 
@@ -354,7 +817,7 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
     }
 
     {
@@ -374,7 +837,7 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
     }
 
     {
@@ -394,7 +857,7 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
     }
 
     {
@@ -413,10 +876,10 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(1) }), 101);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(-1), box(1)}), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(1) }), 101);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-1), box(1)}), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
     }
 
     {
@@ -442,8 +905,8 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(10) }), 10);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(10) }), 10);
     }
 
     {
@@ -478,10 +941,10 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2)}), 3);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100) }), 5050);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2)}), 3);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 5050);
     }
 
     {
@@ -522,14 +985,14 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 2);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 2);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 4);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 12);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 600);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(100) }), 10000);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 2);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 2);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 4);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 12);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 600);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(100) }), 10000);
     }
 
     {
@@ -575,14 +1038,14 @@
         }
 
         // Test this doesn't crash.
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
-        CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
+        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
     }
 
 }
@@ -596,7 +1059,6 @@
     if (options.m_runLEBTests)
         runLEBTests();
 
-
     if (options.m_runWASMTests) {
 #if ENABLE(WEBASSEMBLY)
         JSC::initializeThreading();

Modified: trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.cpp	2016-10-18 02:02:48 UTC (rev 207453)
@@ -29,14 +29,19 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3BasicBlockInlines.h"
+#include "B3ConstPtrValue.h"
 #include "B3FixSSA.h"
+#include "B3StackmapGenerationParams.h"
 #include "B3Validate.h"
 #include "B3ValueInlines.h"
 #include "B3Variable.h"
 #include "B3VariableValue.h"
+#include "B3WasmAddressValue.h"
+#include "B3WasmBoundsCheckValue.h"
 #include "VirtualRegister.h"
 #include "WASMCallingConvention.h"
 #include "WASMFunctionParser.h"
+#include "WASMMemory.h"
 #include <wtf/Optional.h>
 
 void dumpProcedure(void* ptr)
@@ -165,18 +170,25 @@
     typedef Vector<Variable*, 1> ResultList;
     static constexpr ExpressionType emptyExpression = nullptr;
 
-    B3IRGenerator(Procedure&);
+    B3IRGenerator(Memory*, Procedure&);
 
     void addArguments(const Vector<Type>&);
     void addLocal(Type, uint32_t);
     ExpressionType addConstant(Type, uint64_t);
 
+    // Locals
     bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
 
+    // Memory
+    bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
+    bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
+
+    // Basic operators
     bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
     bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
 
+    // Control flow
     ControlData WARN_UNUSED_RETURN addBlock(Type signature);
     ControlData WARN_UNUSED_RETURN addLoop(Type signature);
     ControlData WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature);
@@ -191,18 +203,41 @@
     void dump(const Vector<ControlType>& controlStack, const ExpressionList& expressionStack);
 
 private:
+    ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
+    ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
+    void emitStoreOp(StoreOpType, Origin, ExpressionType pointer, ExpressionType value, uint32_t offset);
+
     void unify(Variable* target, const ExpressionType source);
     void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
 
+    Memory* m_memory;
     Procedure& m_proc;
     BasicBlock* m_currentBlock;
     Vector<Variable*> m_locals;
+    GPRReg m_memoryBaseGPR;
+    GPRReg m_memorySizeGPR;
 };
 
-B3IRGenerator::B3IRGenerator(Procedure& procedure)
-    : m_proc(procedure)
+B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure)
+    : m_memory(memory)
+    , m_proc(procedure)
 {
     m_currentBlock = m_proc.addBlock();
+
+    if (m_memory) {
+        m_memoryBaseGPR = m_memory->pinnedRegisters().baseMemoryPointer;
+        m_proc.pinRegister(m_memoryBaseGPR);
+        ASSERT(!m_memory->pinnedRegisters().sizeRegisters[0].sizeOffset);
+        m_memorySizeGPR = m_memory->pinnedRegisters().sizeRegisters[0].sizeRegister;
+        for (const PinnedSizeRegisterInfo& info : m_memory->pinnedRegisters().sizeRegisters)
+            m_proc.pinRegister(info.sizeRegister);
+    }
+
+    m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
+        ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
+        // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351
+        jit.breakpoint();
+    });
 }
 
 void B3IRGenerator::addLocal(Type type, uint32_t count)
@@ -224,7 +259,7 @@
         });
 }
 
-bool WARN_UNUSED_RETURN B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
+bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
 {
     ASSERT(m_locals[index]);
     result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, Origin(), m_locals[index]);
@@ -231,7 +266,7 @@
     return true;
 }
 
-bool WARN_UNUSED_RETURN B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
+bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
 {
     ASSERT(m_locals[index]);
     m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
@@ -238,6 +273,174 @@
     return true;
 }
 
+inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation)
+{
+    ASSERT(m_memoryBaseGPR && m_memorySizeGPR);
+    ASSERT(sizeOfOperation + offset > offset);
+    m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, Origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1);
+    pointer = m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), pointer);
+    return m_currentBlock->appendNew<WasmAddressValue>(m_proc, Origin(), pointer, m_memoryBaseGPR);
+}
+
+inline uint32_t sizeOfLoadOp(LoadOpType op)
+{
+    switch (op) {
+    case LoadOpType::I32Load8S:
+    case LoadOpType::I32Load8U:
+    case LoadOpType::I64Load8S:
+    case LoadOpType::I64Load8U:
+        return 1;
+    case LoadOpType::I32Load16S:
+    case LoadOpType::I64Load16S:
+        return 2;
+    case LoadOpType::I32Load:
+    case LoadOpType::I64Load32S:
+    case LoadOpType::I64Load32U:
+        return 4;
+    case LoadOpType::I64Load:
+        return 8;
+    case LoadOpType::I32Load16U:
+    case LoadOpType::I64Load16U:
+    case LoadOpType::F32Load:
+    case LoadOpType::F64Load:
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, Origin origin, ExpressionType pointer, uint32_t offset)
+{
+    switch (op) {
+    case LoadOpType::I32Load8S: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
+    }
+
+    case LoadOpType::I64Load8S: {
+        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
+        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
+    }
+
+    case LoadOpType::I32Load8U: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
+    }
+
+    case LoadOpType::I64Load8U: {
+        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
+        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
+    }
+
+    case LoadOpType::I32Load16S: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
+    }
+    case LoadOpType::I64Load16S: {
+        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
+        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
+    }
+
+    case LoadOpType::I32Load: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
+    }
+
+    case LoadOpType::I64Load32U: {
+        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
+        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
+    }
+
+    case LoadOpType::I64Load32S: {
+        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
+        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
+    }
+
+    case LoadOpType::I64Load: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin, pointer);
+    }
+
+    case LoadOpType::F32Load: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Float, origin, pointer);
+    }
+
+    case LoadOpType::F64Load: {
+        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Double, origin, pointer);
+    }
+
+    // B3 doesn't support Load16Z yet.
+    case LoadOpType::I32Load16U:
+    case LoadOpType::I64Load16U:
+        break;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset)
+{
+    ASSERT(pointer->type() == Int32);
+
+    result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset);
+    return true;
+}
+
+inline uint32_t sizeOfStoreOp(StoreOpType op)
+{
+    switch (op) {
+    case StoreOpType::I32Store8:
+    case StoreOpType::I64Store8:
+        return 1;
+    case StoreOpType::I32Store16:
+    case StoreOpType::I64Store16:
+        return 2;
+    case StoreOpType::I32Store:
+    case StoreOpType::I64Store32:
+    case StoreOpType::F32Store:
+        return 4;
+    case StoreOpType::I64Store:
+    case StoreOpType::F64Store:
+        return 8;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+
+inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, ExpressionType pointer, ExpressionType value, uint32_t offset)
+{
+    switch (op) {
+    case StoreOpType::I64Store8:
+        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
+        FALLTHROUGH;
+
+    case StoreOpType::I32Store8:
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Store8, origin, value, pointer, offset);
+        return;
+
+    case StoreOpType::I64Store16:
+        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
+        FALLTHROUGH;
+
+    case StoreOpType::I32Store16:
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Store16, origin, value, pointer, offset);
+        return;
+
+    case StoreOpType::I64Store32:
+        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
+        FALLTHROUGH;
+
+    case StoreOpType::I64Store:
+    case StoreOpType::I32Store:
+    case StoreOpType::F32Store:
+    case StoreOpType::F64Store:
+        m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin, value, pointer, offset);
+        return;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+bool B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
+{
+    ASSERT(pointer->type() == Int32);
+
+    emitStoreOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset);
+    return true;
+}
+
 bool B3IRGenerator::unaryOp(UnaryOpType op, ExpressionType arg, ExpressionType& result)
 {
     result = m_currentBlock->appendNew<Value>(m_proc, toB3Op(op), Origin(), arg);
@@ -403,10 +606,69 @@
 
 } // anonymous namespace
 
-std::unique_ptr<Compilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, FunctionInformation info, unsigned optLevel)
+
+static std::unique_ptr<Compilation> createJSWrapper(VM& vm, const Signature* signature, MacroAssemblerCodePtr mainFunction, Memory* memory)
 {
+    Procedure proc;
+    BasicBlock* block = proc.addBlock();
+
+    // Check argument count is sane.
+    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());
+
+    CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, Origin(),
+        block->appendNew<Value>(proc, Above, Origin(), expectedArgumentCount, argumentCount));
+    argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
+        jit.breakpoint();
+    });
+
+    // Move memory values to the approriate places, if needed.
+    Value* baseMemory = nullptr;
+    Vector<Value*> sizes;
+    if (memory) {
+        baseMemory = block->appendNew<ConstPtrValue>(proc, Origin(), memory->memory());
+        Value* size = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
+            block->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<char*>(memory) + Memory::offsetOfSize()));
+        sizes.reserveCapacity(memory->pinnedRegisters().sizeRegisters.size());
+        for (auto info : memory->pinnedRegisters().sizeRegisters) {
+            sizes.append(block->appendNew<Value>(proc, Sub, Origin(), size,
+                block->appendNew<Const32Value>(proc, Origin(), info.sizeOffset)));
+        }
+    }
+
+    // Get our arguments.
+    Vector<Value*> arguments;
+    jscCallingConvention().iterate(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {
+        arguments.append(argument);
+    });
+
+    // Move the arguments into place.
+    Value* result = jscCallingConvention().setupCall(proc, block, Origin(), mainFunction, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
+        if (memory) {
+            ASSERT(sizes.size() == memory->pinnedRegisters().sizeRegisters.size());
+            patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory->pinnedRegisters().baseMemoryPointer)));
+            for (unsigned i = 0; i < sizes.size(); ++i)
+                patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory->pinnedRegisters().sizeRegisters[i].sizeRegister)));
+        }
+    });
+
+    // Return the result, if needed.
+    if (signature->returnType != Void)
+        block->appendNewControlValue(proc, B3::Return, Origin(), result);
+    else
+        block->appendNewControlValue(proc, B3::Return, Origin());
+
+    return std::make_unique<Compilation>(vm, proc);
+}
+
+std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, unsigned optLevel)
+{
     Procedure procedure;
-    B3IRGenerator context(procedure);
+    B3IRGenerator context(memory, procedure);
     FunctionParser<B3IRGenerator> parser(context, source, info);
     if (!parser.parse())
         RELEASE_ASSERT_NOT_REACHED();
@@ -417,7 +679,11 @@
     fixSSA(procedure);
     if (verbose)
         dataLog("Post SSA: ", procedure);
-    return std::make_unique<Compilation>(vm, procedure, optLevel);
+    auto result = std::make_unique<FunctionCompilation>();
+
+    result->code = std::make_unique<Compilation>(vm, procedure, optLevel);
+    result->jsEntryPoint = createJSWrapper(vm, info.signature, result->code->code(), memory);
+    return result;
 }
 
 } } // namespace JSC::WASM

Modified: trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMB3IRGenerator.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -35,8 +35,10 @@
 
 namespace JSC { namespace WASM {
 
-std::unique_ptr<B3::Compilation> parseAndCompile(VM&, Vector<uint8_t>&, FunctionInformation, unsigned optLevel = 1);
+class Memory;
 
+std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, unsigned optLevel = 1);
+
 } } // namespace JSC::WASM
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/WASMCallingConvention.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMCallingConvention.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMCallingConvention.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -27,23 +27,27 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "AllowMacroScratchRegisterUsage.h"
 #include "B3ArgumentRegValue.h"
 #include "B3BasicBlock.h"
 #include "B3Const64Value.h"
+#include "B3ConstrainedValue.h"
 #include "B3MemoryValue.h"
+#include "B3PatchpointValue.h"
+#include "B3Procedure.h"
+#include "B3StackmapGenerationParams.h"
 #include "CallFrame.h"
+#include "LinkBuffer.h"
 #include "RegisterSet.h"
 #include "WASMFormat.h"
 
 namespace JSC { namespace WASM {
 
-typedef unsigned (*NextOffset)(unsigned currentOffset, Type type);
+typedef unsigned (*NextOffset)(unsigned currentOffset, B3::Type type);
 
-template<unsigned offset, NextOffset updateOffset>
+template<unsigned headerSize, NextOffset updateOffset>
 class CallingConvention {
 public:
-    static const unsigned headerSize = offset;
-
     CallingConvention(Vector<GPRReg>&& registerArguments, RegisterSet&& calleeSaveRegisters)
         : m_registerArguments(registerArguments)
         , m_calleeSaveRegisters(calleeSaveRegisters)
@@ -64,18 +68,55 @@
                 B3::Value* address = block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer,
                     block->appendNew<B3::Const64Value>(proc, origin, currentOffset));
                 argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, toB3Type(argumentTypes[i]), origin, address);
-                currentOffset = updateOffset(currentOffset, argumentTypes[i]);
+                currentOffset = updateOffset(currentOffset, toB3Type(argumentTypes[i]));
             }
             functor(argument, i);
         }
     }
 
+    template<typename Functor>
+    B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, MacroAssemblerCodePtr target, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const
+    {
+        size_t stackArgumentCount = arguments.size() < m_registerArguments.size() ? 0 : arguments.size() - m_registerArguments.size();
+        unsigned offset = headerSize - sizeof(CallerFrameAndPC);
+
+        proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), headerSize + (stackArgumentCount * sizeof(Register))));
+        Vector<B3::ConstrainedValue> constrainedArguments;
+        for (unsigned i = 0; i < arguments.size(); ++i) {
+            B3::ValueRep rep;
+            if (i < m_registerArguments.size())
+                rep = B3::ValueRep::reg(m_registerArguments[i]);
+            else
+                rep = B3::ValueRep::stackArgument(offset);
+            constrainedArguments.append(B3::ConstrainedValue(arguments[i], rep));
+            offset = updateOffset(offset, arguments[i]->type());
+        }
+
+        B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin);
+        patchpoint->appendVector(constrainedArguments);
+        patchpointFunctor(patchpoint);
+        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+
+            CCallHelpers::Call call = jit.call();
+            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+                linkBuffer.link(call, FunctionPtr(target.executableAddress()));
+            });
+        });
+
+        if (returnType == B3::Void)
+            return nullptr;
+
+        patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR);
+        return patchpoint;
+    }
+
     const Vector<GPRReg> m_registerArguments;
     const RegisterSet m_calleeSaveRegisters;
     const RegisterSet m_callerSaveRegisters;
 };
 
-inline unsigned nextJSCOffset(unsigned currentOffset, Type)
+inline unsigned nextJSCOffset(unsigned currentOffset, B3::Type)
 {
     return currentOffset + sizeof(Register);
 }

Modified: trunk/Source/_javascript_Core/wasm/WASMFormat.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMFormat.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMFormat.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -44,6 +44,7 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "B3Compilation.h"
 #include "B3Type.h"
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
@@ -126,6 +127,11 @@
     size_t end;
 };
 
+struct FunctionCompilation {
+    std::unique_ptr<B3::Compilation> code;
+    std::unique_ptr<B3::Compilation> jsEntryPoint;
+};
+
 } } // namespace JSC::WASM
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -154,6 +154,37 @@
         return true;
     }
 
+    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
+        uint32_t alignment;
+        if (!parseVarUInt32(alignment))
+            return false;
+
+        uint32_t offset;
+        if (!parseVarUInt32(offset))
+            return false;
+
+        ExpressionType pointer = m_expressionStack.takeLast();
+        ExpressionType result;
+        if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset))
+            return false;
+        m_expressionStack.append(result);
+        return true;
+    }
+
+    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
+        uint32_t alignment;
+        if (!parseVarUInt32(alignment))
+            return false;
+
+        uint32_t offset;
+        if (!parseVarUInt32(offset))
+            return false;
+
+        ExpressionType value = m_expressionStack.takeLast();
+        ExpressionType pointer = m_expressionStack.takeLast();
+        return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset);
+    }
+
     case OpType::I32Const: {
         uint32_t constant;
         if (!parseVarUInt32(constant))

Added: trunk/Source/_javascript_Core/wasm/WASMMemory.cpp (0 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMMemory.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/wasm/WASMMemory.cpp	2016-10-18 02:02:48 UTC (rev 207453)
@@ -0,0 +1,77 @@
+/*
+ * 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 "WASMMemory.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+namespace JSC { namespace WASM {
+
+Memory::Memory(uint32_t startingSize, uint32_t capacity, const Vector<unsigned>& pinnedSizeRegisters)
+    : m_mode(Mode::BoundsChecking)
+    , m_size(startingSize)
+    , m_capacity(capacity)
+    // FIXME: If we add signal based bounds checking then we need extra space for overflow on load.
+    // see: https://bugs.webkit.org/show_bug.cgi?id=162693
+    , m_mappedCapacity(static_cast<uint64_t>(maxPageCount) * static_cast<uint64_t>(pageSize))
+{
+    ASSERT(pinnedSizeRegisters.size() > 0);
+
+    void* result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, 0, 0);
+    if (result == MAP_FAILED) {
+        // Try again with a different number.
+        m_mappedCapacity = m_capacity;
+        result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, 0, 0);
+        if (result == MAP_FAILED)
+            return;
+    }
+
+    if (mprotect(result, startingSize, PROT_READ | PROT_WRITE)) {
+        munmap(result, m_mappedCapacity);
+        return;
+    }
+
+    unsigned remainingPinnedRegisters = pinnedSizeRegisters.size() + 1;
+    jscCallingConvention().m_calleeSaveRegisters.forEach([&] (Reg reg) {
+        GPRReg gpr = reg.gpr();
+        if (!remainingPinnedRegisters || RegisterSet::stackRegisters().get(reg))
+            return;
+        if (remainingPinnedRegisters == 1) {
+            m_pinnedRegisters.baseMemoryPointer = gpr;
+            remainingPinnedRegisters--;
+        } else
+            m_pinnedRegisters.sizeRegisters.append({ gpr, pinnedSizeRegisters[--remainingPinnedRegisters - 1] });
+    });
+
+    ASSERT(!remainingPinnedRegisters);
+    m_memory = result;
+}
+
+} // namespace JSC
+
+} // namespace WASM
+
+#endif // ENABLE(WEBASSEMBLY)

Added: trunk/Source/_javascript_Core/wasm/WASMMemory.h (0 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMMemory.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/wasm/WASMMemory.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -0,0 +1,99 @@
+/*
+ * 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)
+
+#include "WASMCallingConvention.h"
+
+#include <wtf/Vector.h>
+
+namespace JSC { namespace WASM {
+
+struct PinnedSizeRegisterInfo {
+    GPRReg sizeRegister;
+    unsigned sizeOffset;
+};
+
+// FIXME: We should support more than one memory size register. Right now we take a vector with only one
+// entry. Specifically an extry where the sizeOffset == 0. If we have more than one size register,
+// we can have one for each load size class. see: https://bugs.webkit.org/show_bug.cgi?id=162952
+struct PinnedRegisterInfo {
+    Vector<PinnedSizeRegisterInfo> sizeRegisters;
+    GPRReg baseMemoryPointer;
+};
+
+constexpr uint32_t pageSize = 64 * KB;
+constexpr uint32_t maxPageCount = static_cast<uint32_t>((1ull << 32) / pageSize);
+
+class Memory {
+    WTF_MAKE_NONCOPYABLE(Memory);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+
+    // FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
+    enum class Mode {
+        BoundsChecking
+    };
+
+    Memory() = default;
+    Memory(uint32_t startingSize, uint32_t capacity, const Vector<unsigned>& pinnedSizeRegisters);
+
+    ~Memory()
+    {
+        if (m_memory)
+            munmap(m_memory, m_mappedCapacity);
+    }
+
+    void* memory() const { return m_memory; }
+    uint32_t size() const { return m_size; }
+    const PinnedRegisterInfo& pinnedRegisters() const { return m_pinnedRegisters; }
+
+    Mode mode() const { return m_mode; }
+
+    bool grow(uint32_t newSize)
+    {
+        ASSERT(m_memory);
+        if (newSize > m_capacity)
+            return false;
+
+        return !mprotect(m_memory, newSize, PROT_READ | PROT_WRITE);
+    }
+
+    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
+    
+private:
+    void* m_memory { nullptr };
+    PinnedRegisterInfo m_pinnedRegisters;
+    Mode m_mode;
+    uint32_t m_size { 0 };
+    uint32_t m_capacity { 0 };
+    uint64_t m_mappedCapacity { 0 };
+};
+
+} } // namespace JSC::WASM
+
+#endif // ENABLE(WEBASSEMLY)

Modified: trunk/Source/_javascript_Core/wasm/WASMModuleParser.cpp (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMModuleParser.cpp	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMModuleParser.cpp	2016-10-18 02:02:48 UTC (rev 207453)
@@ -28,10 +28,13 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "JSWASMModule.h"
 #include "WASMFormat.h"
 #include "WASMOps.h"
 #include "WASMSections.h"
 
+#include <sys/mman.h>
+
 namespace JSC { namespace WASM {
 
 static const bool verbose = false;
@@ -62,15 +65,16 @@
         if (verbose)
             dataLogLn("Starting to parse next section at offset: ", m_offset);
 
-        Sections::Section section = Sections::Unknown;
         uint8_t sectionByte;
         if (!parseUInt7(sectionByte))
             return false;
 
+        if (verbose)
+            dataLogLn("Section byte: ", sectionByte);
+
+        Sections::Section section = Sections::Unknown;
         if (sectionByte) {
-            if (sectionByte >= Sections::Unknown)
-                section = Sections::Unknown;
-            else
+            if (sectionByte < Sections::Unknown)
                 section = static_cast<Sections::Section>(sectionByte);
         } else {
             uint32_t sectionNameLength;
@@ -96,6 +100,15 @@
         unsigned end = m_offset + sectionLength;
 
         switch (section) {
+
+        case Sections::Memory: {
+            if (verbose)
+                dataLogLn("Parsing Memory.");
+            if (!parseMemory())
+                return false;
+            break;
+        }
+
         case Sections::FunctionTypes: {
             if (verbose)
                 dataLogLn("Parsing types.");
@@ -143,6 +156,34 @@
     return true;
 }
 
+bool ModuleParser::parseMemory()
+{
+    uint8_t flags;
+    if (!parseVarUInt1(flags))
+        return false;
+
+    uint32_t size;
+    if (!parseVarUInt32(size))
+        return false;
+    if (size > maxPageCount)
+        return false;
+
+    uint32_t capacity = maxPageCount;
+    if (flags) {
+        if (!parseVarUInt32(capacity))
+            return false;
+        if (size > capacity || capacity > maxPageCount)
+            return false;
+    }
+
+    capacity *= pageSize;
+    size *= pageSize;
+
+    Vector<unsigned> pinnedSizes = { 0 };
+    m_memory = std::make_unique<Memory>(size, capacity, pinnedSizes);
+    return m_memory->memory();
+}
+
 bool ModuleParser::parseFunctionTypes()
 {
     uint32_t count;

Modified: trunk/Source/_javascript_Core/wasm/WASMModuleParser.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMModuleParser.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMModuleParser.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -27,6 +27,7 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "WASMMemory.h"
 #include "WASMOps.h"
 #include "WASMParser.h"
 #include <wtf/Vector.h>
@@ -45,18 +46,19 @@
 
     bool WARN_UNUSED_RETURN parse();
 
-    const Vector<FunctionInformation>& functionInformation() { return m_functions; }
+    const Vector<FunctionInformation>& functionInformation() const { return m_functions; }
+    std::unique_ptr<Memory>& memory() { return m_memory; }
 
 private:
+    bool WARN_UNUSED_RETURN parseMemory();
     bool WARN_UNUSED_RETURN parseFunctionTypes();
     bool WARN_UNUSED_RETURN parseFunctionSignatures();
     bool WARN_UNUSED_RETURN parseFunctionDefinitions();
     bool WARN_UNUSED_RETURN parseFunctionDefinition(uint32_t number);
-    bool WARN_UNUSED_RETURN parseBlock();
-    bool WARN_UNUSED_RETURN parseExpression(OpType);
 
     Vector<FunctionInformation> m_functions;
     Vector<Signature> m_signatures;
+    std::unique_ptr<Memory> m_memory;
 };
 
 } } // namespace JSC::WASM

Modified: trunk/Source/_javascript_Core/wasm/WASMOps.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMOps.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMOps.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -159,13 +159,42 @@
     macro(F64Gt, 0x9b, Oops) \
     macro(F64Ge, 0x9c, Oops)
 
+#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
+    macro(I32Load8S, 0x20, Oops) \
+    macro(I32Load8U, 0x21, Oops) \
+    macro(I32Load16S, 0x22, Oops) \
+    macro(I32Load16U, 0x23, Oops) \
+    macro(I64Load8S, 0x24, Oops) \
+    macro(I64Load8U, 0x25, Oops) \
+    macro(I64Load16S, 0x26, Oops) \
+    macro(I64Load16U, 0x27, Oops) \
+    macro(I64Load32S, 0x28, Oops) \
+    macro(I64Load32U, 0x29, Oops) \
+    macro(I32Load, 0x2a, Oops) \
+    macro(I64Load, 0x2b, Oops) \
+    macro(F32Load, 0x2c, Oops) \
+    macro(F64Load, 0x2d, Oops)
 
+#define FOR_EACH_WASM_MEMORY_STORE_OP(macro) \
+    macro(I32Store8, 0x2e, Oops) \
+    macro(I32Store16, 0x2f, Oops) \
+    macro(I64Store8, 0x30, Oops) \
+    macro(I64Store16, 0x31, Oops) \
+    macro(I64Store32, 0x32, Oops) \
+    macro(I32Store, 0x33, Oops) \
+    macro(I64Store, 0x34, Oops) \
+    macro(F32Store, 0x35, Oops) \
+    macro(F64Store, 0x36, Oops)
 
+
+
 #define FOR_EACH_WASM_OP(macro) \
     FOR_EACH_WASM_SPECIAL_OP(macro) \
     FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
     FOR_EACH_WASM_UNARY_OP(macro) \
-    FOR_EACH_WASM_BINARY_OP(macro)
+    FOR_EACH_WASM_BINARY_OP(macro) \
+    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
+    FOR_EACH_WASM_MEMORY_STORE_OP(macro)
 
 #define CREATE_ENUM_VALUE(name, id, b3op) name = id,
 
@@ -189,6 +218,14 @@
     FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
 };
 
+enum class LoadOpType : uint8_t {
+    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
+};
+
+enum class StoreOpType : uint8_t {
+    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
+};
+
 #undef CREATE_ENUM_VALUE
 
 inline bool isControlOp(OpType op)

Modified: trunk/Source/_javascript_Core/wasm/WASMPlan.cpp (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMPlan.cpp	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMPlan.cpp	2016-10-18 02:02:48 UTC (rev 207453)
@@ -30,6 +30,7 @@
 
 #include "B3Compilation.h"
 #include "WASMB3IRGenerator.h"
+#include "WASMCallingConvention.h"
 #include "WASMModuleParser.h"
 #include <wtf/DataLog.h>
 
@@ -53,8 +54,9 @@
     for (const FunctionInformation& info : moduleParser.functionInformation()) {
         if (verbose)
             dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end);
-        result.append(parseAndCompile(vm, source, info));
+        result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info));
     }
+    memory = WTFMove(moduleParser.memory());
 }
 
 } } // namespace JSC::WASM

Modified: trunk/Source/_javascript_Core/wasm/WASMPlan.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMPlan.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMPlan.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -29,23 +29,20 @@
 
 #include "CompilationResult.h"
 #include "VM.h"
+#include "WASMFormat.h"
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/Vector.h>
 
-namespace JSC {
+namespace JSC { namespace WASM {
+class Memory;
 
-namespace B3 {
-class Compilation;
-} // namespace B3
-
-namespace WASM {
-
 // TODO: This should create a WASM Module not a list of functions.
 class Plan {
 public:
     JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t> source);
 
-    Vector<std::unique_ptr<B3::Compilation>> result;
+    Vector<std::unique_ptr<FunctionCompilation>> result;
+    std::unique_ptr<Memory> memory;
 };
 
 } } // namespace JSC::WASM

Modified: trunk/Source/_javascript_Core/wasm/WASMSections.h (207452 => 207453)


--- trunk/Source/_javascript_Core/wasm/WASMSections.h	2016-10-18 01:25:54 UTC (rev 207452)
+++ trunk/Source/_javascript_Core/wasm/WASMSections.h	2016-10-18 02:02:48 UTC (rev 207453)
@@ -33,6 +33,7 @@
     enum Section : uint8_t {
         FunctionTypes = 1,
         Signatures = 3,
+        Memory = 5,
         Definitions = 10,
         Unknown
     };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to