Initial implementation of WebAssembly function compiler
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 20:32:35 +0000 (20:32 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 20:32:35 +0000 (20:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148734

Patch by Sukolsak Sakshuwong <sukolsak@gmail.com> on 2015-09-03
Reviewed by Filip Pizlo.

This patch introduces WASMFunctionCompiler, a class for generating
baseline JIT code for WebAssembly functions. The source for each
WebAssembly function is parsed in two passes.
- The first pass is done by WASMFunctionSyntaxChecker when the
  WebAssembly module is initialized. It validates the syntax,
  determines the start and the end offsets in the source, and
  calculates the stack height of the function.
- The second pass is done by WASMFunctionCompiler when the function
  is about to be executed.
This patch doesn't calculate the correct stack height nor generate
the correct code. That will be done in a subsequent patch.

* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* wasm/JSWASMModule.h:
(JSC::JSWASMModule::functionStartOffsetsInSource):
(JSC::JSWASMModule::functionStackHeights):
* wasm/WASMFunctionCompiler.h: Added.
(JSC::WASMFunctionCompiler::WASMFunctionCompiler):
(JSC::WASMFunctionCompiler::startFunction):
(JSC::WASMFunctionCompiler::endFunction):
(JSC::WASMFunctionCompiler::throwStackOverflowError):
(JSC::WASMFunctionCompiler::localAddress):
* wasm/WASMFunctionParser.cpp:
(JSC::WASMFunctionParser::checkSyntax):
(JSC::WASMFunctionParser::compile):
(JSC::WASMFunctionParser::parseFunction):
* wasm/WASMFunctionParser.h:
* wasm/WASMFunctionSyntaxChecker.h:
(JSC::WASMFunctionSyntaxChecker::startFunction):
(JSC::WASMFunctionSyntaxChecker::endFunction):
(JSC::WASMFunctionSyntaxChecker::stackHeight):
* wasm/WASMModuleParser.cpp:
(JSC::WASMModuleParser::parseFunctionDeclarationSection):
(JSC::WASMModuleParser::parseFunctionDefinition):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/wasm/JSWASMModule.h
Source/JavaScriptCore/wasm/WASMFunctionCompiler.h [new file with mode: 0644]
Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
Source/JavaScriptCore/wasm/WASMFunctionParser.h
Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h
Source/JavaScriptCore/wasm/WASMModuleParser.cpp

index 26c847a..41c7232 100644 (file)
@@ -1,3 +1,47 @@
+2015-09-03  Sukolsak Sakshuwong  <sukolsak@gmail.com>
+
+        Initial implementation of WebAssembly function compiler
+        https://bugs.webkit.org/show_bug.cgi?id=148734
+
+        Reviewed by Filip Pizlo.
+
+        This patch introduces WASMFunctionCompiler, a class for generating
+        baseline JIT code for WebAssembly functions. The source for each
+        WebAssembly function is parsed in two passes.
+        - The first pass is done by WASMFunctionSyntaxChecker when the
+          WebAssembly module is initialized. It validates the syntax,
+          determines the start and the end offsets in the source, and
+          calculates the stack height of the function.
+        - The second pass is done by WASMFunctionCompiler when the function
+          is about to be executed.
+        This patch doesn't calculate the correct stack height nor generate
+        the correct code. That will be done in a subsequent patch.
+
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * wasm/JSWASMModule.h:
+        (JSC::JSWASMModule::functionStartOffsetsInSource):
+        (JSC::JSWASMModule::functionStackHeights):
+        * wasm/WASMFunctionCompiler.h: Added.
+        (JSC::WASMFunctionCompiler::WASMFunctionCompiler):
+        (JSC::WASMFunctionCompiler::startFunction):
+        (JSC::WASMFunctionCompiler::endFunction):
+        (JSC::WASMFunctionCompiler::throwStackOverflowError):
+        (JSC::WASMFunctionCompiler::localAddress):
+        * wasm/WASMFunctionParser.cpp:
+        (JSC::WASMFunctionParser::checkSyntax):
+        (JSC::WASMFunctionParser::compile):
+        (JSC::WASMFunctionParser::parseFunction):
+        * wasm/WASMFunctionParser.h:
+        * wasm/WASMFunctionSyntaxChecker.h:
+        (JSC::WASMFunctionSyntaxChecker::startFunction):
+        (JSC::WASMFunctionSyntaxChecker::endFunction):
+        (JSC::WASMFunctionSyntaxChecker::stackHeight):
+        * wasm/WASMModuleParser.cpp:
+        (JSC::WASMModuleParser::parseFunctionDeclarationSection):
+        (JSC::WASMModuleParser::parseFunctionDefinition):
+
 2015-09-03  Saam barati  <sbarati@apple.com>
 
         Block scoped variables should be visible across scripts
index 42cc5f5..61bba5c 100644 (file)
     <ClInclude Include="..\wasm\JSWASMModule.h" />
     <ClInclude Include="..\wasm\WASMConstants.h" />
     <ClInclude Include="..\wasm\WASMFormat.h" />
+    <ClInclude Include="..\wasm\WASMFunctionCompiler.h" />
     <ClInclude Include="..\wasm\WASMFunctionParser.h" />
     <ClInclude Include="..\wasm\WASMFunctionSyntaxChecker.h" />
     <ClInclude Include="..\wasm\WASMModuleParser.h" />
index 5da4fe3..53281b8 100644 (file)
     <ClInclude Include="..\wasm\WASMFormat.h">
       <Filter>wasm</Filter>
     </ClInclude>
+    <ClInclude Include="..\wasm\WASMFunctionCompiler.h">
+      <Filter>wasm</Filter>
+    </ClInclude>
     <ClInclude Include="..\wasm\WASMFunctionParser.h">
       <Filter>wasm</Filter>
     </ClInclude>
index f1fd3b5..d807d37 100644 (file)
                7B0247561B8682E100542440 /* WASMFunctionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B0247531B8682D500542440 /* WASMFunctionParser.cpp */; };
                7B0247571B8682E400542440 /* WASMFunctionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B0247541B8682D500542440 /* WASMFunctionParser.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7B0247591B868EB700542440 /* WASMFunctionSyntaxChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B0247581B868EAE00542440 /* WASMFunctionSyntaxChecker.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7B2E010E1B97AA6900EF5D5C /* WASMFunctionCompiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B2E010D1B97AA5800EF5D5C /* WASMFunctionCompiler.h */; };
                7B39F76D1B62DE2E00360FB4 /* WASMModuleParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7B39F7691B62DE2200360FB4 /* WASMModuleParser.cpp */; };
                7B39F76E1B62DE3200360FB4 /* WASMModuleParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B39F76A1B62DE2200360FB4 /* WASMModuleParser.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7B39F7701B62DE3200360FB4 /* WASMReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B39F76C1B62DE2200360FB4 /* WASMReader.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7B0247531B8682D500542440 /* WASMFunctionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMFunctionParser.cpp; sourceTree = "<group>"; };
                7B0247541B8682D500542440 /* WASMFunctionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMFunctionParser.h; sourceTree = "<group>"; };
                7B0247581B868EAE00542440 /* WASMFunctionSyntaxChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMFunctionSyntaxChecker.h; sourceTree = "<group>"; };
+               7B2E010D1B97AA5800EF5D5C /* WASMFunctionCompiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMFunctionCompiler.h; sourceTree = "<group>"; };
                7B39F7691B62DE2200360FB4 /* WASMModuleParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMModuleParser.cpp; sourceTree = "<group>"; };
                7B39F76A1B62DE2200360FB4 /* WASMModuleParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMModuleParser.h; sourceTree = "<group>"; };
                7B39F76C1B62DE2200360FB4 /* WASMReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMReader.h; sourceTree = "<group>"; };
                                7B98D1351B60CD5A0023B1A4 /* JSWASMModule.h */,
                                7B0247521B8682D500542440 /* WASMConstants.h */,
                                7BC547D21B69599B00959B58 /* WASMFormat.h */,
+                               7B2E010D1B97AA5800EF5D5C /* WASMFunctionCompiler.h */,
                                7B0247531B8682D500542440 /* WASMFunctionParser.cpp */,
                                7B0247541B8682D500542440 /* WASMFunctionParser.h */,
                                7B0247581B868EAE00542440 /* WASMFunctionSyntaxChecker.h */,
                                0F3A1BFA1A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h in Headers */,
                                451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
                                86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
+                               7B2E010E1B97AA6900EF5D5C /* WASMFunctionCompiler.h in Headers */,
                                86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
                                86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */,
                                86704B8A12DBA33700A9FE7B /* YarrPattern.h in Headers */,
index 467b3e6..e54e8ac 100644 (file)
@@ -65,6 +65,8 @@ public:
     Vector<WASMFunctionPointerTable>& functionPointerTables() { return m_functionPointerTables; }
 
     Vector<WriteBarrier<JSFunction>>& functions() { return m_functions; }
+    Vector<unsigned>& functionStartOffsetsInSource() { return m_functionStartOffsetsInSource; }
+    Vector<unsigned>& functionStackHeights() { return m_functionStackHeights; }
 
 private:
     JSWASMModule(VM& vm, Structure* structure)
@@ -83,6 +85,8 @@ private:
     Vector<WASMFunctionPointerTable> m_functionPointerTables;
 
     Vector<WriteBarrier<JSFunction>> m_functions;
+    Vector<unsigned> m_functionStartOffsetsInSource;
+    Vector<unsigned> m_functionStackHeights;
 };
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h b/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
new file mode 100644 (file)
index 0000000..a2565a4
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WASMFunctionCompiler_h
+#define WASMFunctionCompiler_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "CCallHelpers.h"
+#include "JITOperations.h"
+#include "LinkBuffer.h"
+#include "MaxFrameExtentForSlowPathCall.h"
+
+namespace JSC {
+
+class WASMFunctionCompiler : private CCallHelpers {
+public:
+    typedef int Expression;
+    typedef int Statement;
+
+    union StackSlot {
+        int32_t intValue;
+        float floatValue;
+        double doubleValue;
+    };
+
+    WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, unsigned stackHeight)
+        : CCallHelpers(&vm, codeBlock)
+        , m_stackHeight(stackHeight)
+    {
+    }
+
+    void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
+    {
+        emitFunctionPrologue();
+        emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
+
+        m_beginLabel = label();
+
+        addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot)), GPRInfo::callFrameRegister, GPRInfo::regT1);
+        m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
+
+        move(GPRInfo::regT1, stackPointerRegister);
+        checkStackPointerAlignment();
+
+        m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
+
+        unsigned localIndex = 0;
+        for (size_t i = 0; i < arguments.size(); ++i) {
+            Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register));
+            switch (arguments[i]) {
+            case WASMType::I32:
+                load32(address, GPRInfo::regT0);
+                store32(GPRInfo::regT0, localAddress(localIndex++));
+                break;
+            case WASMType::F32:
+                load64(address, GPRInfo::regT0);
+                unboxDoubleWithoutAssertions(GPRInfo::regT0, FPRInfo::fpRegT0);
+                convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+                storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++));
+                break;
+            case WASMType::F64:
+                load64(address, GPRInfo::regT0);
+                unboxDoubleWithoutAssertions(GPRInfo::regT0, FPRInfo::fpRegT0);
+                storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++));
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+            }
+        }
+        for (uint32_t i = 0; i < numberOfI32LocalVariables; ++i)
+            store32(TrustedImm32(0), localAddress(localIndex++));
+        for (uint32_t i = 0; i < numberOfF32LocalVariables; ++i)
+            store32(TrustedImm32(0), localAddress(localIndex++));
+        for (uint32_t i = 0; i < numberOfF64LocalVariables; ++i)
+            store64(TrustedImm64(0), localAddress(localIndex++));
+
+        m_codeBlock->setNumParameters(1 + arguments.size());
+    }
+
+    void endFunction()
+    {
+        // FIXME: Remove these if the last statement is a return statement.
+        move(TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::returnValueGPR);
+        emitFunctionEpilogue();
+        ret();
+
+        m_stackOverflow.link(this);
+        if (maxFrameExtentForSlowPathCall)
+            addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
+        throwStackOverflowError();
+
+        // FIXME: Implement arity check.
+        Label arityCheck = label();
+        emitFunctionPrologue();
+        emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
+        jump(m_beginLabel);
+
+        LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed);
+
+        for (auto iterator : m_calls)
+            patchBuffer.link(iterator.first, FunctionPtr(iterator.second));
+
+        MacroAssemblerCodePtr withArityCheck = patchBuffer.locationOf(arityCheck);
+        CodeRef result = FINALIZE_CODE(patchBuffer, ("Baseline JIT code for WebAssembly"));
+        m_codeBlock->setJITCode(adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
+        m_codeBlock->capabilityLevel();
+    }
+
+private:
+    Address localAddress(unsigned localIndex) const
+    {
+        ASSERT(localIndex < m_numberOfLocals);
+        return Address(GPRInfo::callFrameRegister, -(localIndex + 1) * sizeof(StackSlot));
+    }
+
+    void throwStackOverflowError()
+    {
+        setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));
+
+        m_calls.append(std::make_pair(call(), FunctionPtr(operationThrowStackOverflowError).value()));
+
+        // lookupExceptionHandlerFromCallerFrame is passed two arguments, the VM and the exec (the CallFrame*).
+        move(TrustedImmPtr(m_vm), GPRInfo::argumentGPR0);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
+#if CPU(X86)
+        // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer!
+        poke(GPRInfo::argumentGPR0);
+        poke(GPRInfo::argumentGPR1, 1);
+#endif
+        m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value()));
+        jumpToExceptionHandler();
+    }
+
+    unsigned m_stackHeight;
+    unsigned m_numberOfLocals;
+
+    Label m_beginLabel;
+    Jump m_stackOverflow;
+
+    Vector<std::pair<Call, void*>> m_calls;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFunctionCompiler_h
index 78a1a19..5d404c7 100644 (file)
@@ -28,9 +28,8 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "CCallHelpers.h"
 #include "JSWASMModule.h"
-#include "LinkBuffer.h"
+#include "WASMFunctionCompiler.h"
 #include "WASMFunctionSyntaxChecker.h"
 
 #define PROPAGATE_ERROR() do { if (!m_errorMessage.isNull()) return 0; } while (0)
@@ -47,7 +46,7 @@
 
 namespace JSC {
 
-bool WASMFunctionParser::checkSyntax(JSWASMModule* module, const SourceCode& source, size_t functionIndex, unsigned startOffsetInSource, unsigned& endOffsetInSource, String& errorMessage)
+bool WASMFunctionParser::checkSyntax(JSWASMModule* module, const SourceCode& source, size_t functionIndex, unsigned startOffsetInSource, unsigned& endOffsetInSource, unsigned& stackHeight, String& errorMessage)
 {
     WASMFunctionParser parser(module, source, functionIndex);
     WASMFunctionSyntaxChecker syntaxChecker;
@@ -58,28 +57,17 @@ bool WASMFunctionParser::checkSyntax(JSWASMModule* module, const SourceCode& sou
         return false;
     }
     endOffsetInSource = parser.m_reader.offset();
+    stackHeight = syntaxChecker.stackHeight();
     return true;
 }
 
-void WASMFunctionParser::compile(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, const SourceCode&, size_t functionIndex)
+void WASMFunctionParser::compile(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, const SourceCode& source, size_t functionIndex)
 {
-    // FIXME: Actually compile the code.
-    CCallHelpers jit(&vm, codeBlock);
-    MacroAssembler::Label beginLabel = jit.label();
-    jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsNumber(0))), GPRInfo::returnValueGPR);
-    jit.ret();
-    MacroAssembler::Label arityCheck = jit.label();
-    jit.jump(beginLabel);
-
-    LinkBuffer patchBuffer(vm, jit, codeBlock, JITCompilationMustSucceed);
-    MacroAssemblerCodePtr withArityCheck = patchBuffer.locationOf(arityCheck);
-    MacroAssembler::CodeRef result = FINALIZE_CODE(patchBuffer, ("Baseline JIT code for WebAssembly"));
-    codeBlock->setJITCode(adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
-    codeBlock->capabilityLevel();
-
-    uint32_t signatureIndex = module->functionDeclarations()[functionIndex].signatureIndex;
-    const WASMSignature& signature = module->signatures()[signatureIndex];
-    codeBlock->setNumParameters(1 + signature.arguments.size());
+    WASMFunctionParser parser(module, source, functionIndex);
+    WASMFunctionCompiler compiler(vm, codeBlock, module->functionStackHeights()[functionIndex]);
+    parser.m_reader.setOffset(module->functionStartOffsetsInSource()[functionIndex]);
+    parser.parseFunction(compiler);
+    ASSERT(parser.m_errorMessage.isNull());
 }
 
 template <class Context>
@@ -102,7 +90,12 @@ bool WASMFunctionParser::parseFunction(Context& context)
     for (uint32_t i = 0; i < m_numberOfF64LocalVariables; ++i)
         m_localTypes.append(WASMType::F64);
 
+    context.startFunction(arguments, m_numberOfI32LocalVariables, m_numberOfF32LocalVariables, m_numberOfF64LocalVariables);
+
     parseBlockStatement(context);
+    PROPAGATE_ERROR();
+
+    context.endFunction();
     return true;
 }
 
index 704c46c..3463062 100644 (file)
@@ -42,7 +42,7 @@ class VM;
 
 class WASMFunctionParser {
 public:
-    static bool checkSyntax(JSWASMModule*, const SourceCode&, size_t functionIndex, unsigned startOffsetInSource, unsigned& endOffsetInSource, String& errorMessage);
+    static bool checkSyntax(JSWASMModule*, const SourceCode&, size_t functionIndex, unsigned startOffsetInSource, unsigned& endOffsetInSource, unsigned& stackHeight, String& errorMessage);
     static void compile(VM&, CodeBlock*, JSWASMModule*, const SourceCode&, size_t functionIndex);
 
 private:
index d4aa4de..5d329c3 100644 (file)
@@ -34,6 +34,19 @@ class WASMFunctionSyntaxChecker {
 public:
     typedef int Expression;
     typedef int Statement;
+
+    void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
+    {
+        // FIXME: Need to include the number of temporaries used.
+        m_stackHeight = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
+    }
+
+    void endFunction() { }
+
+    unsigned stackHeight() { return m_stackHeight; }
+
+private:
+    unsigned m_stackHeight;
 };
 
 } // namespace JSC
index 67e3aa6..45d19ce 100644 (file)
@@ -220,6 +220,8 @@ void WASMModuleParser::parseFunctionDeclarationSection()
     READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionDeclarations, "Cannot read the number of function declarations.");
     m_module->functionDeclarations().reserveInitialCapacity(numberOfFunctionDeclarations);
     m_module->functions().reserveInitialCapacity(numberOfFunctionDeclarations);
+    m_module->functionStartOffsetsInSource().reserveInitialCapacity(numberOfFunctionDeclarations);
+    m_module->functionStackHeights().reserveInitialCapacity(numberOfFunctionDeclarations);
     for (uint32_t i = 0; i < numberOfFunctionDeclarations; ++i) {
         WASMFunctionDeclaration functionDeclaration;
         READ_COMPACT_UINT32_OR_FAIL(functionDeclaration.signatureIndex, "Cannot read the signature index.");
@@ -262,8 +264,9 @@ void WASMModuleParser::parseFunctionDefinition(size_t functionIndex)
 {
     unsigned startOffsetInSource = m_reader.offset();
     unsigned endOffsetInSource;
+    unsigned stackHeight;
     String errorMessage;
-    if (!WASMFunctionParser::checkSyntax(m_module.get(), m_source, functionIndex, startOffsetInSource, endOffsetInSource, errorMessage)) {
+    if (!WASMFunctionParser::checkSyntax(m_module.get(), m_source, functionIndex, startOffsetInSource, endOffsetInSource, stackHeight, errorMessage)) {
         m_errorMessage = errorMessage;
         return;
     }
@@ -272,6 +275,8 @@ void WASMModuleParser::parseFunctionDefinition(size_t functionIndex)
     WebAssemblyExecutable* webAssemblyExecutable = WebAssemblyExecutable::create(m_vm, m_source, m_module.get(), functionIndex);
     JSFunction* function = JSFunction::create(m_vm, webAssemblyExecutable, m_globalObject.get());
     m_module->functions().uncheckedAppend(WriteBarrier<JSFunction>(m_vm, m_module.get(), function));
+    m_module->functionStartOffsetsInSource().uncheckedAppend(startOffsetInSource);
+    m_module->functionStackHeights().uncheckedAppend(stackHeight);
 }
 
 void WASMModuleParser::parseExportSection()