Changeset 207453 in webkit


Ignore:
Timestamp:
Oct 17, 2016 7:02:48 PM (8 years ago)
Author:
keith_miller@apple.com
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/JavaScriptCore:

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:
  • JavaScriptCore.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/JavaScriptCore/wasm/WASMPlan.cpp.

(JSC::WASM::Memory::Memory):

  • wasm/WASMMemory.h: Copied from Source/JavaScriptCore/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:
Location:
trunk
Files:
2 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207433 r207453  
     12016-10-17  Keith Miller  <keith_miller@apple.com>
     2
     3        Add support for WASM Memory.
     4        https://bugs.webkit.org/show_bug.cgi?id=161710
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Add store and load opcodes to wasm.json. Additionally, add new
     9        enums for those opcodes in the generator.
     10
     11        * stress/wasm/generate-wasmops-header.js:
     12        (const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.LoadOpType):
     13        (const.template.pragma.once.ENABLE.WEBASSEMBLY.include.cstdint.namespace.JSC.namespace.WASM.enum.StoreOpType):
     14
    1152016-10-17  Saam Barati  <sbarati@apple.com>
    216
  • trunk/JSTests/wasm/generate-wasmops-header.js

    r207363 r207453  
    3737    "\n\n#define FOR_EACH_WASM_BINARY_OP(macro)",
    3838    ...opcodeMacroizer(op => (op.category === "arithmetic" || op.category === "comparison") && op.parameter.length === 2),
     39    "\n\n#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro)",
     40    ...opcodeMacroizer(op => (op.category === "memory" && op.return.length === 1)),
     41    "\n\n#define FOR_EACH_WASM_MEMORY_STORE_OP(macro)",
     42    ...opcodeMacroizer(op => (op.category === "memory" && op.return.length === 0)),
    3943    "\n\n"].join("");
    4044
     
    9599    FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \\
    96100    FOR_EACH_WASM_UNARY_OP(macro) \\
    97     FOR_EACH_WASM_BINARY_OP(macro)
     101    FOR_EACH_WASM_BINARY_OP(macro) \\
     102    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \\
     103    FOR_EACH_WASM_MEMORY_STORE_OP(macro)
    98104
    99105#define CREATE_ENUM_VALUE(name, id, b3op) name = id,
     
    119125};
    120126
     127enum class LoadOpType : uint8_t {
     128    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
     129};
     130
     131enum class StoreOpType : uint8_t {
     132    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
     133};
     134
    121135#undef CREATE_ENUM_VALUE
    122136
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r207434 r207453  
    864864    wasm/WASMB3IRGenerator.cpp
    865865    wasm/WASMCallingConvention.cpp
     866    wasm/WASMMemory.cpp
    866867    wasm/WASMModuleParser.cpp
    867868    wasm/WASMPlan.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r207444 r207453  
     12016-10-17  Keith Miller  <keith_miller@apple.com>
     2
     3        Add support for WASM Memory.
     4        https://bugs.webkit.org/show_bug.cgi?id=161710
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch add initial support for WASM memory operations. First,
     9        it adds the concept of a WASM Module memory management object.
     10        This object currently mmaps a 32-bit address space for WASM use,
     11        although it marks all the memory outside the current breakpoint as
     12        PROT_NONE. For now, we do a range check on each store and load. In
     13        the future, we should change this to be an signal handler that
     14        checks what module the program trapped in.
     15
     16        Additionally, this patch changes the way that our temporary tests
     17        call into WASM code. There is now a true "thunk" that relocates
     18        arguments and calls into WASM. This thunk does not tail call
     19        because we use pinned values to memory base-pointer and
     20        size. We use the new B3 pinned register api to pin the values.
     21
     22        * CMakeLists.txt:
     23        * Configurations/ToolExecutable.xcconfig:
     24        * JavaScriptCore.xcodeproj/project.pbxproj:
     25        * testWASM.cpp:
     26        (runWASMTests):
     27        (main):
     28        * wasm/WASMB3IRGenerator.cpp:
     29        (JSC::WASM::createJSWrapper):
     30        (JSC::WASM::parseAndCompile):
     31        * wasm/WASMB3IRGenerator.h:
     32        * wasm/WASMCallingConvention.h:
     33        (JSC::WASM::CallingConvention::iterate):
     34        (JSC::WASM::CallingConvention::setupCall):
     35        (JSC::WASM::nextJSCOffset):
     36        * wasm/WASMFormat.h:
     37        * wasm/WASMFunctionParser.h:
     38        (JSC::WASM::FunctionParser<Context>::parseExpression):
     39        * wasm/WASMMemory.cpp: Copied from Source/JavaScriptCore/wasm/WASMPlan.cpp.
     40        (JSC::WASM::Memory::Memory):
     41        * wasm/WASMMemory.h: Copied from Source/JavaScriptCore/wasm/WASMModuleParser.h.
     42        (JSC::WASM::Memory::~Memory):
     43        (JSC::WASM::Memory::memory):
     44        (JSC::WASM::Memory::size):
     45        (JSC::WASM::Memory::pinnedRegisters):
     46        (JSC::WASM::Memory::mode):
     47        (JSC::WASM::Memory::growMemory):
     48        (JSC::WASM::Memory::offsetOfSize):
     49        * wasm/WASMModuleParser.cpp:
     50        (JSC::WASM::ModuleParser::parse):
     51        (JSC::WASM::ModuleParser::parseMemory):
     52        * wasm/WASMModuleParser.h:
     53        (JSC::WASM::ModuleParser::functionInformation):
     54        (JSC::WASM::ModuleParser::memory):
     55        * wasm/WASMOps.h:
     56        * wasm/WASMPlan.cpp:
     57        (JSC::WASM::Plan::Plan):
     58        * wasm/WASMPlan.h:
     59        * wasm/WASMSections.h:
     60
    1612016-10-17  Joseph Pecoraro  <pecoraro@apple.com>
    262
  • trunk/Source/JavaScriptCore/Configurations/ToolExecutable.xcconfig

    r202287 r207453  
    3232CODE_SIGN_ENTITLEMENTS_ios_testapi = entitlements.plist;
    3333CODE_SIGN_ENTITLEMENTS_ios_testb3 = entitlements.plist;
     34CODE_SIGN_ENTITLEMENTS_ios_testWASM = entitlements.plist;
    3435CODE_SIGN_ENTITLEMENTS_ios_testRegExp = entitlements.plist;
    3536
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r207434 r207453  
    12171217                534C457E1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */; };
    12181218                53529A4C1C457B75000B49C6 /* APIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 53529A4B1C457B75000B49C6 /* APIUtils.h */; };
     1219                535557141D9D9EA5006D583B /* WASMMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 535557131D9D9EA5006D583B /* WASMMemory.h */; };
     1220                535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 535557151D9DFA32006D583B /* WASMMemory.cpp */; };
    12191221                5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
    12201222                5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
     
    34643466                534C457D1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewConstructor.cpp; sourceTree = "<group>"; };
    34653467                53529A4B1C457B75000B49C6 /* APIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIUtils.h; sourceTree = "<group>"; };
     3468                535557131D9D9EA5006D583B /* WASMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMMemory.h; sourceTree = "<group>"; };
     3469                535557151D9DFA32006D583B /* WASMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMMemory.cpp; sourceTree = "<group>"; };
    34663470                5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
    34673471                5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
     
    57005704                                7BC547D21B69599B00959B58 /* WASMFormat.h */,
    57015705                                53F40E8A1D5901BB0099A1B6 /* WASMFunctionParser.h */,
     5706                                535557151D9DFA32006D583B /* WASMMemory.cpp */,
     5707                                535557131D9D9EA5006D583B /* WASMMemory.h */,
    57025708                                53F40E961D5A7BEC0099A1B6 /* WASMModuleParser.cpp */,
    57035709                                53F40E941D5A7AEF0099A1B6 /* WASMModuleParser.h */,
     
    78727878                                1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */,
    78737879                                0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,
     7880                                535557141D9D9EA5006D583B /* WASMMemory.h in Headers */,
    78747881                                14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
    78757882                                0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */,
     
    92149221                                0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */,
    92159222                                0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */,
     9223                                535557161D9DFA32006D583B /* WASMMemory.cpp in Sources */,
    92169224                                0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */,
    92179225                                0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */,
  • trunk/Source/JavaScriptCore/testWASM.cpp

    r206110 r207453  
    3333#include "ProtoCallFrame.h"
    3434#include "VM.h"
     35#include "WASMMemory.h"
    3536#include "WASMPlan.h"
     37
    3638#include <wtf/DataLog.h>
    3739#include <wtf/LEBDecoder.h>
     
    243245    {
    244246        // Generated from:
    245         //    (module
    246         //     (func (export "dumb-eq") (param $x i32) (param $y i32) (result i32)
     247        // (module
     248        //  (memory 1)
     249        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     250        //   (i64.store (get_local $ptr) (get_local $i))
     251        //   (return (i64.load (get_local $ptr)))
     252        //   )
     253        //  )
     254        Vector<uint8_t> vector = {
     255            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     256            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     257            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     258            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     259            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
     260            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
     261        };
     262
     263        Plan plan(*vm, vector);
     264        if (plan.result.size() != 1 || !plan.result[0]) {
     265            dataLogLn("Module failed to compile correctly.");
     266            CRASH();
     267        }
     268
     269        // Test this doesn't crash.
     270        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     271        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     272        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     273    }
     274
     275    {
     276        // Generated from:
     277        // (module
     278        //  (memory 1)
     279        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     280        //   (i32.store (get_local $ptr) (get_local $i))
     281        //   (return (i32.load (get_local $ptr)))
     282        //   )
     283        //  )
     284        Vector<uint8_t> vector = {
     285            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     286            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     287            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     288            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     289            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
     290            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
     291        };
     292
     293        Plan plan(*vm, vector);
     294        if (plan.result.size() != 1 || !plan.result[0]) {
     295            dataLogLn("Module failed to compile correctly.");
     296            CRASH();
     297        }
     298
     299        // Test this doesn't crash.
     300        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     301        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     302        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     303    }
     304
     305    {
     306        // Generated from:
     307        //    (module
     308        //     (memory 1)
     309        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
     310        //      (set_local $i (i32.const 0))
     311        //      (block
     312        //       (loop
     313        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
     314        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
     315        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
     316        //        (br 0)
     317        //        )
     318        //       )
     319        //      (return)
     320        //      )
     321        //     )
     322        Vector<uint8_t> vector = {
     323            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     324            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     325            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
     326            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
     327            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
     328            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
     329            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
     330            0x0f, 0x09, 0x0f
     331        };
     332
     333        Plan plan(*vm, vector);
     334        if (plan.result.size() != 1 || !plan.result[0]) {
     335            dataLogLn("Module failed to compile correctly.");
     336            CRASH();
     337        }
     338        ASSERT(plan.memory->size());
     339
     340        // Test this doesn't crash.
     341        unsigned length = 5;
     342        unsigned offset = sizeof(uint32_t);
     343        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
     344        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
     345        offset /= sizeof(uint32_t);
     346        CHECK_EQ(memory[offset - 1], 0u);
     347        CHECK_EQ(memory[offset + length], 0u);
     348        for (unsigned i = 0; i < length; ++i)
     349            CHECK_EQ(memory[i + offset], 100u);
     350
     351        length = 10;
     352        offset = 5 * sizeof(uint32_t);
     353        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
     354        offset /= sizeof(uint32_t);
     355        CHECK_EQ(memory[offset - 1], 100u);
     356        CHECK_EQ(memory[offset + length], 0u);
     357        for (unsigned i = 0; i < length; ++i)
     358            CHECK_EQ(memory[i + offset], 5u);
     359    }
     360
     361    {
     362        // Generated from:
     363        //    (module
     364        //     (memory 1)
     365        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
     366        //      (set_local $i (i32.const 0))
     367        //      (block
     368        //       (loop
     369        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
     370        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
     371        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
     372        //        (br 0)
     373        //        )
     374        //       )
     375        //      (return)
     376        //      )
     377        //     )
     378        Vector<uint8_t> vector = {
     379            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     380            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     381            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
     382            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
     383            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
     384            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
     385            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
     386        };
     387
     388        Plan plan(*vm, vector);
     389        if (plan.result.size() != 1 || !plan.result[0]) {
     390            dataLogLn("Module failed to compile correctly.");
     391            CRASH();
     392        }
     393        ASSERT(plan.memory->size());
     394
     395        // Test this doesn't crash.
     396        unsigned length = 5;
     397        unsigned offset = 1;
     398        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
     399        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
     400        CHECK_EQ(memory[offset - 1], 0u);
     401        CHECK_EQ(memory[offset + length], 0u);
     402        for (unsigned i = 0; i < length; ++i)
     403            CHECK_EQ(memory[i + offset], 100u);
     404
     405        length = 10;
     406        offset = 5;
     407        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
     408        CHECK_EQ(memory[offset - 1], 100u);
     409        CHECK_EQ(memory[offset + length], 0u);
     410        for (unsigned i = 0; i < length; ++i)
     411            CHECK_EQ(memory[i + offset], 5u);
     412    }
     413
     414    {
     415        // Generated from:
     416        //    (module
     417        //     (memory 1)
     418        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     419        //      (i32.store8 (get_local $ptr) (get_local $i))
     420        //      (return (i32.load8_s (get_local $ptr)))
     421        //      )
     422        //     )
     423        Vector<uint8_t> vector = {
     424            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     425            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     426            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     427            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     428            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
     429            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
     430        };
     431
     432        Plan plan(*vm, vector);
     433        if (plan.result.size() != 1 || !plan.result[0]) {
     434            dataLogLn("Module failed to compile correctly.");
     435            CRASH();
     436        }
     437        ASSERT(plan.memory->size());
     438
     439        // Test this doesn't crash.
     440        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     441        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     442        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     443    }
     444
     445    {
     446        // Generated from:
     447        //    (module
     448        //     (memory 1)
     449        //     (func (export "i32_load8_s") (param $i i32) (result i32)
     450        //      (i32.store8 (i32.const 8) (get_local $i))
     451        //      (return (i32.load8_s (i32.const 8)))
     452        //      )
     453        //     )
     454        Vector<uint8_t> vector = {
     455            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     456            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
     457            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
     458            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
     459            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
     460            0x20, 0x00, 0x00, 0x09, 0x0f
     461        };
     462
     463        Plan plan(*vm, vector);
     464        if (plan.result.size() != 1 || !plan.result[0]) {
     465            dataLogLn("Module failed to compile correctly.");
     466            CRASH();
     467        }
     468
     469        // Test this doesn't crash.
     470        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
     471        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
     472        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
     473    }
     474
     475    {
     476        // Generated from:
     477        // (module
     478        //  (memory 1)
     479        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     480        //   (i32.store (get_local $ptr) (get_local $i))
     481        //   (return (i32.load (get_local $ptr)))
     482        //   )
     483        //  )
     484        Vector<uint8_t> vector = {
     485            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     486            0x02, 0x02, 0x01, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     487            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     488            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     489            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x34, 0x03, 0x00, 0x14,
     490            0x01, 0x2b, 0x03, 0x00, 0x09, 0x0f
     491        };
     492
     493        Plan plan(*vm, vector);
     494        if (plan.result.size() != 1 || !plan.result[0]) {
     495            dataLogLn("Module failed to compile correctly.");
     496            CRASH();
     497        }
     498
     499        // Test this doesn't crash.
     500        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     501        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     502        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     503        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-12), box(plan.memory->size() - sizeof(uint64_t)) }), -12);
     504    }
     505
     506    {
     507        // Generated from:
     508        // (module
     509        //  (memory 1)
     510        //  (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     511        //   (i32.store (get_local $ptr) (get_local $i))
     512        //   (return (i32.load (get_local $ptr)))
     513        //   )
     514        //  )
     515        Vector<uint8_t> vector = {
     516            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     517            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     518            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     519            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     520            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x33, 0x02, 0x00, 0x14,
     521            0x01, 0x2a, 0x02, 0x00, 0x09, 0x0f
     522        };
     523
     524        Plan plan(*vm, vector);
     525        if (plan.result.size() != 1 || !plan.result[0]) {
     526            dataLogLn("Module failed to compile correctly.");
     527            CRASH();
     528        }
     529
     530        // Test this doesn't crash.
     531        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     532        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     533        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     534    }
     535
     536    {
     537        // Generated from:
     538        //    (module
     539        //     (memory 1)
     540        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
     541        //      (set_local $i (i32.const 0))
     542        //      (block
     543        //       (loop
     544        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
     545        //        (i32.store (i32.add (get_local $p) (i32.mul (get_local $i) (i32.const 4))) (get_local $x))
     546        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
     547        //        (br 0)
     548        //        )
     549        //       )
     550        //      (return)
     551        //      )
     552        //     )
     553        Vector<uint8_t> vector = {
     554            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     555            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     556            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
     557            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xb2, 0x80, 0x80, 0x80,
     558            0x00, 0x01, 0xac, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
     559            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x10, 0x04, 0x42,
     560            0x40, 0x14, 0x00, 0x33, 0x02, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f,
     561            0x0f, 0x09, 0x0f
     562        };
     563
     564        Plan plan(*vm, vector);
     565        if (plan.result.size() != 1 || !plan.result[0]) {
     566            dataLogLn("Module failed to compile correctly.");
     567            CRASH();
     568        }
     569        ASSERT(plan.memory->size());
     570
     571        // Test this doesn't crash.
     572        unsigned length = 5;
     573        unsigned offset = sizeof(uint32_t);
     574        uint32_t* memory = static_cast<uint32_t*>(plan.memory->memory());
     575        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
     576        offset /= sizeof(uint32_t);
     577        CHECK_EQ(memory[offset - 1], 0u);
     578        CHECK_EQ(memory[offset + length], 0u);
     579        for (unsigned i = 0; i < length; ++i)
     580            CHECK_EQ(memory[i + offset], 100u);
     581
     582        length = 10;
     583        offset = 5 * sizeof(uint32_t);
     584        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
     585        offset /= sizeof(uint32_t);
     586        CHECK_EQ(memory[offset - 1], 100u);
     587        CHECK_EQ(memory[offset + length], 0u);
     588        for (unsigned i = 0; i < length; ++i)
     589            CHECK_EQ(memory[i + offset], 5u);
     590    }
     591
     592    {
     593        // Generated from:
     594        //    (module
     595        //     (memory 1)
     596        //     (func (export "write_array") (param $x i32) (param $p i32) (param $length i32) (local $i i32)
     597        //      (set_local $i (i32.const 0))
     598        //      (block
     599        //       (loop
     600        //        (br_if 1 (i32.ge_u (get_local $i) (get_local $length)))
     601        //        (i32.store8 (i32.add (get_local $p) (get_local $i)) (get_local $x))
     602        //        (set_local $i (i32.add (i32.const 1) (get_local $i)))
     603        //        (br 0)
     604        //        )
     605        //       )
     606        //      (return)
     607        //      )
     608        //     )
     609        Vector<uint8_t> vector = {
     610            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     611            0x03, 0x01, 0x01, 0x01, 0x00, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     612            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x77, 0x72,
     613            0x69, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x00, 0x0a, 0xaf, 0x80, 0x80, 0x80,
     614            0x00, 0x01, 0xa9, 0x80, 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x15, 0x03, 0x01, 0x00,
     615            0x02, 0x00, 0x14, 0x03, 0x14, 0x02, 0x56, 0x07, 0x01, 0x14, 0x01, 0x14, 0x03, 0x40, 0x14, 0x00,
     616            0x2e, 0x00, 0x00, 0x10, 0x01, 0x14, 0x03, 0x40, 0x15, 0x03, 0x06, 0x00, 0x0f, 0x0f, 0x09, 0x0f
     617        };
     618
     619        Plan plan(*vm, vector);
     620        if (plan.result.size() != 1 || !plan.result[0]) {
     621            dataLogLn("Module failed to compile correctly.");
     622            CRASH();
     623        }
     624        ASSERT(plan.memory->size());
     625
     626        // Test this doesn't crash.
     627        unsigned length = 5;
     628        unsigned offset = 1;
     629        uint8_t* memory = static_cast<uint8_t*>(plan.memory->memory());
     630        invoke<void>(*plan.result[0]->jsEntryPoint, { box(100), box(offset), box(length) });
     631        CHECK_EQ(memory[offset - 1], 0u);
     632        CHECK_EQ(memory[offset + length], 0u);
     633        for (unsigned i = 0; i < length; ++i)
     634            CHECK_EQ(memory[i + offset], 100u);
     635
     636        length = 10;
     637        offset = 5;
     638        invoke<void>(*plan.result[0]->jsEntryPoint, { box(5), box(offset), box(length) });
     639        CHECK_EQ(memory[offset - 1], 100u);
     640        CHECK_EQ(memory[offset + length], 0u);
     641        for (unsigned i = 0; i < length; ++i)
     642            CHECK_EQ(memory[i + offset], 5u);
     643    }
     644
     645    {
     646        // Generated from:
     647        //    (module
     648        //     (memory 1)
     649        //     (func (export "i32_load8_s") (param $i i32) (param $ptr i32) (result i32)
     650        //      (i32.store8 (get_local $ptr) (get_local $i))
     651        //      (return (i32.load8_s (get_local $ptr)))
     652        //      )
     653        //     )
     654        Vector<uint8_t> vector = {
     655            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     656            0x02, 0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80,
     657            0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33,
     658            0x32, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80,
     659            0x00, 0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x01, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x14,
     660            0x01, 0x20, 0x00, 0x00, 0x09, 0x0f
     661        };
     662
     663        Plan plan(*vm, vector);
     664        if (plan.result.size() != 1 || !plan.result[0]) {
     665            dataLogLn("Module failed to compile correctly.");
     666            CRASH();
     667        }
     668        ASSERT(plan.memory->size());
     669
     670        // Test this doesn't crash.
     671        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(10) }), 0);
     672        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(2) }), 100);
     673        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(100) }), 1);
     674    }
     675
     676    {
     677        // Generated from:
     678        //    (module
     679        //     (memory 1)
     680        //     (func (export "i32_load8_s") (param $i i32) (result i32)
     681        //      (i32.store8 (i32.const 8) (get_local $i))
     682        //      (return (i32.load8_s (i32.const 8)))
     683        //      )
     684        //     )
     685        Vector<uint8_t> vector = {
     686            0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40,
     687            0x01, 0x01, 0x01, 0x01, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80,
     688            0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0b, 0x69, 0x33, 0x32,
     689            0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x38, 0x5f, 0x73, 0x00, 0x00, 0x0a, 0x95, 0x80, 0x80, 0x80, 0x00,
     690            0x01, 0x8f, 0x80, 0x80, 0x80, 0x00, 0x00, 0x10, 0x08, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x10, 0x08,
     691            0x20, 0x00, 0x00, 0x09, 0x0f
     692        };
     693
     694        Plan plan(*vm, vector);
     695        if (plan.result.size() != 1 || !plan.result[0]) {
     696            dataLogLn("Module failed to compile correctly.");
     697            CRASH();
     698        }
     699
     700        // Test this doesn't crash.
     701        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
     702        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100);
     703        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
     704    }
     705
     706    {
     707        // Generated from:
     708        //    (module
     709        //     (func "dumb-eq" (param $x i32) (param $y i32) (result i32)
    247710        //      (if (i32.eq (get_local $x) (get_local $y))
    248711        //       (then (br 0))
     
    266729
    267730        // Test this doesn't crash.
    268         CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
    269         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 1);
    270         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 1);
    271         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
    272         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
    273         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
    274         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
    275         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 1);
     731        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
     732        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 1);
     733        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 1);
     734        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
     735        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
     736        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
     737        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
     738        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 1);
    276739    }
    277740
     
    307770
    308771        // Test this doesn't crash.
    309         CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
    310         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
    311         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
    312         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
    313         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
    314         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
    315         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
    316         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
     772        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
     773        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
     774        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
     775        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
     776        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
     777        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
     778        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
     779        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
    317780    }
    318781
     
    334797
    335798        // Test this doesn't crash.
    336         CHECK_EQ(invoke<int>(*plan.result[0], { }), 5);
     799        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 5);
    337800    }
    338801
     
    355818
    356819        // Test this doesn't crash.
    357         CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
     820        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
    358821    }
    359822
     
    375838
    376839        // Test this doesn't crash.
    377         CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
     840        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
    378841    }
    379842
     
    395858
    396859        // Test this doesn't crash.
    397         CHECK_EQ(invoke<int>(*plan.result[0], { }), 11);
     860        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { }), 11);
    398861    }
    399862
     
    414877
    415878        // Test this doesn't crash.
    416         CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
    417         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(1) }), 101);
    418         CHECK_EQ(invoke<int>(*plan.result[0], { box(-1), box(1)}), 0);
    419         CHECK_EQ(invoke<int>(*plan.result[0], { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
     879        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
     880        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(1) }), 101);
     881        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(-1), box(1)}), 0);
     882        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(std::numeric_limits<int>::max()), box(1) }), std::numeric_limits<int>::min());
    420883    }
    421884
     
    443906
    444907        // Test this doesn't crash.
    445         CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
    446         CHECK_EQ(invoke<int>(*plan.result[0], { box(10) }), 10);
     908        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
     909        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(10) }), 10);
    447910    }
    448911
     
    479942
    480943        // Test this doesn't crash.
    481         CHECK_EQ(invoke<int>(*plan.result[0], { box(0) }), 0);
    482         CHECK_EQ(invoke<int>(*plan.result[0], { box(1) }), 1);
    483         CHECK_EQ(invoke<int>(*plan.result[0], { box(2)}), 3);
    484         CHECK_EQ(invoke<int>(*plan.result[0], { box(100) }), 5050);
     944        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0);
     945        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1);
     946        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2)}), 3);
     947        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 5050);
    485948    }
    486949
     
    523986
    524987        // Test this doesn't crash.
    525         CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 0);
    526         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
    527         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 2);
    528         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 2);
    529         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 4);
    530         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 12);
    531         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 600);
    532         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(100) }), 10000);
     988        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 0);
     989        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
     990        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 2);
     991        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 2);
     992        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 4);
     993        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 12);
     994        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 600);
     995        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(100) }), 10000);
    533996    }
    534997
     
    5761039
    5771040        // Test this doesn't crash.
    578         CHECK_EQ(invoke<int>(*plan.result[0], { box(0), box(1) }), 1);
    579         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(0) }), 0);
    580         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(1) }), 0);
    581         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(2) }), 1);
    582         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(2) }), 0);
    583         CHECK_EQ(invoke<int>(*plan.result[0], { box(1), box(1) }), 0);
    584         CHECK_EQ(invoke<int>(*plan.result[0], { box(2), box(6) }), 1);
    585         CHECK_EQ(invoke<int>(*plan.result[0], { box(100), box(6) }), 0);
     1041        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0), box(1) }), 1);
     1042        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(0) }), 0);
     1043        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(1) }), 0);
     1044        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2) }), 1);
     1045        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(2) }), 0);
     1046        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(1) }), 0);
     1047        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2), box(6) }), 1);
     1048        CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100), box(6) }), 0);
    5861049    }
    5871050
     
    5961059    if (options.m_runLEBTests)
    5971060        runLEBTests();
    598 
    5991061
    6001062    if (options.m_runWASMTests) {
  • trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp

    r206110 r207453  
    3030
    3131#include "B3BasicBlockInlines.h"
     32#include "B3ConstPtrValue.h"
    3233#include "B3FixSSA.h"
     34#include "B3StackmapGenerationParams.h"
    3335#include "B3Validate.h"
    3436#include "B3ValueInlines.h"
    3537#include "B3Variable.h"
    3638#include "B3VariableValue.h"
     39#include "B3WasmAddressValue.h"
     40#include "B3WasmBoundsCheckValue.h"
    3741#include "VirtualRegister.h"
    3842#include "WASMCallingConvention.h"
    3943#include "WASMFunctionParser.h"
     44#include "WASMMemory.h"
    4045#include <wtf/Optional.h>
    4146
     
    166171    static constexpr ExpressionType emptyExpression = nullptr;
    167172
    168     B3IRGenerator(Procedure&);
     173    B3IRGenerator(Memory*, Procedure&);
    169174
    170175    void addArguments(const Vector<Type>&);
     
    172177    ExpressionType addConstant(Type, uint64_t);
    173178
     179    // Locals
    174180    bool WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
    175181    bool WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
    176182
     183    // Memory
     184    bool WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
     185    bool WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
     186
     187    // Basic operators
    177188    bool WARN_UNUSED_RETURN binaryOp(BinaryOpType, ExpressionType left, ExpressionType right, ExpressionType& result);
    178189    bool WARN_UNUSED_RETURN unaryOp(UnaryOpType, ExpressionType arg, ExpressionType& result);
    179190
     191    // Control flow
    180192    ControlData WARN_UNUSED_RETURN addBlock(Type signature);
    181193    ControlData WARN_UNUSED_RETURN addLoop(Type signature);
     
    192204
    193205private:
     206    ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
     207    ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
     208    void emitStoreOp(StoreOpType, Origin, ExpressionType pointer, ExpressionType value, uint32_t offset);
     209
    194210    void unify(Variable* target, const ExpressionType source);
    195211    void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
    196212
     213    Memory* m_memory;
    197214    Procedure& m_proc;
    198215    BasicBlock* m_currentBlock;
    199216    Vector<Variable*> m_locals;
     217    GPRReg m_memoryBaseGPR;
     218    GPRReg m_memorySizeGPR;
    200219};
    201220
    202 B3IRGenerator::B3IRGenerator(Procedure& procedure)
    203     : m_proc(procedure)
     221B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure)
     222    : m_memory(memory)
     223    , m_proc(procedure)
    204224{
    205225    m_currentBlock = m_proc.addBlock();
     226
     227    if (m_memory) {
     228        m_memoryBaseGPR = m_memory->pinnedRegisters().baseMemoryPointer;
     229        m_proc.pinRegister(m_memoryBaseGPR);
     230        ASSERT(!m_memory->pinnedRegisters().sizeRegisters[0].sizeOffset);
     231        m_memorySizeGPR = m_memory->pinnedRegisters().sizeRegisters[0].sizeRegister;
     232        for (const PinnedSizeRegisterInfo& info : m_memory->pinnedRegisters().sizeRegisters)
     233            m_proc.pinRegister(info.sizeRegister);
     234    }
     235
     236    m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
     237        ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
     238        // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351
     239        jit.breakpoint();
     240    });
    206241}
    207242
     
    225260}
    226261
    227 bool WARN_UNUSED_RETURN B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
     262bool B3IRGenerator::getLocal(uint32_t index, ExpressionType& result)
    228263{
    229264    ASSERT(m_locals[index]);
     
    232267}
    233268
    234 bool WARN_UNUSED_RETURN B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
     269bool B3IRGenerator::setLocal(uint32_t index, ExpressionType value)
    235270{
    236271    ASSERT(m_locals[index]);
    237272    m_currentBlock->appendNew<VariableValue>(m_proc, B3::Set, Origin(), m_locals[index], value);
     273    return true;
     274}
     275
     276inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation)
     277{
     278    ASSERT(m_memoryBaseGPR && m_memorySizeGPR);
     279    ASSERT(sizeOfOperation + offset > offset);
     280    m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, Origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1);
     281    pointer = m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), pointer);
     282    return m_currentBlock->appendNew<WasmAddressValue>(m_proc, Origin(), pointer, m_memoryBaseGPR);
     283}
     284
     285inline uint32_t sizeOfLoadOp(LoadOpType op)
     286{
     287    switch (op) {
     288    case LoadOpType::I32Load8S:
     289    case LoadOpType::I32Load8U:
     290    case LoadOpType::I64Load8S:
     291    case LoadOpType::I64Load8U:
     292        return 1;
     293    case LoadOpType::I32Load16S:
     294    case LoadOpType::I64Load16S:
     295        return 2;
     296    case LoadOpType::I32Load:
     297    case LoadOpType::I64Load32S:
     298    case LoadOpType::I64Load32U:
     299        return 4;
     300    case LoadOpType::I64Load:
     301        return 8;
     302    case LoadOpType::I32Load16U:
     303    case LoadOpType::I64Load16U:
     304    case LoadOpType::F32Load:
     305    case LoadOpType::F64Load:
     306        break;
     307    }
     308    RELEASE_ASSERT_NOT_REACHED();
     309}
     310
     311inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, Origin origin, ExpressionType pointer, uint32_t offset)
     312{
     313    switch (op) {
     314    case LoadOpType::I32Load8S: {
     315        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
     316    }
     317
     318    case LoadOpType::I64Load8S: {
     319        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
     320        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
     321    }
     322
     323    case LoadOpType::I32Load8U: {
     324        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
     325    }
     326
     327    case LoadOpType::I64Load8U: {
     328        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
     329        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
     330    }
     331
     332    case LoadOpType::I32Load16S: {
     333        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     334    }
     335    case LoadOpType::I64Load16S: {
     336        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     337        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
     338    }
     339
     340    case LoadOpType::I32Load: {
     341        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
     342    }
     343
     344    case LoadOpType::I64Load32U: {
     345        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
     346        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
     347    }
     348
     349    case LoadOpType::I64Load32S: {
     350        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer);
     351        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
     352    }
     353
     354    case LoadOpType::I64Load: {
     355        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin, pointer);
     356    }
     357
     358    case LoadOpType::F32Load: {
     359        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Float, origin, pointer);
     360    }
     361
     362    case LoadOpType::F64Load: {
     363        return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Double, origin, pointer);
     364    }
     365
     366    // B3 doesn't support Load16Z yet.
     367    case LoadOpType::I32Load16U:
     368    case LoadOpType::I64Load16U:
     369        break;
     370    }
     371    RELEASE_ASSERT_NOT_REACHED();
     372}
     373
     374bool B3IRGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset)
     375{
     376    ASSERT(pointer->type() == Int32);
     377
     378    result = emitLoadOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset);
     379    return true;
     380}
     381
     382inline uint32_t sizeOfStoreOp(StoreOpType op)
     383{
     384    switch (op) {
     385    case StoreOpType::I32Store8:
     386    case StoreOpType::I64Store8:
     387        return 1;
     388    case StoreOpType::I32Store16:
     389    case StoreOpType::I64Store16:
     390        return 2;
     391    case StoreOpType::I32Store:
     392    case StoreOpType::I64Store32:
     393    case StoreOpType::F32Store:
     394        return 4;
     395    case StoreOpType::I64Store:
     396    case StoreOpType::F64Store:
     397        return 8;
     398    }
     399    RELEASE_ASSERT_NOT_REACHED();
     400}
     401
     402
     403inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, ExpressionType pointer, ExpressionType value, uint32_t offset)
     404{
     405    switch (op) {
     406    case StoreOpType::I64Store8:
     407        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
     408        FALLTHROUGH;
     409
     410    case StoreOpType::I32Store8:
     411        m_currentBlock->appendNew<MemoryValue>(m_proc, Store8, origin, value, pointer, offset);
     412        return;
     413
     414    case StoreOpType::I64Store16:
     415        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
     416        FALLTHROUGH;
     417
     418    case StoreOpType::I32Store16:
     419        m_currentBlock->appendNew<MemoryValue>(m_proc, Store16, origin, value, pointer, offset);
     420        return;
     421
     422    case StoreOpType::I64Store32:
     423        value = m_currentBlock->appendNew<Value>(m_proc, Trunc, origin, value);
     424        FALLTHROUGH;
     425
     426    case StoreOpType::I64Store:
     427    case StoreOpType::I32Store:
     428    case StoreOpType::F32Store:
     429    case StoreOpType::F64Store:
     430        m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin, value, pointer, offset);
     431        return;
     432    }
     433    RELEASE_ASSERT_NOT_REACHED();
     434}
     435
     436bool B3IRGenerator::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
     437{
     438    ASSERT(pointer->type() == Int32);
     439
     440    emitStoreOp(op, Origin(), emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset);
    238441    return true;
    239442}
     
    404607} // anonymous namespace
    405608
    406 std::unique_ptr<Compilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, FunctionInformation info, unsigned optLevel)
     609
     610static std::unique_ptr<Compilation> createJSWrapper(VM& vm, const Signature* signature, MacroAssemblerCodePtr mainFunction, Memory* memory)
     611{
     612    Procedure proc;
     613    BasicBlock* block = proc.addBlock();
     614
     615    // Check argument count is sane.
     616    Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, Origin());
     617    Value* offSetOfArgumentCount = block->appendNew<Const64Value>(proc, Origin(), CallFrameSlot::argumentCount * sizeof(Register));
     618    Value* argumentCount = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
     619        block->appendNew<Value>(proc, Add, Origin(), framePointer, offSetOfArgumentCount));
     620
     621    Value* expectedArgumentCount = block->appendNew<Const32Value>(proc, Origin(), signature->arguments.size());
     622
     623    CheckValue* argumentCountCheck = block->appendNew<CheckValue>(proc, Check, Origin(),
     624        block->appendNew<Value>(proc, Above, Origin(), expectedArgumentCount, argumentCount));
     625    argumentCountCheck->setGenerator([] (CCallHelpers& jit, const StackmapGenerationParams&) {
     626        jit.breakpoint();
     627    });
     628
     629    // Move memory values to the approriate places, if needed.
     630    Value* baseMemory = nullptr;
     631    Vector<Value*> sizes;
     632    if (memory) {
     633        baseMemory = block->appendNew<ConstPtrValue>(proc, Origin(), memory->memory());
     634        Value* size = block->appendNew<MemoryValue>(proc, Load, Int32, Origin(),
     635            block->appendNew<ConstPtrValue>(proc, Origin(), bitwise_cast<char*>(memory) + Memory::offsetOfSize()));
     636        sizes.reserveCapacity(memory->pinnedRegisters().sizeRegisters.size());
     637        for (auto info : memory->pinnedRegisters().sizeRegisters) {
     638            sizes.append(block->appendNew<Value>(proc, Sub, Origin(), size,
     639                block->appendNew<Const32Value>(proc, Origin(), info.sizeOffset)));
     640        }
     641    }
     642
     643    // Get our arguments.
     644    Vector<Value*> arguments;
     645    jscCallingConvention().iterate(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {
     646        arguments.append(argument);
     647    });
     648
     649    // Move the arguments into place.
     650    Value* result = jscCallingConvention().setupCall(proc, block, Origin(), mainFunction, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {
     651        if (memory) {
     652            ASSERT(sizes.size() == memory->pinnedRegisters().sizeRegisters.size());
     653            patchpoint->append(ConstrainedValue(baseMemory, ValueRep::reg(memory->pinnedRegisters().baseMemoryPointer)));
     654            for (unsigned i = 0; i < sizes.size(); ++i)
     655                patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory->pinnedRegisters().sizeRegisters[i].sizeRegister)));
     656        }
     657    });
     658
     659    // Return the result, if needed.
     660    if (signature->returnType != Void)
     661        block->appendNewControlValue(proc, B3::Return, Origin(), result);
     662    else
     663        block->appendNewControlValue(proc, B3::Return, Origin());
     664
     665    return std::make_unique<Compilation>(vm, proc);
     666}
     667
     668std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, unsigned optLevel)
    407669{
    408670    Procedure procedure;
    409     B3IRGenerator context(procedure);
     671    B3IRGenerator context(memory, procedure);
    410672    FunctionParser<B3IRGenerator> parser(context, source, info);
    411673    if (!parser.parse())
     
    418680    if (verbose)
    419681        dataLog("Post SSA: ", procedure);
    420     return std::make_unique<Compilation>(vm, procedure, optLevel);
     682    auto result = std::make_unique<FunctionCompilation>();
     683
     684    result->code = std::make_unique<Compilation>(vm, procedure, optLevel);
     685    result->jsEntryPoint = createJSWrapper(vm, info.signature, result->code->code(), memory);
     686    return result;
    421687}
    422688
  • trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h

    r205769 r207453  
    3636namespace JSC { namespace WASM {
    3737
    38 std::unique_ptr<B3::Compilation> parseAndCompile(VM&, Vector<uint8_t>&, FunctionInformation, unsigned optLevel = 1);
     38class Memory;
     39
     40std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, unsigned optLevel = 1);
    3941
    4042} } // namespace JSC::WASM
  • trunk/Source/JavaScriptCore/wasm/WASMCallingConvention.h

    r205552 r207453  
    2828#if ENABLE(WEBASSEMBLY)
    2929
     30#include "AllowMacroScratchRegisterUsage.h"
    3031#include "B3ArgumentRegValue.h"
    3132#include "B3BasicBlock.h"
    3233#include "B3Const64Value.h"
     34#include "B3ConstrainedValue.h"
    3335#include "B3MemoryValue.h"
     36#include "B3PatchpointValue.h"
     37#include "B3Procedure.h"
     38#include "B3StackmapGenerationParams.h"
    3439#include "CallFrame.h"
     40#include "LinkBuffer.h"
    3541#include "RegisterSet.h"
    3642#include "WASMFormat.h"
     
    3844namespace JSC { namespace WASM {
    3945
    40 typedef unsigned (*NextOffset)(unsigned currentOffset, Type type);
     46typedef unsigned (*NextOffset)(unsigned currentOffset, B3::Type type);
    4147
    42 template<unsigned offset, NextOffset updateOffset>
     48template<unsigned headerSize, NextOffset updateOffset>
    4349class CallingConvention {
    4450public:
    45     static const unsigned headerSize = offset;
    46 
    4751    CallingConvention(Vector<GPRReg>&& registerArguments, RegisterSet&& calleeSaveRegisters)
    4852        : m_registerArguments(registerArguments)
     
    6569                    block->appendNew<B3::Const64Value>(proc, origin, currentOffset));
    6670                argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, toB3Type(argumentTypes[i]), origin, address);
    67                 currentOffset = updateOffset(currentOffset, argumentTypes[i]);
     71                currentOffset = updateOffset(currentOffset, toB3Type(argumentTypes[i]));
    6872            }
    6973            functor(argument, i);
    7074        }
     75    }
     76
     77    template<typename Functor>
     78    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
     79    {
     80        size_t stackArgumentCount = arguments.size() < m_registerArguments.size() ? 0 : arguments.size() - m_registerArguments.size();
     81        unsigned offset = headerSize - sizeof(CallerFrameAndPC);
     82
     83        proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), headerSize + (stackArgumentCount * sizeof(Register))));
     84        Vector<B3::ConstrainedValue> constrainedArguments;
     85        for (unsigned i = 0; i < arguments.size(); ++i) {
     86            B3::ValueRep rep;
     87            if (i < m_registerArguments.size())
     88                rep = B3::ValueRep::reg(m_registerArguments[i]);
     89            else
     90                rep = B3::ValueRep::stackArgument(offset);
     91            constrainedArguments.append(B3::ConstrainedValue(arguments[i], rep));
     92            offset = updateOffset(offset, arguments[i]->type());
     93        }
     94
     95        B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin);
     96        patchpoint->appendVector(constrainedArguments);
     97        patchpointFunctor(patchpoint);
     98        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
     99            AllowMacroScratchRegisterUsage allowScratch(jit);
     100
     101            CCallHelpers::Call call = jit.call();
     102            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
     103                linkBuffer.link(call, FunctionPtr(target.executableAddress()));
     104            });
     105        });
     106
     107        if (returnType == B3::Void)
     108            return nullptr;
     109
     110        patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR);
     111        return patchpoint;
    71112    }
    72113
     
    76117};
    77118
    78 inline unsigned nextJSCOffset(unsigned currentOffset, Type)
     119inline unsigned nextJSCOffset(unsigned currentOffset, B3::Type)
    79120{
    80121    return currentOffset + sizeof(Register);
  • trunk/Source/JavaScriptCore/wasm/WASMFormat.h

    r206110 r207453  
    4545#if ENABLE(WEBASSEMBLY)
    4646
     47#include "B3Compilation.h"
    4748#include "B3Type.h"
    4849#include <wtf/Vector.h>
     
    127128};
    128129
     130struct FunctionCompilation {
     131    std::unique_ptr<B3::Compilation> code;
     132    std::unique_ptr<B3::Compilation> jsEntryPoint;
     133};
     134
    129135} } // namespace JSC::WASM
    130136
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h

    r206794 r207453  
    155155    }
    156156
     157    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
     158        uint32_t alignment;
     159        if (!parseVarUInt32(alignment))
     160            return false;
     161
     162        uint32_t offset;
     163        if (!parseVarUInt32(offset))
     164            return false;
     165
     166        ExpressionType pointer = m_expressionStack.takeLast();
     167        ExpressionType result;
     168        if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset))
     169            return false;
     170        m_expressionStack.append(result);
     171        return true;
     172    }
     173
     174    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
     175        uint32_t alignment;
     176        if (!parseVarUInt32(alignment))
     177            return false;
     178
     179        uint32_t offset;
     180        if (!parseVarUInt32(offset))
     181            return false;
     182
     183        ExpressionType value = m_expressionStack.takeLast();
     184        ExpressionType pointer = m_expressionStack.takeLast();
     185        return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset);
     186    }
     187
    157188    case OpType::I32Const: {
    158189        uint32_t constant;
  • trunk/Source/JavaScriptCore/wasm/WASMModuleParser.cpp

    r206110 r207453  
    2929#if ENABLE(WEBASSEMBLY)
    3030
     31#include "JSWASMModule.h"
    3132#include "WASMFormat.h"
    3233#include "WASMOps.h"
    3334#include "WASMSections.h"
    3435
     36#include <sys/mman.h>
     37
    3538namespace JSC { namespace WASM {
    3639
     
    6366            dataLogLn("Starting to parse next section at offset: ", m_offset);
    6467
    65         Sections::Section section = Sections::Unknown;
    6668        uint8_t sectionByte;
    6769        if (!parseUInt7(sectionByte))
    6870            return false;
    6971
     72        if (verbose)
     73            dataLogLn("Section byte: ", sectionByte);
     74
     75        Sections::Section section = Sections::Unknown;
    7076        if (sectionByte) {
    71             if (sectionByte >= Sections::Unknown)
    72                 section = Sections::Unknown;
    73             else
     77            if (sectionByte < Sections::Unknown)
    7478                section = static_cast<Sections::Section>(sectionByte);
    7579        } else {
     
    97101
    98102        switch (section) {
     103
     104        case Sections::Memory: {
     105            if (verbose)
     106                dataLogLn("Parsing Memory.");
     107            if (!parseMemory())
     108                return false;
     109            break;
     110        }
     111
    99112        case Sections::FunctionTypes: {
    100113            if (verbose)
     
    142155    // TODO
    143156    return true;
     157}
     158
     159bool ModuleParser::parseMemory()
     160{
     161    uint8_t flags;
     162    if (!parseVarUInt1(flags))
     163        return false;
     164
     165    uint32_t size;
     166    if (!parseVarUInt32(size))
     167        return false;
     168    if (size > maxPageCount)
     169        return false;
     170
     171    uint32_t capacity = maxPageCount;
     172    if (flags) {
     173        if (!parseVarUInt32(capacity))
     174            return false;
     175        if (size > capacity || capacity > maxPageCount)
     176            return false;
     177    }
     178
     179    capacity *= pageSize;
     180    size *= pageSize;
     181
     182    Vector<unsigned> pinnedSizes = { 0 };
     183    m_memory = std::make_unique<Memory>(size, capacity, pinnedSizes);
     184    return m_memory->memory();
    144185}
    145186
  • trunk/Source/JavaScriptCore/wasm/WASMModuleParser.h

    r205552 r207453  
    2828#if ENABLE(WEBASSEMBLY)
    2929
     30#include "WASMMemory.h"
    3031#include "WASMOps.h"
    3132#include "WASMParser.h"
     
    4647    bool WARN_UNUSED_RETURN parse();
    4748
    48     const Vector<FunctionInformation>& functionInformation() { return m_functions; }
     49    const Vector<FunctionInformation>& functionInformation() const { return m_functions; }
     50    std::unique_ptr<Memory>& memory() { return m_memory; }
    4951
    5052private:
     53    bool WARN_UNUSED_RETURN parseMemory();
    5154    bool WARN_UNUSED_RETURN parseFunctionTypes();
    5255    bool WARN_UNUSED_RETURN parseFunctionSignatures();
    5356    bool WARN_UNUSED_RETURN parseFunctionDefinitions();
    5457    bool WARN_UNUSED_RETURN parseFunctionDefinition(uint32_t number);
    55     bool WARN_UNUSED_RETURN parseBlock();
    56     bool WARN_UNUSED_RETURN parseExpression(OpType);
    5758
    5859    Vector<FunctionInformation> m_functions;
    5960    Vector<Signature> m_signatures;
     61    std::unique_ptr<Memory> m_memory;
    6062};
    6163
  • trunk/Source/JavaScriptCore/wasm/WASMOps.h

    r206794 r207453  
    160160    macro(F64Ge, 0x9c, Oops)
    161161
     162#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
     163    macro(I32Load8S, 0x20, Oops) \
     164    macro(I32Load8U, 0x21, Oops) \
     165    macro(I32Load16S, 0x22, Oops) \
     166    macro(I32Load16U, 0x23, Oops) \
     167    macro(I64Load8S, 0x24, Oops) \
     168    macro(I64Load8U, 0x25, Oops) \
     169    macro(I64Load16S, 0x26, Oops) \
     170    macro(I64Load16U, 0x27, Oops) \
     171    macro(I64Load32S, 0x28, Oops) \
     172    macro(I64Load32U, 0x29, Oops) \
     173    macro(I32Load, 0x2a, Oops) \
     174    macro(I64Load, 0x2b, Oops) \
     175    macro(F32Load, 0x2c, Oops) \
     176    macro(F64Load, 0x2d, Oops)
     177
     178#define FOR_EACH_WASM_MEMORY_STORE_OP(macro) \
     179    macro(I32Store8, 0x2e, Oops) \
     180    macro(I32Store16, 0x2f, Oops) \
     181    macro(I64Store8, 0x30, Oops) \
     182    macro(I64Store16, 0x31, Oops) \
     183    macro(I64Store32, 0x32, Oops) \
     184    macro(I32Store, 0x33, Oops) \
     185    macro(I64Store, 0x34, Oops) \
     186    macro(F32Store, 0x35, Oops) \
     187    macro(F64Store, 0x36, Oops)
     188
    162189
    163190
     
    166193    FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
    167194    FOR_EACH_WASM_UNARY_OP(macro) \
    168     FOR_EACH_WASM_BINARY_OP(macro)
     195    FOR_EACH_WASM_BINARY_OP(macro) \
     196    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
     197    FOR_EACH_WASM_MEMORY_STORE_OP(macro)
    169198
    170199#define CREATE_ENUM_VALUE(name, id, b3op) name = id,
     
    188217enum class UnaryOpType : uint8_t {
    189218    FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
     219};
     220
     221enum class LoadOpType : uint8_t {
     222    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
     223};
     224
     225enum class StoreOpType : uint8_t {
     226    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
    190227};
    191228
  • trunk/Source/JavaScriptCore/wasm/WASMPlan.cpp

    r205552 r207453  
    3131#include "B3Compilation.h"
    3232#include "WASMB3IRGenerator.h"
     33#include "WASMCallingConvention.h"
    3334#include "WASMModuleParser.h"
    3435#include <wtf/DataLog.h>
     
    5455        if (verbose)
    5556            dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end);
    56         result.append(parseAndCompile(vm, source, info));
     57        result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info));
    5758    }
     59    memory = WTFMove(moduleParser.memory());
    5860}
    5961
  • trunk/Source/JavaScriptCore/wasm/WASMPlan.h

    r205552 r207453  
    3030#include "CompilationResult.h"
    3131#include "VM.h"
     32#include "WASMFormat.h"
    3233#include <wtf/ThreadSafeRefCounted.h>
    3334#include <wtf/Vector.h>
    3435
    35 namespace JSC {
    36 
    37 namespace B3 {
    38 class Compilation;
    39 } // namespace B3
    40 
    41 namespace WASM {
     36namespace JSC { namespace WASM {
     37class Memory;
    4238
    4339// TODO: This should create a WASM Module not a list of functions.
     
    4642    JS_EXPORT_PRIVATE Plan(VM&, Vector<uint8_t> source);
    4743
    48     Vector<std::unique_ptr<B3::Compilation>> result;
     44    Vector<std::unique_ptr<FunctionCompilation>> result;
     45    std::unique_ptr<Memory> memory;
    4946};
    5047
  • trunk/Source/JavaScriptCore/wasm/WASMSections.h

    r206110 r207453  
    3434        FunctionTypes = 1,
    3535        Signatures = 3,
     36        Memory = 5,
    3637        Definitions = 10,
    3738        Unknown
Note: See TracChangeset for help on using the changeset viewer.