Changeset 189993 in webkit


Ignore:
Timestamp:
Sep 18, 2015 4:06:47 PM (9 years ago)
Author:
commit-queue@webkit.org
Message:

Implement linear memory instructions in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=149326

Patch by Sukolsak Sakshuwong <Sukolsak Sakshuwong> on 2015-09-18
Reviewed by Geoffrey Garen.

This patch implements linear memory instructions in WebAssembly.[1] To
use the linear memory, an ArrayBuffer must be passed to loadWebAssembly().

Notes:

  • We limit the ArrayBuffer's byte length to 231 - 1. This enables us to use only one comparison (unsigned greater than) to check for out-of-bounds access.
  • There is no consensus yet on what should happen when an out-of-bounds access occurs.[2] For now, we throw an error when that happens.
  • In asm.js, a heap access looks like this: int32Array[i >> 2]. Note that ">> 2" is part of the syntax and is required. pack-asmjs will produce bytecodes that look something like "LoadI32, i" (not "LoadI32, ShiftRightI32, i, 2"). The requirement of the shift operator prevents unaligned accesses in asm.js. (There is a proposal to support unaligned accesses in the future version of asm.js using DataView.[3]) The WebAssembly spec allows unaligned accesses.[4] But since we use asm.js for testing, we follow asm.js's behaviors for now.

[1]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#linear-memory
[2]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#out-of-bounds
[3]: https://wiki.mozilla.org/Javascript:SpiderMonkey:OdinMonkey#Possible_asm.js_extensions_that_don.27t_require_new_JS_features
[4]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#alignment

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:
  • jsc.cpp:

(GlobalObject::finishCreation):
(functionLoadWebAssembly):

  • tests/stress/wasm-linear-memory.js: Added.

(shouldBe):
(shouldThrow):

  • tests/stress/wasm/linear-memory.wasm: Added.
  • wasm/JSWASMModule.cpp:

(JSC::JSWASMModule::JSWASMModule):
(JSC::JSWASMModule::visitChildren):

  • wasm/JSWASMModule.h:

(JSC::JSWASMModule::create):
(JSC::JSWASMModule::arrayBuffer):
(JSC::JSWASMModule::JSWASMModule): Deleted.

  • wasm/WASMConstants.h:
  • wasm/WASMFunctionCompiler.h:

(JSC::sizeOfMemoryType):
(JSC::WASMFunctionCompiler::MemoryAddress::MemoryAddress):
(JSC::WASMFunctionCompiler::endFunction):
(JSC::WASMFunctionCompiler::buildLoad):
(JSC::WASMFunctionCompiler::buildStore):

  • wasm/WASMFunctionParser.cpp:

(JSC::WASMFunctionParser::parseStatement):
(JSC::WASMFunctionParser::parseExpressionI32):
(JSC::WASMFunctionParser::parseExpressionF32):
(JSC::WASMFunctionParser::parseExpressionF64):
(JSC::WASMFunctionParser::parseMemoryAddress):
(JSC::WASMFunctionParser::parseLoad):
(JSC::WASMFunctionParser::parseStore):

  • wasm/WASMFunctionParser.h:
  • wasm/WASMFunctionSyntaxChecker.h:

(JSC::WASMFunctionSyntaxChecker::MemoryAddress::MemoryAddress):
(JSC::WASMFunctionSyntaxChecker::buildLoad):
(JSC::WASMFunctionSyntaxChecker::buildStore):

  • wasm/WASMModuleParser.cpp:

(JSC::WASMModuleParser::WASMModuleParser):
(JSC::WASMModuleParser::parseModule):
(JSC::parseWebAssembly):
(JSC::WASMModuleParser::parse): Deleted.

  • wasm/WASMModuleParser.h:
Location:
trunk/Source/JavaScriptCore
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r189984 r189993  
     12015-09-18  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        Implement linear memory instructions in WebAssembly
     4        https://bugs.webkit.org/show_bug.cgi?id=149326
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch implements linear memory instructions in WebAssembly.[1] To
     9        use the linear memory, an ArrayBuffer must be passed to loadWebAssembly().
     10
     11        Notes:
     12        - We limit the ArrayBuffer's byte length to 2^31 - 1. This enables us to
     13          use only one comparison (unsigned greater than) to check for
     14          out-of-bounds access.
     15        - There is no consensus yet on what should happen when an out-of-bounds
     16          access occurs.[2] For now, we throw an error when that happens.
     17        - In asm.js, a heap access looks like this: int32Array[i >> 2]. Note
     18          that ">> 2" is part of the syntax and is required. pack-asmjs will
     19          produce bytecodes that look something like "LoadI32, i" (not
     20          "LoadI32, ShiftRightI32, i, 2"). The requirement of the shift operator
     21          prevents unaligned accesses in asm.js. (There is a proposal to support
     22          unaligned accesses in the future version of asm.js using DataView.[3])
     23          The WebAssembly spec allows unaligned accesses.[4] But since we use
     24          asm.js for testing, we follow asm.js's behaviors for now.
     25
     26        [1]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#linear-memory
     27        [2]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#out-of-bounds
     28        [3]: https://wiki.mozilla.org/Javascript:SpiderMonkey:OdinMonkey#Possible_asm.js_extensions_that_don.27t_require_new_JS_features
     29        [4]: https://github.com/WebAssembly/design/blob/master/AstSemantics.md#alignment
     30
     31        * jit/JITOperations.cpp:
     32        * jit/JITOperations.h:
     33        * jsc.cpp:
     34        (GlobalObject::finishCreation):
     35        (functionLoadWebAssembly):
     36        * tests/stress/wasm-linear-memory.js: Added.
     37        (shouldBe):
     38        (shouldThrow):
     39        * tests/stress/wasm/linear-memory.wasm: Added.
     40        * wasm/JSWASMModule.cpp:
     41        (JSC::JSWASMModule::JSWASMModule):
     42        (JSC::JSWASMModule::visitChildren):
     43        * wasm/JSWASMModule.h:
     44        (JSC::JSWASMModule::create):
     45        (JSC::JSWASMModule::arrayBuffer):
     46        (JSC::JSWASMModule::JSWASMModule): Deleted.
     47        * wasm/WASMConstants.h:
     48        * wasm/WASMFunctionCompiler.h:
     49        (JSC::sizeOfMemoryType):
     50        (JSC::WASMFunctionCompiler::MemoryAddress::MemoryAddress):
     51        (JSC::WASMFunctionCompiler::endFunction):
     52        (JSC::WASMFunctionCompiler::buildLoad):
     53        (JSC::WASMFunctionCompiler::buildStore):
     54        * wasm/WASMFunctionParser.cpp:
     55        (JSC::WASMFunctionParser::parseStatement):
     56        (JSC::WASMFunctionParser::parseExpressionI32):
     57        (JSC::WASMFunctionParser::parseExpressionF32):
     58        (JSC::WASMFunctionParser::parseExpressionF64):
     59        (JSC::WASMFunctionParser::parseMemoryAddress):
     60        (JSC::WASMFunctionParser::parseLoad):
     61        (JSC::WASMFunctionParser::parseStore):
     62        * wasm/WASMFunctionParser.h:
     63        * wasm/WASMFunctionSyntaxChecker.h:
     64        (JSC::WASMFunctionSyntaxChecker::MemoryAddress::MemoryAddress):
     65        (JSC::WASMFunctionSyntaxChecker::buildLoad):
     66        (JSC::WASMFunctionSyntaxChecker::buildStore):
     67        * wasm/WASMModuleParser.cpp:
     68        (JSC::WASMModuleParser::WASMModuleParser):
     69        (JSC::WASMModuleParser::parseModule):
     70        (JSC::parseWebAssembly):
     71        (JSC::WASMModuleParser::parse): Deleted.
     72        * wasm/WASMModuleParser.h:
     73
    1742015-09-18  Sukolsak Sakshuwong  <sukolsak@gmail.com>
    275
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r189967 r189993  
    106106    vm->throwException(callerFrame, createError(callerFrame, ASCIILiteral("Division by zero or division overflow.")));
    107107}
     108
     109void JIT_OPERATION operationThrowOutOfBoundsAccessError(ExecState* exec)
     110{
     111    VM* vm = &exec->vm();
     112    VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
     113    CallFrame* callerFrame = exec->callerFrame(vmEntryFrame);
     114
     115    NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
     116    ErrorHandlingScope errorScope(*vm);
     117    vm->throwException(callerFrame, createError(callerFrame, ASCIILiteral("Out-of-bounds access.")));
     118}
    108119#endif
    109120
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r189920 r189993  
    252252#if ENABLE(WEBASSEMBLY)
    253253void JIT_OPERATION operationThrowDivideError(ExecState*) WTF_INTERNAL;
     254void JIT_OPERATION operationThrowOutOfBoundsAccessError(ExecState*) WTF_INTERNAL;
    254255#endif
    255256int32_t JIT_OPERATION operationCallArityCheck(ExecState*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/jsc.cpp

    r189941 r189993  
    678678
    679679#if ENABLE(WEBASSEMBLY)
    680         addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 2);
     680        addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 3);
    681681#endif
    682682        addFunction(vm, "loadModule", functionLoadModule, 1);
     
    14511451    SourceCode source(sourceProvider);
    14521452    JSObject* imports = exec->argument(1).getObject();
     1453    JSArrayBuffer* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(2));
    14531454
    14541455    String errorMessage;
    1455     JSWASMModule* module = parseWebAssembly(exec, source, imports, errorMessage);
     1456    JSWASMModule* module = parseWebAssembly(exec, source, imports, arrayBuffer, errorMessage);
    14561457    if (!module)
    14571458        return JSValue::encode(exec->vm().throwException(exec, createSyntaxError(exec, errorMessage)));
  • trunk/Source/JavaScriptCore/wasm/JSWASMModule.cpp

    r189822 r189993  
    2929#if ENABLE(WEBASSEMBLY)
    3030
     31#include "JSArrayBuffer.h"
    3132#include "JSFunction.h"
    3233#include "SlotVisitorInlines.h"
     
    3536
    3637const ClassInfo JSWASMModule::s_info = { "WASMModule", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWASMModule) };
     38
     39JSWASMModule::JSWASMModule(VM& vm, Structure* structure, JSArrayBuffer* arrayBuffer)
     40    : Base(vm, structure)
     41{
     42    if (arrayBuffer)
     43        m_arrayBuffer.set(vm, this, arrayBuffer);
     44}
    3745
    3846void JSWASMModule::destroy(JSCell* cell)
     
    4755    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    4856    Base::visitChildren(thisObject, visitor);
     57    visitor.append(&thisObject->m_arrayBuffer);
    4958    for (auto function : thisObject->m_functions)
    5059        visitor.append(&function);
  • trunk/Source/JavaScriptCore/wasm/JSWASMModule.h

    r189822 r189993  
    5757    };
    5858
    59     static JSWASMModule* create(VM& vm, Structure* structure)
     59    static JSWASMModule* create(VM& vm, Structure* structure, JSArrayBuffer* arrayBuffer)
    6060    {
    61         JSWASMModule* module = new (NotNull, allocateCell<JSWASMModule>(vm.heap)) JSWASMModule(vm, structure);
     61        JSWASMModule* module = new (NotNull, allocateCell<JSWASMModule>(vm.heap)) JSWASMModule(vm, structure, arrayBuffer);
    6262        module->finishCreation(vm);
    6363        return module;
     
    8484    Vector<WASMFunctionPointerTable>& functionPointerTables() { return m_functionPointerTables; }
    8585
     86    const JSArrayBuffer* arrayBuffer() const { return m_arrayBuffer.get(); }
    8687    Vector<WriteBarrier<JSFunction>>& functions() { return m_functions; }
    8788    Vector<unsigned>& functionStartOffsetsInSource() { return m_functionStartOffsetsInSource; }
     
    9192
    9293private:
    93     JSWASMModule(VM& vm, Structure* structure)
    94         : Base(vm, structure)
    95     {
    96     }
     94    JSWASMModule(VM&, Structure*, JSArrayBuffer*);
    9795
    9896    Vector<uint32_t> m_i32Constants;
     
    106104    Vector<WASMFunctionPointerTable> m_functionPointerTables;
    107105
     106    WriteBarrier<JSArrayBuffer> m_arrayBuffer;
    108107    Vector<WriteBarrier<JSFunction>> m_functions;
    109108    Vector<unsigned> m_functionStartOffsetsInSource;
  • trunk/Source/JavaScriptCore/wasm/WASMConstants.h

    r189984 r189993  
    292292};
    293293
     294enum class WASMMemoryType {
     295    I8,
     296    I16,
     297    I32,
     298    F32,
     299    F64
     300};
     301
     302enum class MemoryAccessOffsetMode { NoOffset, WithOffset };
     303enum class MemoryAccessConversion { NoConversion, SignExtend, ZeroExtend };
     304
    294305static const uint8_t hasImmediateInOpFlag = 0x80;
    295306
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h

    r189984 r189993  
    3333#include "JIT.h"
    3434#include "JITOperations.h"
     35#include "JSArrayBuffer.h"
    3536#include "LinkBuffer.h"
    3637#include "MaxFrameExtentForSlowPathCall.h"
     
    7980#endif
    8081
     82static size_t sizeOfMemoryType(WASMMemoryType memoryType)
     83{
     84    switch (memoryType) {
     85    case WASMMemoryType::I8:
     86        return 1;
     87    case WASMMemoryType::I16:
     88        return 2;
     89    case WASMMemoryType::I32:
     90    case WASMMemoryType::F32:
     91        return 4;
     92    case WASMMemoryType::F64:
     93        return 8;
     94    default:
     95        ASSERT_NOT_REACHED();
     96    }
     97}
     98
    8199class WASMFunctionCompiler : private CCallHelpers {
    82100public:
     
    84102    typedef int Statement;
    85103    typedef int ExpressionList;
     104    struct MemoryAddress {
     105        MemoryAddress(void*) { }
     106        MemoryAddress(int, uint32_t offset)
     107            : offset(offset)
     108        {
     109        }
     110        uint32_t offset;
     111    };
    86112    struct JumpTarget {
    87113        Label label;
     
    198224            setupArgumentsExecState();
    199225            appendCallWithExceptionCheck(operationThrowDivideError);
     226        }
     227
     228        if (!m_outOfBoundsErrorJumpList.empty()) {
     229            m_outOfBoundsErrorJumpList.link(this);
     230
     231            setupArgumentsExecState();
     232            appendCallWithExceptionCheck(operationThrowOutOfBoundsAccessError);
    200233        }
    201234
     
    434467            ASSERT_NOT_REACHED();
    435468        }
     469        return UNUSED;
     470    }
     471
     472    int buildLoad(const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessConversion conversion)
     473    {
     474        const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl();
     475        move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0);
     476        load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
     477        if (memoryAddress.offset)
     478            add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1);
     479        and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1);
     480
     481        ASSERT(arrayBuffer->byteLength() < (unsigned)(1 << 31));
     482        if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType))
     483            m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType))));
     484        else
     485            m_outOfBoundsErrorJumpList.append(jump());
     486
     487        BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne);
     488
     489        switch (expressionType) {
     490        case WASMExpressionType::I32:
     491            switch (memoryType) {
     492            case WASMMemoryType::I8:
     493                if (conversion == MemoryAccessConversion::SignExtend)
     494                    load8SignedExtendTo32(address, GPRInfo::regT0);
     495                else {
     496                    ASSERT(conversion == MemoryAccessConversion::ZeroExtend);
     497                    load8(address, GPRInfo::regT0);
     498                }
     499                break;
     500            case WASMMemoryType::I16:
     501                if (conversion == MemoryAccessConversion::SignExtend)
     502                    load16SignedExtendTo32(address, GPRInfo::regT0);
     503                else {
     504                    ASSERT(conversion == MemoryAccessConversion::ZeroExtend);
     505                    load16(address, GPRInfo::regT0);
     506                }
     507                break;
     508            case WASMMemoryType::I32:
     509                load32(address, GPRInfo::regT0);
     510                break;
     511            default:
     512                ASSERT_NOT_REACHED();
     513            }
     514            store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
     515            break;
     516        case WASMExpressionType::F32:
     517            ASSERT(memoryType == WASMMemoryType::F32 && conversion == MemoryAccessConversion::NoConversion);
     518            load32(address, GPRInfo::regT0);
     519            store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
     520            break;
     521        case WASMExpressionType::F64:
     522            ASSERT(memoryType == WASMMemoryType::F64 && conversion == MemoryAccessConversion::NoConversion);
     523            loadDouble(address, FPRInfo::fpRegT0);
     524            storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
     525            break;
     526        default:
     527            ASSERT_NOT_REACHED();
     528        }
     529        return UNUSED;
     530    }
     531
     532    int buildStore(const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, int)
     533    {
     534        const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl();
     535        move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0);
     536        load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT1);
     537        if (memoryAddress.offset)
     538            add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1);
     539        and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1);
     540
     541        ASSERT(arrayBuffer->byteLength() < (1u << 31));
     542        if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType))
     543            m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType))));
     544        else
     545            m_outOfBoundsErrorJumpList.append(jump());
     546
     547        BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne);
     548
     549        switch (expressionType) {
     550        case WASMExpressionType::I32:
     551            load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2);
     552            switch (memoryType) {
     553            case WASMMemoryType::I8:
     554                store8(GPRInfo::regT2, address);
     555                break;
     556            case WASMMemoryType::I16:
     557                store16(GPRInfo::regT2, address);
     558                break;
     559            case WASMMemoryType::I32:
     560                store32(GPRInfo::regT2, address);
     561                break;
     562            default:
     563                ASSERT_NOT_REACHED();
     564            }
     565            break;
     566        case WASMExpressionType::F32:
     567            ASSERT(memoryType == WASMMemoryType::F32);
     568            load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2);
     569            store32(GPRInfo::regT2, address);
     570            break;
     571        case WASMExpressionType::F64:
     572            ASSERT(memoryType == WASMMemoryType::F64);
     573            loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
     574            storeDouble(FPRInfo::fpRegT0, address);
     575            break;
     576        default:
     577            ASSERT_NOT_REACHED();
     578        }
     579        m_tempStackTop -= 2;
    436580        return UNUSED;
    437581    }
     
    11871331    Jump m_stackOverflow;
    11881332    JumpList m_divideErrorJumpList;
     1333    JumpList m_outOfBoundsErrorJumpList;
    11891334    JumpList m_exceptionChecks;
    11901335
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp

    r189984 r189993  
    144144            parseSetGlobalStatement(context);
    145145            break;
     146        case WASMOpStatement::I32Store8:
     147            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset);
     148            break;
     149        case WASMOpStatement::I32StoreWithOffset8:
     150            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset);
     151            break;
     152        case WASMOpStatement::I32Store16:
     153            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset);
     154            break;
     155        case WASMOpStatement::I32StoreWithOffset16:
     156            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset);
     157            break;
     158        case WASMOpStatement::I32Store32:
     159            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::NoOffset);
     160            break;
     161        case WASMOpStatement::I32StoreWithOffset32:
     162            parseStore(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::WithOffset);
     163            break;
     164        case WASMOpStatement::F32Store:
     165            parseStore(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::NoOffset);
     166            break;
     167        case WASMOpStatement::F32StoreWithOffset:
     168            parseStore(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::WithOffset);
     169            break;
     170        case WASMOpStatement::F64Store:
     171            parseStore(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::NoOffset);
     172            break;
     173        case WASMOpStatement::F64StoreWithOffset:
     174            parseStore(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::WithOffset);
     175            break;
    146176        case WASMOpStatement::Return:
    147177            parseReturnStatement(context);
     
    180210            parseSwitchStatement(context);
    181211            break;
    182         case WASMOpStatement::I32Store8:
    183         case WASMOpStatement::I32StoreWithOffset8:
    184         case WASMOpStatement::I32Store16:
    185         case WASMOpStatement::I32StoreWithOffset16:
    186         case WASMOpStatement::I32Store32:
    187         case WASMOpStatement::I32StoreWithOffset32:
    188         case WASMOpStatement::F32Store:
    189         case WASMOpStatement::F32StoreWithOffset:
    190         case WASMOpStatement::F64Store:
    191         case WASMOpStatement::F64StoreWithOffset:
    192212        case WASMOpStatement::CallInternal:
    193213        case WASMOpStatement::CallIndirect:
     
    529549        case WASMOpExpressionI32::GetGlobal:
    530550            return parseGetGlobalExpressionI32(context);
     551        case WASMOpExpressionI32::SLoad8:
     552            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::SignExtend);
     553        case WASMOpExpressionI32::SLoadWithOffset8:
     554            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::SignExtend);
     555        case WASMOpExpressionI32::ULoad8:
     556            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::ZeroExtend);
     557        case WASMOpExpressionI32::ULoadWithOffset8:
     558            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::ZeroExtend);
     559        case WASMOpExpressionI32::SLoad16:
     560            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::SignExtend);
     561        case WASMOpExpressionI32::SLoadWithOffset16:
     562            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::SignExtend);
     563        case WASMOpExpressionI32::ULoad16:
     564            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::ZeroExtend);
     565        case WASMOpExpressionI32::ULoadWithOffset16:
     566            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::ZeroExtend);
     567        case WASMOpExpressionI32::Load32:
     568            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::NoOffset);
     569        case WASMOpExpressionI32::LoadWithOffset32:
     570            return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::WithOffset);
    531571        case WASMOpExpressionI32::CallInternal:
    532572            return parseCallInternal(context, WASMExpressionType::I32);
     
    586626        case WASMOpExpressionI32::SetLocal:
    587627        case WASMOpExpressionI32::SetGlobal:
    588         case WASMOpExpressionI32::SLoad8:
    589         case WASMOpExpressionI32::SLoadWithOffset8:
    590         case WASMOpExpressionI32::ULoad8:
    591         case WASMOpExpressionI32::ULoadWithOffset8:
    592         case WASMOpExpressionI32::SLoad16:
    593         case WASMOpExpressionI32::SLoadWithOffset16:
    594         case WASMOpExpressionI32::ULoad16:
    595         case WASMOpExpressionI32::ULoadWithOffset16:
    596         case WASMOpExpressionI32::Load32:
    597         case WASMOpExpressionI32::LoadWithOffset32:
    598628        case WASMOpExpressionI32::Store8:
    599629        case WASMOpExpressionI32::StoreWithOffset8:
     
    749779        case WASMOpExpressionF32::GetGlobal:
    750780            return parseGetGlobalExpressionF32(context);
     781        case WASMOpExpressionF32::Load:
     782            return parseLoad(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::NoOffset);
     783        case WASMOpExpressionF32::LoadWithOffset:
     784            return parseLoad(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::WithOffset);
    751785        case WASMOpExpressionF32::CallInternal:
    752786            return parseCallInternal(context, WASMExpressionType::F32);
     
    772806        case WASMOpExpressionF32::SetLocal:
    773807        case WASMOpExpressionF32::SetGlobal:
    774         case WASMOpExpressionF32::Load:
    775         case WASMOpExpressionF32::LoadWithOffset:
    776808        case WASMOpExpressionF32::Store:
    777809        case WASMOpExpressionF32::StoreWithOffset:
     
    881913        case WASMOpExpressionF64::GetGlobal:
    882914            return parseGetGlobalExpressionF64(context);
     915        case WASMOpExpressionF64::Load:
     916            return parseLoad(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::NoOffset);
     917        case WASMOpExpressionF64::LoadWithOffset:
     918            return parseLoad(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::WithOffset);
    883919        case WASMOpExpressionF64::CallInternal:
    884920            return parseCallInternal(context, WASMExpressionType::F64);
     
    895931        case WASMOpExpressionF64::SetLocal:
    896932        case WASMOpExpressionF64::SetGlobal:
    897         case WASMOpExpressionF64::Load:
    898         case WASMOpExpressionF64::LoadWithOffset:
    899933        case WASMOpExpressionF64::Store:
    900934        case WASMOpExpressionF64::StoreWithOffset:
     
    9911025
    9921026template <class Context>
     1027ContextMemoryAddress WASMFunctionParser::parseMemoryAddress(Context& context, MemoryAccessOffsetMode offsetMode)
     1028{
     1029    uint32_t offset = 0;
     1030    if (offsetMode == MemoryAccessOffsetMode::WithOffset)
     1031        READ_COMPACT_UINT32_OR_FAIL(offset, "Cannot read the address offset.");
     1032    ContextExpression index = parseExpressionI32(context);
     1033    PROPAGATE_ERROR();
     1034    return ContextMemoryAddress(index, offset);
     1035}
     1036
     1037template <class Context>
     1038ContextExpression WASMFunctionParser::parseLoad(Context& context, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessOffsetMode offsetMode, MemoryAccessConversion conversion)
     1039{
     1040    FAIL_IF_FALSE(m_module->arrayBuffer(), "An ArrayBuffer is not provided.");
     1041    const ContextMemoryAddress& memoryAddress = parseMemoryAddress(context, offsetMode);
     1042    PROPAGATE_ERROR();
     1043    return context.buildLoad(memoryAddress, expressionType, memoryType, conversion);
     1044}
     1045
     1046template <class Context>
     1047ContextExpression WASMFunctionParser::parseStore(Context& context, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessOffsetMode offsetMode)
     1048{
     1049    FAIL_IF_FALSE(m_module->arrayBuffer(), "An ArrayBuffer is not provided.");
     1050    const ContextMemoryAddress& memoryAddress = parseMemoryAddress(context, offsetMode);
     1051    PROPAGATE_ERROR();
     1052
     1053    ContextExpression value = parseExpression(context, expressionType);
     1054    PROPAGATE_ERROR();
     1055    return context.buildStore(memoryAddress, expressionType, memoryType, value);
     1056}
     1057
     1058template <class Context>
    9931059ContextExpressionList WASMFunctionParser::parseCallArguments(Context& context, const Vector<WASMType>& arguments)
    9941060{
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h

    r189984 r189993  
    3535#define ContextStatement typename Context::Statement
    3636#define ContextExpressionList typename Context::ExpressionList
     37#define ContextMemoryAddress typename Context::MemoryAddress
    3738#define ContextJumpTarget typename Context::JumpTarget
    3839
     
    114115    template <class Context> ContextExpression parseGetGlobalExpressionF64(Context&);
    115116
     117    template <class Context> ContextMemoryAddress parseMemoryAddress(Context&, MemoryAccessOffsetMode);
     118    template <class Context> ContextExpression parseLoad(Context&, WASMExpressionType, WASMMemoryType, MemoryAccessOffsetMode, MemoryAccessConversion = MemoryAccessConversion::NoConversion);
     119    template <class Context> ContextExpression parseStore(Context&, WASMExpressionType, WASMMemoryType, MemoryAccessOffsetMode);
     120
    116121    template <class Context> ContextExpressionList parseCallArguments(Context&, const Vector<WASMType>& arguments);
    117122    template <class Context> ContextExpression parseCallInternal(Context&, WASMExpressionType returnType);
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h

    r189984 r189993  
    3838    typedef int Statement;
    3939    typedef int ExpressionList;
     40    struct MemoryAddress {
     41        MemoryAddress(void*) { }
     42        MemoryAddress(int, uint32_t) { }
     43    };
    4044    typedef int JumpTarget;
    4145    enum class JumpCondition { Zero, NonZero };
     
    104108    int buildConvertType(int, WASMExpressionType, WASMExpressionType, WASMTypeConversion)
    105109    {
     110        return UNUSED;
     111    }
     112
     113    int buildLoad(const MemoryAddress&, WASMExpressionType, WASMMemoryType, MemoryAccessConversion)
     114    {
     115        return UNUSED;
     116    }
     117
     118    int buildStore(const MemoryAddress&, WASMExpressionType, WASMMemoryType, int)
     119    {
     120        m_tempStackTop -= 2;
    106121        return UNUSED;
    107122    }
  • trunk/Source/JavaScriptCore/wasm/WASMModuleParser.cpp

    r189892 r189993  
    2929#if ENABLE(WEBASSEMBLY)
    3030
     31#include "JSArrayBuffer.h"
    3132#include "JSCInlines.h"
    3233#include "JSWASMModule.h"
     
    5051namespace JSC {
    5152
    52 WASMModuleParser::WASMModuleParser(VM& vm, JSGlobalObject* globalObject, const SourceCode& source, JSObject* imports)
     53WASMModuleParser::WASMModuleParser(VM& vm, JSGlobalObject* globalObject, const SourceCode& source, JSObject* imports, JSArrayBuffer* arrayBuffer)
    5354    : m_vm(vm)
    5455    , m_globalObject(vm, globalObject)
     
    5657    , m_imports(vm, imports)
    5758    , m_reader(static_cast<WebAssemblySourceProvider*>(source.provider())->data())
     59    , m_module(vm, JSWASMModule::create(vm, globalObject->wasmModuleStructure(), arrayBuffer))
    5860{
    5961}
     
    6163JSWASMModule* WASMModuleParser::parse(ExecState* exec, String& errorMessage)
    6264{
    63     m_module.set(m_vm, JSWASMModule::create(m_vm, m_globalObject->wasmModuleStructure()));
    6465    parseModule(exec);
    6566    if (!m_errorMessage.isNull()) {
     
    9495    PROPAGATE_ERROR();
    9596    parseExportSection();
     97    PROPAGATE_ERROR();
     98
     99    FAIL_IF_FALSE(!m_module->arrayBuffer() || m_module->arrayBuffer()->impl()->byteLength() < (1u << 31), "The ArrayBuffer's length must be less than 2^31.");
    96100}
    97101
     
    363367}
    364368
    365 JSWASMModule* parseWebAssembly(ExecState* exec, const SourceCode& source, JSObject* imports, String& errorMessage)
    366 {
    367     WASMModuleParser moduleParser(exec->vm(), exec->lexicalGlobalObject(), source, imports);
     369JSWASMModule* parseWebAssembly(ExecState* exec, const SourceCode& source, JSObject* imports, JSArrayBuffer* arrayBuffer, String& errorMessage)
     370{
     371    WASMModuleParser moduleParser(exec->vm(), exec->lexicalGlobalObject(), source, imports, arrayBuffer);
    368372    return moduleParser.parse(exec, errorMessage);
    369373}
  • trunk/Source/JavaScriptCore/wasm/WASMModuleParser.h

    r189846 r189993  
    3636
    3737class ExecState;
     38class JSArrayBuffer;
    3839class JSGlobalObject;
    3940class JSWASMModule;
     
    4344class WASMModuleParser {
    4445public:
    45     WASMModuleParser(VM&, JSGlobalObject*, const SourceCode&, JSObject* imports);
     46    WASMModuleParser(VM&, JSGlobalObject*, const SourceCode&, JSObject* imports, JSArrayBuffer*);
    4647    JSWASMModule* parse(ExecState*, String& errorMessage);
    4748
     
    6869};
    6970
    70 JS_EXPORT_PRIVATE JSWASMModule* parseWebAssembly(ExecState*, const SourceCode&, JSObject* imports, String& errorMessage);
     71JS_EXPORT_PRIVATE JSWASMModule* parseWebAssembly(ExecState*, const SourceCode&, JSObject* imports, JSArrayBuffer*, String& errorMessage);
    7172
    7273} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.