summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/wasm
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
commit881da28418d380042aa95a97f0cbd42560a64f7c (patch)
treea794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/wasm
parent7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff)
parent0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff)
downloadqtwebkit-881da28418d380042aa95a97f0cbd42560a64f7c.tar.gz
Merge 'wip/next' into dev
Change-Id: Iff9ee5e23bb326c4371ec8ed81d56f2f05d680e9
Diffstat (limited to 'Source/JavaScriptCore/wasm')
-rw-r--r--Source/JavaScriptCore/wasm/JSWASMModule.cpp68
-rw-r--r--Source/JavaScriptCore/wasm/JSWASMModule.h118
-rw-r--r--Source/JavaScriptCore/wasm/WASMConstants.h329
-rw-r--r--Source/JavaScriptCore/wasm/WASMFormat.h98
-rw-r--r--Source/JavaScriptCore/wasm/WASMFunctionB3IRGenerator.h394
-rw-r--r--Source/JavaScriptCore/wasm/WASMFunctionCompiler.h1541
-rw-r--r--Source/JavaScriptCore/wasm/WASMFunctionParser.cpp1225
-rw-r--r--Source/JavaScriptCore/wasm/WASMFunctionParser.h148
-rw-r--r--Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h287
-rw-r--r--Source/JavaScriptCore/wasm/WASMModuleParser.cpp377
-rw-r--r--Source/JavaScriptCore/wasm/WASMModuleParser.h77
-rw-r--r--Source/JavaScriptCore/wasm/WASMReader.cpp249
-rw-r--r--Source/JavaScriptCore/wasm/WASMReader.h79
13 files changed, 4990 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wasm/JSWASMModule.cpp b/Source/JavaScriptCore/wasm/JSWASMModule.cpp
new file mode 100644
index 000000000..c7ea4a6ed
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/JSWASMModule.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSWASMModule.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSArrayBuffer.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSFunction.h"
+#include "SlotVisitorInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSWASMModule::s_info = { "WASMModule", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWASMModule) };
+
+JSWASMModule::JSWASMModule(VM& vm, Structure* structure, JSArrayBuffer* arrayBuffer)
+ : Base(vm, structure)
+{
+ if (arrayBuffer)
+ m_arrayBuffer.set(vm, this, arrayBuffer);
+}
+
+void JSWASMModule::destroy(JSCell* cell)
+{
+ JSWASMModule* thisObject = jsCast<JSWASMModule*>(cell);
+ thisObject->JSWASMModule::~JSWASMModule();
+}
+
+void JSWASMModule::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSWASMModule* thisObject = jsCast<JSWASMModule*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_arrayBuffer);
+ for (auto function : thisObject->m_functions)
+ visitor.append(&function);
+ for (auto importedFunction : thisObject->m_importedFunctions)
+ visitor.append(&importedFunction);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/JSWASMModule.h b/Source/JavaScriptCore/wasm/JSWASMModule.h
new file mode 100644
index 000000000..2d16791cc
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/JSWASMModule.h
@@ -0,0 +1,118 @@
+/*
+ * 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 JSWASMModule_h
+#define JSWASMModule_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSDestructibleObject.h"
+#include "WASMFormat.h"
+
+namespace JSC {
+
+class JSWASMModule : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ union GlobalVariable {
+ GlobalVariable(int32_t value)
+ : intValue(value)
+ {
+ }
+ GlobalVariable(float value)
+ : floatValue(value)
+ {
+ }
+ GlobalVariable(double value)
+ : doubleValue(value)
+ {
+ }
+
+ int32_t intValue;
+ float floatValue;
+ double doubleValue;
+ };
+
+ static JSWASMModule* create(VM& vm, Structure* structure, JSArrayBuffer* arrayBuffer)
+ {
+ JSWASMModule* module = new (NotNull, allocateCell<JSWASMModule>(vm.heap)) JSWASMModule(vm, structure, arrayBuffer);
+ module->finishCreation(vm);
+ return module;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
+ {
+ return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ Vector<uint32_t>& i32Constants() { return m_i32Constants; }
+ Vector<float>& f32Constants() { return m_f32Constants; }
+ Vector<double>& f64Constants() { return m_f64Constants; }
+ Vector<WASMSignature>& signatures() { return m_signatures; }
+ Vector<WASMFunctionImport>& functionImports() { return m_functionImports; }
+ Vector<WASMFunctionImportSignature>& functionImportSignatures() { return m_functionImportSignatures; }
+ Vector<WASMType>& globalVariableTypes() { return m_globalVariableTypes; }
+ Vector<WASMFunctionDeclaration>& functionDeclarations() { return m_functionDeclarations; }
+ Vector<WASMFunctionPointerTable>& functionPointerTables() { return m_functionPointerTables; }
+
+ const JSArrayBuffer* arrayBuffer() const { return m_arrayBuffer.get(); }
+ Vector<WriteBarrier<JSFunction>>& functions() { return m_functions; }
+ Vector<unsigned>& functionStartOffsetsInSource() { return m_functionStartOffsetsInSource; }
+ Vector<unsigned>& functionStackHeights() { return m_functionStackHeights; }
+ Vector<GlobalVariable>& globalVariables() { return m_globalVariables; }
+ Vector<WriteBarrier<JSFunction>>& importedFunctions() { return m_importedFunctions; }
+
+private:
+ JSWASMModule(VM&, Structure*, JSArrayBuffer*);
+
+ Vector<uint32_t> m_i32Constants;
+ Vector<float> m_f32Constants;
+ Vector<double> m_f64Constants;
+ Vector<WASMSignature> m_signatures;
+ Vector<WASMFunctionImport> m_functionImports;
+ Vector<WASMFunctionImportSignature> m_functionImportSignatures;
+ Vector<WASMType> m_globalVariableTypes;
+ Vector<WASMFunctionDeclaration> m_functionDeclarations;
+ Vector<WASMFunctionPointerTable> m_functionPointerTables;
+
+ WriteBarrier<JSArrayBuffer> m_arrayBuffer;
+ Vector<WriteBarrier<JSFunction>> m_functions;
+ Vector<unsigned> m_functionStartOffsetsInSource;
+ Vector<unsigned> m_functionStackHeights;
+ Vector<GlobalVariable> m_globalVariables;
+ Vector<WriteBarrier<JSFunction>> m_importedFunctions;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // JSWASMModule_h
diff --git a/Source/JavaScriptCore/wasm/WASMConstants.h b/Source/JavaScriptCore/wasm/WASMConstants.h
new file mode 100644
index 000000000..4e3bd443f
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMConstants.h
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ *
+ * =========================================================================
+ *
+ * Copyright (c) 2015 by the repository authors of
+ * WebAssembly/polyfill-prototype-1.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WASMConstants_h
+#define WASMConstants_h
+
+#if ENABLE(WEBASSEMBLY)
+
+namespace JSC {
+
+static const uint32_t wasmMagicNumber = 0x6d736177;
+
+enum class WASMOpKind {
+ Statement,
+ Expression
+};
+
+enum class WASMOpStatement : uint8_t {
+ SetLocal,
+ SetGlobal,
+ I32Store8,
+ I32StoreWithOffset8,
+ I32Store16,
+ I32StoreWithOffset16,
+ I32Store32,
+ I32StoreWithOffset32,
+ F32Store,
+ F32StoreWithOffset,
+ F64Store,
+ F64StoreWithOffset,
+ CallInternal,
+ CallIndirect,
+ CallImport,
+ Return,
+ Block,
+ If,
+ IfElse,
+ While,
+ Do,
+ Label,
+ Break,
+ BreakLabel,
+ Continue,
+ ContinueLabel,
+ Switch,
+ NumberOfWASMOpStatements
+};
+
+enum class WASMOpStatementWithImmediate : uint8_t {
+ SetLocal,
+ SetGlobal,
+ NumberOfWASMOpStatementWithImmediates
+};
+
+enum class WASMOpExpressionI32 : uint8_t {
+ ConstantPoolIndex,
+ Immediate,
+ GetLocal,
+ GetGlobal,
+ SetLocal,
+ SetGlobal,
+ SLoad8,
+ SLoadWithOffset8,
+ ULoad8,
+ ULoadWithOffset8,
+ SLoad16,
+ SLoadWithOffset16,
+ ULoad16,
+ ULoadWithOffset16,
+ Load32,
+ LoadWithOffset32,
+ Store8,
+ StoreWithOffset8,
+ Store16,
+ StoreWithOffset16,
+ Store32,
+ StoreWithOffset32,
+ CallInternal,
+ CallIndirect,
+ CallImport,
+ Conditional,
+ Comma,
+ FromF32,
+ FromF64,
+ Negate,
+ Add,
+ Sub,
+ Mul,
+ SDiv,
+ UDiv,
+ SMod,
+ UMod,
+ BitNot,
+ BitOr,
+ BitAnd,
+ BitXor,
+ LeftShift,
+ ArithmeticRightShift,
+ LogicalRightShift,
+ CountLeadingZeros,
+ LogicalNot,
+ EqualI32,
+ EqualF32,
+ EqualF64,
+ NotEqualI32,
+ NotEqualF32,
+ NotEqualF64,
+ SLessThanI32,
+ ULessThanI32,
+ LessThanF32,
+ LessThanF64,
+ SLessThanOrEqualI32,
+ ULessThanOrEqualI32,
+ LessThanOrEqualF32,
+ LessThanOrEqualF64,
+ SGreaterThanI32,
+ UGreaterThanI32,
+ GreaterThanF32,
+ GreaterThanF64,
+ SGreaterThanOrEqualI32,
+ UGreaterThanOrEqualI32,
+ GreaterThanOrEqualF32,
+ GreaterThanOrEqualF64,
+ SMin,
+ UMin,
+ SMax,
+ UMax,
+ Abs,
+ NumberOfWASMOpExpressionI32s
+};
+
+enum class WASMOpExpressionI32WithImmediate : uint8_t {
+ ConstantPoolIndex,
+ Immediate,
+ GetLocal,
+ NumberOfWASMOpExpressionI32WithImmediates
+};
+
+enum class WASMOpExpressionF32 : uint8_t {
+ ConstantPoolIndex,
+ Immediate,
+ GetLocal,
+ GetGlobal,
+ SetLocal,
+ SetGlobal,
+ Load,
+ LoadWithOffset,
+ Store,
+ StoreWithOffset,
+ CallInternal,
+ CallIndirect,
+ Conditional,
+ Comma,
+ FromS32,
+ FromU32,
+ FromF64,
+ Negate,
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Abs,
+ Ceil,
+ Floor,
+ Sqrt,
+ NumberOfWASMOpExpressionF32s
+};
+
+enum class WASMOpExpressionF32WithImmediate : uint8_t {
+ ConstantPoolIndex,
+ GetLocal,
+ NumberOfWASMOpExpressionF32WithImmediates
+};
+
+enum class WASMOpExpressionF64 : uint8_t {
+ ConstantPoolIndex,
+ Immediate,
+ GetLocal,
+ GetGlobal,
+ SetLocal,
+ SetGlobal,
+ Load,
+ LoadWithOffset,
+ Store,
+ StoreWithOffset,
+ CallInternal,
+ CallIndirect,
+ CallImport,
+ Conditional,
+ Comma,
+ FromS32,
+ FromU32,
+ FromF32,
+ Negate,
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Mod,
+ Min,
+ Max,
+ Abs,
+ Ceil,
+ Floor,
+ Sqrt,
+ Cos,
+ Sin,
+ Tan,
+ ACos,
+ ASin,
+ ATan,
+ ATan2,
+ Exp,
+ Ln,
+ Pow,
+ NumberOfWASMOpExpressionF64s
+};
+
+enum class WASMOpExpressionF64WithImmediate : uint8_t {
+ ConstantPoolIndex,
+ GetLocal,
+ NumberOfWASMOpExpressionF64WithImmediates
+};
+
+enum class WASMOpExpressionVoid : uint8_t {
+ CallInternal,
+ CallIndirect,
+ CallImport,
+ NumberOfWASMOpExpressionVoids
+};
+
+enum class WASMVariableTypes : uint8_t {
+ I32 = 1 << 0,
+ F32 = 1 << 1,
+ F64 = 1 << 2,
+ NumberOfVariableTypes = 8
+};
+
+enum class WASMVariableTypesWithImmediate : uint8_t {
+ I32,
+ NumberOfVariableTypesWithImmediates
+};
+
+enum class WASMSwitchCase : uint8_t {
+ CaseWithNoStatements,
+ CaseWithStatement,
+ CaseWithBlockStatement,
+ DefaultWithNoStatements,
+ DefaultWithStatement,
+ DefaultWithBlockStatement,
+ NumberOfSwitchCases
+};
+
+enum class WASMExportFormat : uint8_t {
+ Default,
+ Record,
+ NumberOfExportFormats
+};
+
+enum class WASMTypeConversion {
+ ConvertSigned,
+ ConvertUnsigned,
+ Promote,
+ Demote,
+};
+
+enum class WASMMemoryType {
+ I8,
+ I16,
+ I32,
+ F32,
+ F64
+};
+
+enum class MemoryAccessOffsetMode { NoOffset, WithOffset };
+enum class MemoryAccessConversion { NoConversion, SignExtend, ZeroExtend };
+
+static const uint8_t hasImmediateInOpFlag = 0x80;
+
+static const unsigned opWithImmediateBits = 2;
+static const uint32_t opWithImmediateLimit = 1 << opWithImmediateBits;
+
+static const unsigned immediateBits = 5;
+static const uint32_t immediateLimit = 1 << immediateBits;
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMConstants_h
diff --git a/Source/JavaScriptCore/wasm/WASMFormat.h b/Source/JavaScriptCore/wasm/WASMFormat.h
new file mode 100644
index 000000000..b36341056
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFormat.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * =========================================================================
+ *
+ * Copyright (c) 2015 by the repository authors of
+ * WebAssembly/polyfill-prototype-1.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WASMFormat_h
+#define WASMFormat_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class JSFunction;
+
+enum class WASMType : uint8_t {
+ I32,
+ F32,
+ F64,
+ NumberOfTypes
+};
+
+enum class WASMExpressionType : uint8_t {
+ I32,
+ F32,
+ F64,
+ Void,
+ NumberOfExpressionTypes
+};
+
+struct WASMSignature {
+ WASMExpressionType returnType;
+ Vector<WASMType> arguments;
+};
+
+struct WASMFunctionImport {
+ String functionName;
+};
+
+struct WASMFunctionImportSignature {
+ uint32_t signatureIndex;
+ uint32_t functionImportIndex;
+};
+
+struct WASMFunctionDeclaration {
+ uint32_t signatureIndex;
+};
+
+struct WASMFunctionPointerTable {
+ uint32_t signatureIndex;
+ Vector<uint32_t> functionIndices;
+ Vector<JSFunction*> functions;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFormat_h
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionB3IRGenerator.h b/Source/JavaScriptCore/wasm/WASMFunctionB3IRGenerator.h
new file mode 100644
index 000000000..7813a23da
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFunctionB3IRGenerator.h
@@ -0,0 +1,394 @@
+/*
+ * 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 WASMFunctionB3IRGenerator_h
+#define WASMFunctionB3IRGenerator_h
+
+#if ENABLE(WEBASSEMBLY) && ENABLE(FTL_JIT)
+
+#include "FTLAbbreviatedTypes.h"
+
+#define UNUSED 0
+
+namespace JSC {
+
+using FTL::LBasicBlock;
+using FTL::LValue;
+
+class WASMFunctionB3IRGenerator {
+public:
+ typedef LValue Expression;
+ typedef int Statement;
+ typedef Vector<LValue> ExpressionList;
+ struct MemoryAddress {
+ MemoryAddress(void*) { }
+ MemoryAddress(LValue index, uint32_t offset)
+ : index(index)
+ , offset(offset)
+ {
+ }
+ LValue index;
+ uint32_t offset;
+ };
+ typedef LBasicBlock JumpTarget;
+ enum class JumpCondition { Zero, NonZero };
+
+ void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(arguments);
+ UNUSED_PARAM(numberOfI32LocalVariables);
+ UNUSED_PARAM(numberOfF32LocalVariables);
+ UNUSED_PARAM(numberOfF64LocalVariables);
+ }
+
+ void endFunction()
+ {
+ // FIXME: Implement this method.
+ }
+
+ LValue buildSetLocal(WASMOpKind opKind, uint32_t localIndex, LValue value, WASMType type)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(opKind);
+ UNUSED_PARAM(localIndex);
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(type);
+ return UNUSED;
+ }
+
+ LValue buildSetGlobal(WASMOpKind opKind, uint32_t globalIndex, LValue value, WASMType type)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(opKind);
+ UNUSED_PARAM(globalIndex);
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(type);
+ return UNUSED;
+ }
+
+ void buildReturn(LValue value, WASMExpressionType returnType)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(returnType);
+ }
+
+ LValue buildImmediateI32(uint32_t immediate)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(immediate);
+ return UNUSED;
+ }
+
+ LValue buildImmediateF32(float immediate)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(immediate);
+ return UNUSED;
+ }
+
+ LValue buildImmediateF64(double immediate)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(immediate);
+ return UNUSED;
+ }
+
+ LValue buildGetLocal(uint32_t localIndex, WASMType type)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(localIndex);
+ UNUSED_PARAM(type);
+ return UNUSED;
+ }
+
+ LValue buildGetGlobal(uint32_t globalIndex, WASMType type)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(globalIndex);
+ UNUSED_PARAM(type);
+ return UNUSED;
+ }
+
+ LValue buildConvertType(LValue value, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion conversion)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(fromType);
+ UNUSED_PARAM(toType);
+ UNUSED_PARAM(conversion);
+ return UNUSED;
+ }
+
+ LValue buildLoad(const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessConversion conversion)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(memoryAddress);
+ UNUSED_PARAM(expressionType);
+ UNUSED_PARAM(memoryType);
+ UNUSED_PARAM(conversion);
+ return UNUSED;
+ }
+
+ LValue buildStore(WASMOpKind opKind, const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, LValue value)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(opKind);
+ UNUSED_PARAM(memoryAddress);
+ UNUSED_PARAM(expressionType);
+ UNUSED_PARAM(memoryType);
+ UNUSED_PARAM(value);
+ return UNUSED;
+ }
+
+ LValue buildUnaryI32(LValue value, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildUnaryF32(LValue value, WASMOpExpressionF32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildUnaryF64(LValue value, WASMOpExpressionF64 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildBinaryI32(LValue left, LValue right, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildBinaryF32(LValue left, LValue right, WASMOpExpressionF32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildBinaryF64(LValue left, LValue right, WASMOpExpressionF64 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildRelationalI32(LValue left, LValue right, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildRelationalF32(LValue left, LValue right, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildRelationalF64(LValue left, LValue right, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildMinOrMaxI32(LValue left, LValue right, WASMOpExpressionI32 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildMinOrMaxF64(LValue left, LValue right, WASMOpExpressionF64 op)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(left);
+ UNUSED_PARAM(right);
+ UNUSED_PARAM(op);
+ return UNUSED;
+ }
+
+ LValue buildCallInternal(uint32_t functionIndex, const Vector<LValue>& argumentList, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(functionIndex);
+ UNUSED_PARAM(argumentList);
+ UNUSED_PARAM(signature);
+ UNUSED_PARAM(returnType);
+ return UNUSED;
+ }
+
+ LValue buildCallIndirect(uint32_t functionPointerTableIndex, LValue index, const Vector<LValue>& argumentList, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(functionPointerTableIndex);
+ UNUSED_PARAM(index);
+ UNUSED_PARAM(argumentList);
+ UNUSED_PARAM(signature);
+ UNUSED_PARAM(returnType);
+ return UNUSED;
+ }
+
+ LValue buildCallImport(uint32_t functionImportIndex, const Vector<LValue>& argumentList, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(functionImportIndex);
+ UNUSED_PARAM(argumentList);
+ UNUSED_PARAM(signature);
+ UNUSED_PARAM(returnType);
+ return UNUSED;
+ }
+
+ void appendExpressionList(Vector<LValue>& expressionList, LValue value)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(expressionList);
+ UNUSED_PARAM(value);
+ }
+
+ void discard(LValue)
+ {
+ }
+
+ void linkTarget(LBasicBlock target)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(target);
+ }
+
+ void jumpToTarget(LBasicBlock target)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(target);
+ }
+
+ void jumpToTargetIf(JumpCondition, LValue value, LBasicBlock target)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(target);
+ }
+
+ void startLoop()
+ {
+ // FIXME: Implement this method.
+ }
+
+ void endLoop()
+ {
+ // FIXME: Implement this method.
+ }
+
+ void startSwitch()
+ {
+ // FIXME: Implement this method.
+ }
+
+ void endSwitch()
+ {
+ // FIXME: Implement this method.
+ }
+
+ void startLabel()
+ {
+ // FIXME: Implement this method.
+ }
+
+ void endLabel()
+ {
+ // FIXME: Implement this method.
+ }
+
+ LBasicBlock breakTarget()
+ {
+ // FIXME: Implement this method.
+ return UNUSED;
+ }
+
+ LBasicBlock continueTarget()
+ {
+ // FIXME: Implement this method.
+ return UNUSED;
+ }
+
+ LBasicBlock breakLabelTarget(uint32_t labelIndex)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(labelIndex);
+ return UNUSED;
+ }
+
+ LBasicBlock continueLabelTarget(uint32_t labelIndex)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(labelIndex);
+ return UNUSED;
+ }
+
+ void buildSwitch(LValue value, const Vector<int64_t>& cases, const Vector<LBasicBlock>& targets, LBasicBlock defaultTarget)
+ {
+ // FIXME: Implement this method.
+ UNUSED_PARAM(value);
+ UNUSED_PARAM(cases);
+ UNUSED_PARAM(targets);
+ UNUSED_PARAM(defaultTarget);
+ }
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFunctionB3IRGenerator_h
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h b/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
new file mode 100644
index 000000000..de439ba07
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
@@ -0,0 +1,1541 @@
+/*
+ * 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 "BinarySwitch.h"
+#include "CCallHelpers.h"
+#include "JIT.h"
+#include "JITOperations.h"
+#include "JSArrayBuffer.h"
+#include "LinkBuffer.h"
+#include "MaxFrameExtentForSlowPathCall.h"
+
+#define UNUSED 0
+
+namespace JSC {
+
+static int32_t JIT_OPERATION operationConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
+{
+ return JSValue::decode(value).toInt32(exec);
+}
+
+static double JIT_OPERATION operationConvertJSValueToDouble(ExecState* exec, EncodedJSValue value)
+{
+ return JSValue::decode(value).toNumber(exec);
+}
+
+#if !CPU(X86) && !CPU(X86_64)
+static int32_t JIT_OPERATION operationDiv(int32_t left, int32_t right)
+{
+ return left / right;
+}
+
+static int32_t JIT_OPERATION operationMod(int32_t left, int32_t right)
+{
+ return left % right;
+}
+
+static uint32_t JIT_OPERATION operationUnsignedDiv(uint32_t left, uint32_t right)
+{
+ return left / right;
+}
+
+static uint32_t JIT_OPERATION operationUnsignedMod(uint32_t left, uint32_t right)
+{
+ return left % right;
+}
+#endif
+
+#if !USE(JSVALUE64)
+static double JIT_OPERATION operationConvertUnsignedInt32ToDouble(uint32_t value)
+{
+ return static_cast<double>(value);
+}
+#endif
+
+static size_t sizeOfMemoryType(WASMMemoryType memoryType)
+{
+ switch (memoryType) {
+ case WASMMemoryType::I8:
+ return 1;
+ case WASMMemoryType::I16:
+ return 2;
+ case WASMMemoryType::I32:
+ case WASMMemoryType::F32:
+ return 4;
+ case WASMMemoryType::F64:
+ return 8;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+class WASMFunctionCompiler : private CCallHelpers {
+public:
+ typedef int Expression;
+ typedef int Statement;
+ typedef int ExpressionList;
+ struct MemoryAddress {
+ MemoryAddress(void*) { }
+ MemoryAddress(int, uint32_t offset)
+ : offset(offset)
+ {
+ }
+ uint32_t offset;
+ };
+ struct JumpTarget {
+ Label label;
+ JumpList jumpList;
+ };
+ enum class JumpCondition { Zero, NonZero };
+
+ WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, unsigned stackHeight)
+ : CCallHelpers(&vm, codeBlock)
+ , m_module(module)
+ , m_stackHeight(stackHeight)
+ {
+ }
+
+ void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
+ {
+ m_calleeSaveSpace = WTF::roundUpToMultipleOf(sizeof(StackSlot), RegisterSet::webAssemblyCalleeSaveRegisters().numberOfSetRegisters() * sizeof(void*));
+ m_codeBlock->setCalleeSaveRegisters(RegisterSet::webAssemblyCalleeSaveRegisters());
+
+ emitFunctionPrologue();
+ emitPutToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
+
+ m_beginLabel = label();
+
+ addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1);
+ m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
+
+ move(GPRInfo::regT1, stackPointerRegister);
+ checkStackPointerAlignment();
+
+ emitSaveCalleeSaves();
+ emitMaterializeTagCheckRegisters();
+
+ m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
+
+ unsigned localIndex = 0;
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ // FIXME: No need to do type conversion if the caller is a WebAssembly function.
+ // https://bugs.webkit.org/show_bug.cgi?id=149310
+ Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register));
+#if USE(JSVALUE64)
+ JSValueRegs valueRegs(GPRInfo::regT0);
+#else
+ JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
+#endif
+ loadValue(address, valueRegs);
+ switch (arguments[i]) {
+ case WASMType::I32:
+ convertValueToInt32(valueRegs, GPRInfo::regT0);
+ store32(GPRInfo::regT0, localAddress(localIndex++));
+ break;
+ case WASMType::F32:
+ case WASMType::F64:
+#if USE(JSVALUE64)
+ convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT1);
+#else
+ convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT2, FPRInfo::fpRegT1);
+#endif
+ if (arguments[i] == WASMType::F32)
+ convertDoubleToFloat(FPRInfo::fpRegT0, 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) {
+#if USE(JSVALUE64)
+ store64(TrustedImm64(0), localAddress(localIndex++));
+#else
+ store32(TrustedImm32(0), localAddress(localIndex));
+ store32(TrustedImm32(0), localAddress(localIndex).withOffset(4));
+ localIndex++;
+#endif
+ }
+
+ m_codeBlock->setNumParameters(1 + arguments.size());
+ }
+
+ void endFunction()
+ {
+ ASSERT(!m_tempStackTop);
+
+ // FIXME: Remove these if the last statement is a return statement.
+#if USE(JSVALUE64)
+ JSValueRegs returnValueRegs(GPRInfo::returnValueGPR);
+#else
+ JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
+#endif
+ moveTrustedValue(jsUndefined(), returnValueRegs);
+ emitRestoreCalleeSaves();
+ emitFunctionEpilogue();
+ ret();
+
+ m_stackOverflow.link(this);
+ if (maxFrameExtentForSlowPathCall)
+ addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
+ setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));
+ appendCallWithExceptionCheck(operationThrowStackOverflowError);
+
+ // FIXME: Implement arity check.
+ Label arityCheck = label();
+ emitFunctionPrologue();
+ emitPutToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
+ jump(m_beginLabel);
+
+ if (!m_divideErrorJumpList.empty()) {
+ m_divideErrorJumpList.link(this);
+
+ setupArgumentsExecState();
+ appendCallWithExceptionCheck(operationThrowDivideError);
+ }
+
+ if (!m_outOfBoundsErrorJumpList.empty()) {
+ m_outOfBoundsErrorJumpList.link(this);
+
+ setupArgumentsExecState();
+ appendCallWithExceptionCheck(operationThrowOutOfBoundsAccessError);
+ }
+
+ if (!m_exceptionChecks.empty()) {
+ m_exceptionChecks.link(this);
+
+ copyCalleeSavesToVMCalleeSavesBuffer();
+
+ // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*).
+ move(TrustedImmPtr(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();
+ }
+
+ LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed);
+
+ for (const auto& iterator : m_calls)
+ patchBuffer.link(iterator.first, FunctionPtr(iterator.second));
+
+ for (size_t i = 0; i < m_callCompilationInfo.size(); ++i) {
+ CallCompilationInfo& compilationInfo = m_callCompilationInfo[i];
+ CallLinkInfo& info = *compilationInfo.callLinkInfo;
+ info.setCallLocations(patchBuffer.locationOfNearCall(compilationInfo.callReturnLocation),
+ patchBuffer.locationOf(compilationInfo.hotPathBegin),
+ patchBuffer.locationOfNearCall(compilationInfo.hotPathOther));
+ }
+
+ 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();
+ }
+
+ int buildSetLocal(WASMOpKind opKind, uint32_t localIndex, int, WASMType type)
+ {
+ switch (type) {
+ case WASMType::I32:
+ case WASMType::F32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ store32(GPRInfo::regT0, localAddress(localIndex));
+ break;
+ case WASMType::F64:
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, localAddress(localIndex));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ if (opKind == WASMOpKind::Statement)
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildSetGlobal(WASMOpKind opKind, uint32_t globalIndex, int, WASMType type)
+ {
+ move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0);
+ switch (type) {
+ case WASMType::I32:
+ case WASMType::F32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ store32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMType::F64:
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ if (opKind == WASMOpKind::Statement)
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ void buildReturn(int, WASMExpressionType returnType)
+ {
+#if USE(JSVALUE64)
+ JSValueRegs returnValueRegs(GPRInfo::returnValueGPR);
+#else
+ JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
+#endif
+ switch (returnType) {
+ case WASMExpressionType::I32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::returnValueGPR);
+#if USE(JSVALUE64)
+ or64(GPRInfo::tagTypeNumberRegister, GPRInfo::returnValueGPR);
+#else
+ move(TrustedImm32(JSValue::Int32Tag), GPRInfo::returnValueGPR2);
+#endif
+ m_tempStackTop--;
+ break;
+ case WASMExpressionType::F32:
+ case WASMExpressionType::F64:
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ if (returnType == WASMExpressionType::F32)
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ convertDoubleToValue(FPRInfo::fpRegT0, returnValueRegs);
+ m_tempStackTop--;
+ break;
+ case WASMExpressionType::Void:
+ moveTrustedValue(jsUndefined(), returnValueRegs);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ emitRestoreCalleeSaves();
+ emitFunctionEpilogue();
+ ret();
+ }
+
+ int buildImmediateI32(uint32_t immediate)
+ {
+ store32(Imm32(immediate), temporaryAddress(m_tempStackTop++));
+ return UNUSED;
+ }
+
+ int buildImmediateF32(float immediate)
+ {
+ store32(Imm32(bitwise_cast<int32_t>(immediate)), temporaryAddress(m_tempStackTop++));
+ return UNUSED;
+ }
+
+ int buildImmediateF64(double immediate)
+ {
+#if USE(JSVALUE64)
+ store64(Imm64(bitwise_cast<int64_t>(immediate)), temporaryAddress(m_tempStackTop++));
+#else
+ union {
+ double doubleValue;
+ int32_t int32Values[2];
+ } u = { immediate };
+ m_tempStackTop++;
+ store32(Imm32(u.int32Values[0]), temporaryAddress(m_tempStackTop - 1));
+ store32(Imm32(u.int32Values[1]), temporaryAddress(m_tempStackTop - 1).withOffset(4));
+#endif
+ return UNUSED;
+ }
+
+ int buildGetLocal(uint32_t localIndex, WASMType type)
+ {
+ switch (type) {
+ case WASMType::I32:
+ case WASMType::F32:
+ load32(localAddress(localIndex), GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
+ break;
+ case WASMType::F64:
+ loadDouble(localAddress(localIndex), FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return UNUSED;
+ }
+
+ int buildGetGlobal(uint32_t globalIndex, WASMType type)
+ {
+ move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0);
+ switch (type) {
+ case WASMType::I32:
+ case WASMType::F32:
+ load32(GPRInfo::regT0, GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
+ break;
+ case WASMType::F64:
+ loadDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return UNUSED;
+ }
+
+ int buildConvertType(int, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion conversion)
+ {
+ switch (fromType) {
+ case WASMExpressionType::I32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ ASSERT(toType == WASMExpressionType::F32 || toType == WASMExpressionType::F64);
+ if (conversion == WASMTypeConversion::ConvertSigned)
+ convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
+ else {
+ ASSERT(conversion == WASMTypeConversion::ConvertUnsigned);
+#if USE(JSVALUE64)
+ convertInt64ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
+#else
+ callOperation(operationConvertUnsignedInt32ToDouble, GPRInfo::regT0, FPRInfo::fpRegT0);
+#endif
+ }
+ if (toType == WASMExpressionType::F32)
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ case WASMExpressionType::F32:
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ switch (toType) {
+ case WASMExpressionType::I32:
+ ASSERT(conversion == WASMTypeConversion::ConvertSigned);
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ case WASMExpressionType::F64:
+ ASSERT(conversion == WASMTypeConversion::Promote);
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case WASMExpressionType::F64:
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ switch (toType) {
+ case WASMExpressionType::I32:
+ ASSERT(conversion == WASMTypeConversion::ConvertSigned);
+ truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ case WASMExpressionType::F32:
+ ASSERT(conversion == WASMTypeConversion::Demote);
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return UNUSED;
+ }
+
+ int buildLoad(const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessConversion conversion)
+ {
+ const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl();
+ move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ if (memoryAddress.offset)
+ add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1);
+ and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1);
+
+ ASSERT(arrayBuffer->byteLength() < (unsigned)(1 << 31));
+ if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType))
+ m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType))));
+ else
+ m_outOfBoundsErrorJumpList.append(jump());
+
+ BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne);
+
+ switch (expressionType) {
+ case WASMExpressionType::I32:
+ switch (memoryType) {
+ case WASMMemoryType::I8:
+ if (conversion == MemoryAccessConversion::SignExtend)
+ load8SignedExtendTo32(address, GPRInfo::regT0);
+ else {
+ ASSERT(conversion == MemoryAccessConversion::ZeroExtend);
+ load8(address, GPRInfo::regT0);
+ }
+ break;
+ case WASMMemoryType::I16:
+ if (conversion == MemoryAccessConversion::SignExtend)
+ load16SignedExtendTo32(address, GPRInfo::regT0);
+ else {
+ ASSERT(conversion == MemoryAccessConversion::ZeroExtend);
+ load16(address, GPRInfo::regT0);
+ }
+ break;
+ case WASMMemoryType::I32:
+ load32(address, GPRInfo::regT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ case WASMExpressionType::F32:
+ ASSERT(memoryType == WASMMemoryType::F32 && conversion == MemoryAccessConversion::NoConversion);
+ load32(address, GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ case WASMExpressionType::F64:
+ ASSERT(memoryType == WASMMemoryType::F64 && conversion == MemoryAccessConversion::NoConversion);
+ loadDouble(address, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return UNUSED;
+ }
+
+ int buildStore(WASMOpKind opKind, const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, int)
+ {
+ const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl();
+ move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT1);
+ if (memoryAddress.offset)
+ add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1);
+ and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1);
+
+ ASSERT(arrayBuffer->byteLength() < (1u << 31));
+ if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType))
+ m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType))));
+ else
+ m_outOfBoundsErrorJumpList.append(jump());
+
+ BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne);
+
+ switch (expressionType) {
+ case WASMExpressionType::I32:
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2);
+ switch (memoryType) {
+ case WASMMemoryType::I8:
+ store8(GPRInfo::regT2, address);
+ break;
+ case WASMMemoryType::I16:
+ store16(GPRInfo::regT2, address);
+ break;
+ case WASMMemoryType::I32:
+ store32(GPRInfo::regT2, address);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ break;
+ case WASMExpressionType::F32:
+ ASSERT(memoryType == WASMMemoryType::F32);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2);
+ store32(GPRInfo::regT2, address);
+ break;
+ case WASMExpressionType::F64:
+ ASSERT(memoryType == WASMMemoryType::F64);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, address);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop -= 2;
+
+ if (opKind == WASMOpKind::Expression) {
+ switch (expressionType) {
+ case WASMExpressionType::I32:
+ case WASMExpressionType::F32:
+ store32(GPRInfo::regT2, temporaryAddress(m_tempStackTop++));
+ break;
+ case WASMExpressionType::F64:
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ return UNUSED;
+ }
+
+ int buildUnaryI32(int, WASMOpExpressionI32 op)
+ {
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ switch (op) {
+ case WASMOpExpressionI32::Negate:
+ neg32(GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::BitNot:
+ xor32(TrustedImm32(-1), GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::CountLeadingZeros:
+ countLeadingZeros32(GPRInfo::regT0, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::LogicalNot: {
+ // FIXME: Don't use branches.
+ Jump zero = branchTest32(Zero, GPRInfo::regT0);
+ move(TrustedImm32(0), GPRInfo::regT0);
+ Jump end = jump();
+ zero.link(this);
+ move(TrustedImm32(1), GPRInfo::regT0);
+ end.link(this);
+ break;
+ }
+ case WASMOpExpressionI32::Abs: {
+ // FIXME: Don't use branches.
+ Jump end = branchTest32(PositiveOrZero, GPRInfo::regT0);
+ neg32(GPRInfo::regT0);
+ end.link(this);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildUnaryF32(int, WASMOpExpressionF32 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ switch (op) {
+ case WASMOpExpressionF32::Negate:
+ convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+ negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Abs:
+ convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+ absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Ceil:
+ callOperation(ceilf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Floor:
+ callOperation(floorf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Sqrt:
+ convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+ sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildUnaryF64(int, WASMOpExpressionF64 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ switch (op) {
+ case WASMOpExpressionF64::Negate:
+ negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Abs:
+ absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Sqrt:
+ sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Ceil:
+ case WASMOpExpressionF64::Floor:
+ case WASMOpExpressionF64::Cos:
+ case WASMOpExpressionF64::Sin:
+ case WASMOpExpressionF64::Tan:
+ case WASMOpExpressionF64::ACos:
+ case WASMOpExpressionF64::ASin:
+ case WASMOpExpressionF64::ATan:
+ case WASMOpExpressionF64::Exp:
+ case WASMOpExpressionF64::Ln:
+ D_JITOperation_D operation;
+ switch (op) {
+ case WASMOpExpressionF64::Ceil:
+ operation = ceil;
+ break;
+ case WASMOpExpressionF64::Floor:
+ operation = floor;
+ break;
+ case WASMOpExpressionF64::Cos:
+ operation = cos;
+ break;
+ case WASMOpExpressionF64::Sin:
+ operation = sin;
+ break;
+ case WASMOpExpressionF64::Tan:
+ operation = tan;
+ break;
+ case WASMOpExpressionF64::ACos:
+ operation = acos;
+ break;
+ case WASMOpExpressionF64::ASin:
+ operation = asin;
+ break;
+ case WASMOpExpressionF64::ATan:
+ operation = atan;
+ break;
+ case WASMOpExpressionF64::Exp:
+ operation = exp;
+ break;
+ case WASMOpExpressionF64::Ln:
+ operation = log;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ callOperation(operation, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildBinaryI32(int, int, WASMOpExpressionI32 op)
+ {
+ load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ switch (op) {
+ case WASMOpExpressionI32::Add:
+ add32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::Sub:
+ sub32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::Mul:
+ mul32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::SDiv:
+ case WASMOpExpressionI32::UDiv:
+ case WASMOpExpressionI32::SMod:
+ case WASMOpExpressionI32::UMod: {
+ m_divideErrorJumpList.append(branchTest32(Zero, GPRInfo::regT1));
+ if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
+ Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1));
+ m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1)));
+ denominatorNotNeg1.link(this);
+ }
+#if CPU(X86) || CPU(X86_64)
+ ASSERT(GPRInfo::regT0 == X86Registers::eax);
+ move(GPRInfo::regT1, X86Registers::ecx);
+ if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
+ x86ConvertToDoubleWord32();
+ x86Div32(X86Registers::ecx);
+ } else {
+ ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod);
+ xor32(X86Registers::edx, X86Registers::edx);
+ m_assembler.divl_r(X86Registers::ecx);
+ }
+ if (op == WASMOpExpressionI32::SMod || op == WASMOpExpressionI32::UMod)
+ move(X86Registers::edx, GPRInfo::regT0);
+#else
+ // FIXME: We should be able to do an inline div on ARMv7 and ARM64.
+ switch (op) {
+ case WASMOpExpressionI32::SDiv:
+ callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::UDiv:
+ callOperation(operationUnsignedDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::SMod:
+ callOperation(operationMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::UMod:
+ callOperation(operationUnsignedMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+#endif
+ break;
+ }
+ case WASMOpExpressionI32::BitOr:
+ or32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::BitAnd:
+ and32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::BitXor:
+ xor32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::LeftShift:
+ lshift32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::ArithmeticRightShift:
+ rshift32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ case WASMOpExpressionI32::LogicalRightShift:
+ urshift32(GPRInfo::regT1, GPRInfo::regT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop--;
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildBinaryF32(int, int, WASMOpExpressionF32 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+ switch (op) {
+ case WASMOpExpressionF32::Add:
+ addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Sub:
+ subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Mul:
+ mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF32::Div:
+ divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ m_tempStackTop--;
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildBinaryF64(int, int, WASMOpExpressionF64 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ switch (op) {
+ case WASMOpExpressionF64::Add:
+ addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Sub:
+ subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Mul:
+ mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Div:
+ divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ case WASMOpExpressionF64::Mod:
+ case WASMOpExpressionF64::ATan2:
+ case WASMOpExpressionF64::Pow:
+ D_JITOperation_DD operation;
+ switch (op) {
+ case WASMOpExpressionF64::Mod:
+ operation = fmod;
+ break;
+ case WASMOpExpressionF64::ATan2:
+ operation = atan2;
+ break;
+ case WASMOpExpressionF64::Pow:
+ operation = pow;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ callOperation(operation, FPRInfo::fpRegT0, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop--;
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildRelationalI32(int, int, WASMOpExpressionI32 op)
+ {
+ load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ RelationalCondition condition;
+ switch (op) {
+ case WASMOpExpressionI32::EqualI32:
+ condition = Equal;
+ break;
+ case WASMOpExpressionI32::NotEqualI32:
+ condition = NotEqual;
+ break;
+ case WASMOpExpressionI32::SLessThanI32:
+ condition = LessThan;
+ break;
+ case WASMOpExpressionI32::ULessThanI32:
+ condition = Below;
+ break;
+ case WASMOpExpressionI32::SLessThanOrEqualI32:
+ condition = LessThanOrEqual;
+ break;
+ case WASMOpExpressionI32::ULessThanOrEqualI32:
+ condition = BelowOrEqual;
+ break;
+ case WASMOpExpressionI32::SGreaterThanI32:
+ condition = GreaterThan;
+ break;
+ case WASMOpExpressionI32::UGreaterThanI32:
+ condition = Above;
+ break;
+ case WASMOpExpressionI32::SGreaterThanOrEqualI32:
+ condition = GreaterThanOrEqual;
+ break;
+ case WASMOpExpressionI32::UGreaterThanOrEqualI32:
+ condition = AboveOrEqual;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ compare32(condition, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
+ m_tempStackTop--;
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
+ return UNUSED;
+ }
+
+ int buildRelationalF32(int, int, WASMOpExpressionI32 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+ DoubleCondition condition;
+ switch (op) {
+ case WASMOpExpressionI32::EqualF32:
+ condition = DoubleEqual;
+ break;
+ case WASMOpExpressionI32::NotEqualF32:
+ condition = DoubleNotEqual;
+ break;
+ case WASMOpExpressionI32::LessThanF32:
+ condition = DoubleLessThan;
+ break;
+ case WASMOpExpressionI32::LessThanOrEqualF32:
+ condition = DoubleLessThanOrEqual;
+ break;
+ case WASMOpExpressionI32::GreaterThanF32:
+ condition = DoubleGreaterThan;
+ break;
+ case WASMOpExpressionI32::GreaterThanOrEqualF32:
+ condition = DoubleGreaterThanOrEqual;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop--;
+ Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
+ store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1));
+ Jump end = jump();
+ trueCase.link(this);
+ store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1));
+ end.link(this);
+ return UNUSED;
+ }
+
+ int buildRelationalF64(int, int, WASMOpExpressionI32 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ DoubleCondition condition;
+ switch (op) {
+ case WASMOpExpressionI32::EqualF64:
+ condition = DoubleEqual;
+ break;
+ case WASMOpExpressionI32::NotEqualF64:
+ condition = DoubleNotEqual;
+ break;
+ case WASMOpExpressionI32::LessThanF64:
+ condition = DoubleLessThan;
+ break;
+ case WASMOpExpressionI32::LessThanOrEqualF64:
+ condition = DoubleLessThanOrEqual;
+ break;
+ case WASMOpExpressionI32::GreaterThanF64:
+ condition = DoubleGreaterThan;
+ break;
+ case WASMOpExpressionI32::GreaterThanOrEqualF64:
+ condition = DoubleGreaterThanOrEqual;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ m_tempStackTop--;
+ Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
+ store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1));
+ Jump end = jump();
+ trueCase.link(this);
+ store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1));
+ end.link(this);
+ return UNUSED;
+ }
+
+ int buildMinOrMaxI32(int, int, WASMOpExpressionI32 op)
+ {
+ load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ RelationalCondition condition;
+ switch (op) {
+ case WASMOpExpressionI32::SMin:
+ condition = LessThanOrEqual;
+ break;
+ case WASMOpExpressionI32::UMin:
+ condition = BelowOrEqual;
+ break;
+ case WASMOpExpressionI32::SMax:
+ condition = GreaterThanOrEqual;
+ break;
+ case WASMOpExpressionI32::UMax:
+ condition = AboveOrEqual;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ Jump useLeft = branch32(condition, GPRInfo::regT0, GPRInfo::regT1);
+ store32(GPRInfo::regT1, temporaryAddress(m_tempStackTop - 2));
+ useLeft.link(this);
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildMinOrMaxF64(int, int, WASMOpExpressionF64 op)
+ {
+ loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+ loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+ DoubleCondition condition;
+ switch (op) {
+ case WASMOpExpressionF64::Min:
+ condition = DoubleLessThanOrEqual;
+ break;
+ case WASMOpExpressionF64::Max:
+ condition = DoubleGreaterThanOrEqual;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ Jump useLeft = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
+ storeDouble(FPRInfo::fpRegT1, temporaryAddress(m_tempStackTop - 2));
+ useLeft.link(this);
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildCallInternal(uint32_t functionIndex, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ boxArgumentsAndAdjustStackPointer(signature.arguments);
+
+ JSFunction* function = m_module->functions()[functionIndex].get();
+ move(TrustedImmPtr(function), GPRInfo::regT0);
+
+ callAndUnboxResult(returnType);
+ return UNUSED;
+ }
+
+ int buildCallIndirect(uint32_t functionPointerTableIndex, int, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ boxArgumentsAndAdjustStackPointer(signature.arguments);
+
+ const Vector<JSFunction*>& functions = m_module->functionPointerTables()[functionPointerTableIndex].functions;
+ move(TrustedImmPtr(functions.data()), GPRInfo::regT0);
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
+ m_tempStackTop--;
+ and32(TrustedImm32(functions.size() - 1), GPRInfo::regT1);
+ loadPtr(BaseIndex(GPRInfo::regT0, GPRInfo::regT1, timesPtr()), GPRInfo::regT0);
+
+ callAndUnboxResult(returnType);
+ return UNUSED;
+ }
+
+ int buildCallImport(uint32_t functionImportIndex, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ boxArgumentsAndAdjustStackPointer(signature.arguments);
+
+ JSFunction* function = m_module->importedFunctions()[functionImportIndex].get();
+ move(TrustedImmPtr(function), GPRInfo::regT0);
+
+ callAndUnboxResult(returnType);
+ return UNUSED;
+ }
+
+ void appendExpressionList(int&, int) { }
+
+ void discard(int)
+ {
+ m_tempStackTop--;
+ }
+
+ void linkTarget(JumpTarget& target)
+ {
+ target.label = label();
+ target.jumpList.link(this);
+ }
+
+ void jumpToTarget(JumpTarget& target)
+ {
+ if (target.label.isSet())
+ jump(target.label);
+ else
+ target.jumpList.append(jump());
+ }
+
+ void jumpToTargetIf(JumpCondition condition, int, JumpTarget& target)
+ {
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ m_tempStackTop--;
+ Jump taken = branchTest32((condition == JumpCondition::Zero) ? Zero : NonZero, GPRInfo::regT0);
+ if (target.label.isSet())
+ taken.linkTo(target.label, this);
+ else
+ target.jumpList.append(taken);
+ }
+
+ void startLoop()
+ {
+ m_breakTargets.append(JumpTarget());
+ m_continueTargets.append(JumpTarget());
+ }
+
+ void endLoop()
+ {
+ m_breakTargets.removeLast();
+ m_continueTargets.removeLast();
+ }
+
+ void startSwitch()
+ {
+ m_breakTargets.append(JumpTarget());
+ }
+
+ void endSwitch()
+ {
+ m_breakTargets.removeLast();
+ }
+
+ void startLabel()
+ {
+ m_breakLabelTargets.append(JumpTarget());
+ m_continueLabelTargets.append(JumpTarget());
+
+ linkTarget(m_continueLabelTargets.last());
+ }
+
+ void endLabel()
+ {
+ linkTarget(m_breakLabelTargets.last());
+
+ m_breakLabelTargets.removeLast();
+ m_continueLabelTargets.removeLast();
+ }
+
+ JumpTarget& breakTarget()
+ {
+ return m_breakTargets.last();
+ }
+
+ JumpTarget& continueTarget()
+ {
+ return m_continueTargets.last();
+ }
+
+ JumpTarget& breakLabelTarget(uint32_t labelIndex)
+ {
+ return m_breakLabelTargets[labelIndex];
+ }
+
+ JumpTarget& continueLabelTarget(uint32_t labelIndex)
+ {
+ return m_continueLabelTargets[labelIndex];
+ }
+
+ void buildSwitch(int, const Vector<int64_t>& cases, Vector<JumpTarget>& targets, JumpTarget defaultTarget)
+ {
+ load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
+ m_tempStackTop--;
+ BinarySwitch binarySwitch(GPRInfo::regT0, cases, BinarySwitch::Int32);
+ while (binarySwitch.advance(*this)) {
+ unsigned index = binarySwitch.caseIndex();
+ jump(targets[index].label);
+ }
+ binarySwitch.fallThrough().linkTo(defaultTarget.label, this);
+ }
+
+private:
+ union StackSlot {
+ int32_t intValue;
+ float floatValue;
+ double doubleValue;
+ };
+
+ enum class FloatingPointPrecision { Single, Double };
+
+ Address localAddress(unsigned localIndex) const
+ {
+ ASSERT(localIndex < m_numberOfLocals);
+ return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (localIndex + 1) * sizeof(StackSlot));
+ }
+
+ Address temporaryAddress(unsigned temporaryIndex) const
+ {
+ ASSERT(m_numberOfLocals + temporaryIndex < m_stackHeight);
+ return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot));
+ }
+
+ void appendCall(const FunctionPtr& function)
+ {
+ m_calls.append(std::make_pair(call(), function.value()));
+ }
+
+ void appendCallWithExceptionCheck(const FunctionPtr& function)
+ {
+ appendCall(function);
+ m_exceptionChecks.append(emitExceptionCheck());
+ }
+
+ Call emitNakedCall(CodePtr function)
+ {
+ Call nakedCall = nearCall();
+ m_calls.append(std::make_pair(nakedCall, function.executableAddress()));
+ return nakedCall;
+ }
+
+ void appendCallSetResult(const FunctionPtr& function, GPRReg result)
+ {
+ appendCall(function);
+ move(GPRInfo::returnValueGPR, result);
+ }
+
+#if CPU(X86)
+ void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision precision)
+ {
+ appendCall(function);
+ switch (precision) {
+ case FloatingPointPrecision::Single:
+ m_assembler.fstps(0, stackPointerRegister);
+ break;
+ case FloatingPointPrecision::Double:
+ m_assembler.fstpl(0, stackPointerRegister);
+ break;
+ }
+ loadDouble(stackPointerRegister, result);
+ }
+#elif CPU(ARM) && !CPU(ARM_HARDFP)
+ void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision)
+ {
+ appendCall(function);
+ m_assembler.vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
+ }
+#else // CPU(X86_64) || (CPU(ARM) && CPU(ARM_HARDFP)) || CPU(ARM64) || CPU(MIPS) || CPU(SH4)
+ void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision)
+ {
+ appendCall(function);
+ moveDouble(FPRInfo::returnValueFPR, result);
+ }
+#endif
+
+#if USE(JSVALUE64)
+ void callOperation(Z_JITOperation_EJ operation, GPRReg src, GPRReg dst)
+ {
+ setupArgumentsWithExecState(src);
+ appendCallSetResult(operation, dst);
+ }
+
+ void callOperation(D_JITOperation_EJ operation, GPRReg src, FPRReg dst)
+ {
+ setupArgumentsWithExecState(src);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
+ }
+#else
+// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned on an even-numbered register (r0, r2 or [sp]).
+// To prevent the assembler from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
+#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
+#define EABI_32BIT_DUMMY_ARG TrustedImm32(0),
+#else
+#define EABI_32BIT_DUMMY_ARG
+#endif
+
+ void callOperation(Z_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, GPRReg dst)
+ {
+ setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag);
+ appendCallSetResult(operation, dst);
+ }
+
+ void callOperation(D_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, FPRReg dst)
+ {
+ setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
+ }
+#endif
+
+ void callOperation(float JIT_OPERATION (*operation)(float), FPRegisterID src, FPRegisterID dst)
+ {
+ setupArguments(src);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Single);
+ }
+
+ void callOperation(D_JITOperation_D operation, FPRegisterID src, FPRegisterID dst)
+ {
+ setupArguments(src);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
+ }
+
+ void callOperation(int32_t JIT_OPERATION (*operation)(int32_t, int32_t), GPRReg src1, GPRReg src2, GPRReg dst)
+ {
+ setupArguments(src1, src2);
+ appendCallSetResult(operation, dst);
+ }
+
+ void callOperation(uint32_t JIT_OPERATION (*operation)(uint32_t, uint32_t), GPRReg src1, GPRReg src2, GPRReg dst)
+ {
+ setupArguments(src1, src2);
+ appendCallSetResult(operation, dst);
+ }
+
+ void callOperation(D_JITOperation_DD operation, FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ setupArguments(src1, src2);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
+ }
+
+ void callOperation(double JIT_OPERATION (*operation)(uint32_t), GPRReg src, FPRegisterID dst)
+ {
+ setupArguments(src);
+ appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
+ }
+
+ void boxArgumentsAndAdjustStackPointer(const Vector<WASMType>& arguments)
+ {
+ size_t argumentCount = arguments.size();
+ int stackOffset = -m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_numberOfLocals + m_tempStackTop + argumentCount + 1 + JSStack::CallFrameHeaderSize);
+
+ storeTrustedValue(jsUndefined(), Address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::thisArgumentOffset()) * sizeof(Register)));
+
+ for (size_t i = 0; i < argumentCount; ++i) {
+ Address address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::argumentOffset(i)) * sizeof(Register));
+#if USE(JSVALUE64)
+ JSValueRegs valueRegs(GPRInfo::regT0);
+#else
+ JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
+#endif
+ switch (arguments[i]) {
+ case WASMType::I32:
+ load32(temporaryAddress(m_tempStackTop - argumentCount + i), GPRInfo::regT0);
+#if USE(JSVALUE64)
+ or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
+ store64(GPRInfo::regT0, address);
+#else
+ store32(GPRInfo::regT0, address.withOffset(PayloadOffset));
+ store32(TrustedImm32(JSValue::Int32Tag), address.withOffset(TagOffset));
+#endif
+ break;
+ case WASMType::F32:
+ case WASMType::F64:
+ loadDouble(temporaryAddress(m_tempStackTop - argumentCount + i), FPRInfo::fpRegT0);
+ if (arguments[i] == WASMType::F32)
+ convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ convertDoubleToValue(FPRInfo::fpRegT0, valueRegs);
+ storeValue(valueRegs, address);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ m_tempStackTop -= argumentCount;
+
+ addPtr(TrustedImm32(stackOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), GPRInfo::callFrameRegister, stackPointerRegister);
+ store32(TrustedImm32(argumentCount + 1), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
+ }
+
+ void callAndUnboxResult(WASMExpressionType returnType)
+ {
+ // regT0 holds callee.
+#if USE(JSVALUE64)
+ store64(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC)));
+#else
+ store32(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
+ store32(TrustedImm32(JSValue::CellTag), Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC)));
+#endif
+
+ DataLabelPtr addressOfLinkedFunctionCheck;
+ Jump slowCase = branchPtrWithPatch(NotEqual, GPRInfo::regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
+
+ CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
+ info->setUpCall(CallLinkInfo::Call, CodeOrigin(), GPRInfo::regT0);
+ m_callCompilationInfo.append(CallCompilationInfo());
+ m_callCompilationInfo.last().hotPathBegin = addressOfLinkedFunctionCheck;
+ m_callCompilationInfo.last().callLinkInfo = info;
+ m_callCompilationInfo.last().hotPathOther = nearCall();
+ Jump end = jump();
+
+ slowCase.link(this);
+ move(TrustedImmPtr(info), GPRInfo::regT2);
+ m_callCompilationInfo.last().callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
+
+ end.link(this);
+ addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister);
+ checkStackPointerAlignment();
+
+ // FIXME: No need to do type conversion if the callee is a WebAssembly function.
+ // https://bugs.webkit.org/show_bug.cgi?id=149310
+#if USE(JSVALUE64)
+ JSValueRegs valueRegs(GPRInfo::returnValueGPR);
+#else
+ JSValueRegs valueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
+#endif
+ switch (returnType) {
+ case WASMExpressionType::I32:
+ convertValueToInt32(valueRegs, GPRInfo::regT0);
+ store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
+ break;
+ case WASMExpressionType::F32:
+ case WASMExpressionType::F64:
+#if USE(JSVALUE64)
+ convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR);
+#else
+ convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR, FPRInfo::fpRegT1);
+#endif
+ if (returnType == WASMExpressionType::F32)
+ convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+ storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
+ break;
+ case WASMExpressionType::Void:
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+#if USE(JSVALUE64)
+ void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
+ {
+ Jump checkJSInt32 = branchIfInt32(valueRegs);
+
+ callOperation(operationConvertJSValueToInt32, valueRegs.gpr(), valueRegs.gpr());
+
+ checkJSInt32.link(this);
+ move(valueRegs.gpr(), dst);
+ }
+
+ void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch)
+ {
+ Jump checkJSInt32 = branchIfInt32(valueRegs);
+ Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
+ JumpList end;
+
+ callOperation(operationConvertJSValueToDouble, valueRegs.gpr(), dst);
+ end.append(jump());
+
+ checkJSInt32.link(this);
+ convertInt32ToDouble(valueRegs.gpr(), dst);
+ end.append(jump());
+
+ checkJSNumber.link(this);
+ unboxDoubleWithoutAssertions(valueRegs.gpr(), dst);
+ end.link(this);
+ }
+#else
+ void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
+ {
+ Jump checkJSInt32 = branchIfInt32(valueRegs);
+
+ callOperation(operationConvertJSValueToInt32, valueRegs.tagGPR(), valueRegs.payloadGPR(), valueRegs.payloadGPR());
+
+ checkJSInt32.link(this);
+ move(valueRegs.payloadGPR(), dst);
+ }
+
+ void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch, FPRReg fpScratch)
+ {
+ Jump checkJSInt32 = branchIfInt32(valueRegs);
+ Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
+ JumpList end;
+
+ callOperation(operationConvertJSValueToDouble, valueRegs.tagGPR(), valueRegs.payloadGPR(), dst);
+ end.append(jump());
+
+ checkJSInt32.link(this);
+ convertInt32ToDouble(valueRegs.payloadGPR(), dst);
+ end.append(jump());
+
+ checkJSNumber.link(this);
+ unboxDouble(valueRegs.tagGPR(), valueRegs.payloadGPR(), dst, fpScratch);
+ end.link(this);
+ }
+#endif
+
+ void convertDoubleToValue(FPRReg fpr, JSValueRegs valueRegs)
+ {
+#if USE(JSVALUE64)
+ boxDouble(fpr, valueRegs.gpr());
+#else
+ boxDouble(fpr, valueRegs.tagGPR(), valueRegs.payloadGPR());
+#endif
+ }
+
+ JSWASMModule* m_module;
+ unsigned m_stackHeight;
+ unsigned m_numberOfLocals;
+ unsigned m_tempStackTop { 0 };
+ unsigned m_calleeSaveSpace;
+
+ Vector<JumpTarget> m_breakTargets;
+ Vector<JumpTarget> m_continueTargets;
+ Vector<JumpTarget> m_breakLabelTargets;
+ Vector<JumpTarget> m_continueLabelTargets;
+
+ Label m_beginLabel;
+ Jump m_stackOverflow;
+ JumpList m_divideErrorJumpList;
+ JumpList m_outOfBoundsErrorJumpList;
+ JumpList m_exceptionChecks;
+
+ Vector<std::pair<Call, void*>> m_calls;
+ Vector<CallCompilationInfo> m_callCompilationInfo;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFunctionCompiler_h
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp b/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
new file mode 100644
index 000000000..e65da5885
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
@@ -0,0 +1,1225 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WASMFunctionParser.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSCJSValueInlines.h"
+#include "JSWASMModule.h"
+#include "WASMFunctionCompiler.h"
+#include "WASMFunctionB3IRGenerator.h"
+#include "WASMFunctionSyntaxChecker.h"
+
+#define PROPAGATE_ERROR() do { if (!m_errorMessage.isNull()) return 0; } while (0)
+#define FAIL_WITH_MESSAGE(errorMessage) do { m_errorMessage = errorMessage; return 0; } while (0)
+#define READ_FLOAT_OR_FAIL(result, errorMessage) do { if (!m_reader.readFloat(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_DOUBLE_OR_FAIL(result, errorMessage) do { if (!m_reader.readDouble(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_COMPACT_INT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readCompactInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_COMPACT_UINT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readCompactUInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_EXPRESSION_TYPE_OR_FAIL(result, errorMessage) do { if (!m_reader.readExpressionType(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_OP_STATEMENT_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpStatement(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_OP_EXPRESSION_I32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpExpressionI32(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_OP_EXPRESSION_F32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpExpressionF32(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_OP_EXPRESSION_F64_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpExpressionF64(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_OP_EXPRESSION_VOID_OR_FAIL(op, errorMessage) do { if (!m_reader.readOpExpressionVoid(op)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_VARIABLE_TYPES_OR_FAIL(hasImmediate, variableTypes, variableTypesWithImmediate, immediate, errorMessage) do { if (!m_reader.readVariableTypes(hasImmediate, variableTypes, variableTypesWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_SWITCH_CASE_OR_FAIL(result, errorMessage) do { if (!m_reader.readSwitchCase(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define FAIL_IF_FALSE(condition, errorMessage) do { if (!(condition)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+
+#define UNUSED 0
+
+namespace JSC {
+
+static String nameOfType(WASMType type)
+{
+ switch (type) {
+ case WASMType::I32:
+ return "int32";
+ case WASMType::F32:
+ return "float32";
+ case WASMType::F64:
+ return "float64";
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}
+
+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;
+ parser.m_reader.setOffset(startOffsetInSource);
+ parser.parseFunction(syntaxChecker);
+ if (!parser.m_errorMessage.isNull()) {
+ errorMessage = parser.m_errorMessage;
+ return false;
+ }
+ endOffsetInSource = parser.m_reader.offset();
+ stackHeight = syntaxChecker.stackHeight();
+ return true;
+}
+
+void WASMFunctionParser::compile(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, const SourceCode& source, size_t functionIndex)
+{
+ WASMFunctionParser parser(module, source, functionIndex);
+ WASMFunctionCompiler compiler(vm, codeBlock, module, module->functionStackHeights()[functionIndex]);
+ parser.m_reader.setOffset(module->functionStartOffsetsInSource()[functionIndex]);
+ parser.parseFunction(compiler);
+ ASSERT(parser.m_errorMessage.isNull());
+}
+
+template <class Context>
+bool WASMFunctionParser::parseFunction(Context& context)
+{
+ const WASMSignature& signature = m_module->signatures()[m_module->functionDeclarations()[m_functionIndex].signatureIndex];
+
+ m_returnType = signature.returnType;
+
+ parseLocalVariables();
+ PROPAGATE_ERROR();
+
+ const Vector<WASMType>& arguments = signature.arguments;
+ for (size_t i = 0; i < arguments.size(); ++i)
+ m_localTypes.append(arguments[i]);
+ for (uint32_t i = 0; i < m_numberOfI32LocalVariables; ++i)
+ m_localTypes.append(WASMType::I32);
+ for (uint32_t i = 0; i < m_numberOfF32LocalVariables; ++i)
+ m_localTypes.append(WASMType::F32);
+ 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;
+}
+
+bool WASMFunctionParser::parseLocalVariables()
+{
+ m_numberOfI32LocalVariables = 0;
+ m_numberOfF32LocalVariables = 0;
+ m_numberOfF64LocalVariables = 0;
+
+ bool hasImmediate;
+ WASMVariableTypes variableTypes;
+ WASMVariableTypesWithImmediate variableTypesWithImmediate;
+ uint8_t immediate;
+ READ_VARIABLE_TYPES_OR_FAIL(hasImmediate, variableTypes, variableTypesWithImmediate, immediate, "Cannot read the types of local variables.");
+ if (!hasImmediate) {
+ if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::I32))
+ READ_COMPACT_UINT32_OR_FAIL(m_numberOfI32LocalVariables, "Cannot read the number of int32 local variables.");
+ if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::F32))
+ READ_COMPACT_UINT32_OR_FAIL(m_numberOfF32LocalVariables, "Cannot read the number of float32 local variables.");
+ if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::F64))
+ READ_COMPACT_UINT32_OR_FAIL(m_numberOfF64LocalVariables, "Cannot read the number of float64 local variables.");
+ } else
+ m_numberOfI32LocalVariables = immediate;
+ return true;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseStatement(Context& context)
+{
+ bool hasImmediate;
+ WASMOpStatement op;
+ WASMOpStatementWithImmediate opWithImmediate;
+ uint8_t immediate;
+ READ_OP_STATEMENT_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the statement opcode.");
+ if (!hasImmediate) {
+ switch (op) {
+ case WASMOpStatement::SetLocal:
+ parseSetLocal(context, WASMOpKind::Statement, WASMExpressionType::Void);
+ break;
+ case WASMOpStatement::SetGlobal:
+ parseSetGlobal(context, WASMOpKind::Statement, WASMExpressionType::Void);
+ break;
+ case WASMOpStatement::I32Store8:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset);
+ break;
+ case WASMOpStatement::I32StoreWithOffset8:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset);
+ break;
+ case WASMOpStatement::I32Store16:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset);
+ break;
+ case WASMOpStatement::I32StoreWithOffset16:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset);
+ break;
+ case WASMOpStatement::I32Store32:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::NoOffset);
+ break;
+ case WASMOpStatement::I32StoreWithOffset32:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::WithOffset);
+ break;
+ case WASMOpStatement::F32Store:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::NoOffset);
+ break;
+ case WASMOpStatement::F32StoreWithOffset:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::WithOffset);
+ break;
+ case WASMOpStatement::F64Store:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::NoOffset);
+ break;
+ case WASMOpStatement::F64StoreWithOffset:
+ parseStore(context, WASMOpKind::Statement, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::WithOffset);
+ break;
+ case WASMOpStatement::CallInternal:
+ parseCallInternal(context, WASMOpKind::Statement, WASMExpressionType::Void);
+ break;
+ case WASMOpStatement::CallIndirect:
+ parseCallIndirect(context, WASMOpKind::Statement, WASMExpressionType::Void);
+ break;
+ case WASMOpStatement::CallImport:
+ parseCallImport(context, WASMOpKind::Statement, WASMExpressionType::Void);
+ break;
+ case WASMOpStatement::Return:
+ parseReturnStatement(context);
+ break;
+ case WASMOpStatement::Block:
+ parseBlockStatement(context);
+ break;
+ case WASMOpStatement::If:
+ parseIfStatement(context);
+ break;
+ case WASMOpStatement::IfElse:
+ parseIfElseStatement(context);
+ break;
+ case WASMOpStatement::While:
+ parseWhileStatement(context);
+ break;
+ case WASMOpStatement::Do:
+ parseDoStatement(context);
+ break;
+ case WASMOpStatement::Label:
+ parseLabelStatement(context);
+ break;
+ case WASMOpStatement::Break:
+ parseBreakStatement(context);
+ break;
+ case WASMOpStatement::BreakLabel:
+ parseBreakLabelStatement(context);
+ break;
+ case WASMOpStatement::Continue:
+ parseContinueStatement(context);
+ break;
+ case WASMOpStatement::ContinueLabel:
+ parseContinueLabelStatement(context);
+ break;
+ case WASMOpStatement::Switch:
+ parseSwitchStatement(context);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else {
+ switch (opWithImmediate) {
+ case WASMOpStatementWithImmediate::SetLocal:
+ parseSetLocal(context, WASMOpKind::Statement, WASMExpressionType::Void, immediate);
+ break;
+ case WASMOpStatementWithImmediate::SetGlobal:
+ parseSetGlobal(context, WASMOpKind::Statement, WASMExpressionType::Void, immediate);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseReturnStatement(Context& context)
+{
+ ContextExpression expression = 0;
+ if (m_returnType != WASMExpressionType::Void) {
+ expression = parseExpression(context, m_returnType);
+ PROPAGATE_ERROR();
+ }
+ context.buildReturn(expression, m_returnType);
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseBlockStatement(Context& context)
+{
+ uint32_t numberOfStatements;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfStatements, "Cannot read the number of statements.");
+ for (uint32_t i = 0; i < numberOfStatements; ++i) {
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ }
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseIfStatement(Context& context)
+{
+ ContextJumpTarget end;
+
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTargetIf(Context::JumpCondition::Zero, expression, end);
+
+ parseStatement(context);
+ PROPAGATE_ERROR();
+
+ context.linkTarget(end);
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseIfElseStatement(Context& context)
+{
+ ContextJumpTarget elseTarget;
+ ContextJumpTarget end;
+
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTargetIf(Context::JumpCondition::Zero, expression, elseTarget);
+
+ parseStatement(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTarget(end);
+ context.linkTarget(elseTarget);
+
+ parseStatement(context);
+ PROPAGATE_ERROR();
+
+ context.linkTarget(end);
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseWhileStatement(Context& context)
+{
+ context.startLoop();
+ context.linkTarget(context.continueTarget());
+
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTargetIf(Context::JumpCondition::Zero, expression, context.breakTarget());
+
+ m_breakScopeDepth++;
+ m_continueScopeDepth++;
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ m_continueScopeDepth--;
+ m_breakScopeDepth--;
+
+ context.jumpToTarget(context.continueTarget());
+
+ context.linkTarget(context.breakTarget());
+ context.endLoop();
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseDoStatement(Context& context)
+{
+ context.startLoop();
+
+ ContextJumpTarget topOfLoop;
+ context.linkTarget(topOfLoop);
+
+ m_breakScopeDepth++;
+ m_continueScopeDepth++;
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ m_continueScopeDepth--;
+ m_breakScopeDepth--;
+
+ context.linkTarget(context.continueTarget());
+
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTargetIf(Context::JumpCondition::NonZero, expression, topOfLoop);
+
+ context.linkTarget(context.breakTarget());
+ context.endLoop();
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseLabelStatement(Context& context)
+{
+ context.startLabel();
+ m_labelDepth++;
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ m_labelDepth--;
+ context.endLabel();
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseBreakStatement(Context& context)
+{
+ FAIL_IF_FALSE(m_breakScopeDepth, "'break' is only valid inside a switch or loop statement.");
+ context.jumpToTarget(context.breakTarget());
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseBreakLabelStatement(Context& context)
+{
+ uint32_t labelIndex;
+ READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
+ FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
+ context.jumpToTarget(context.breakLabelTarget(labelIndex));
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseContinueStatement(Context& context)
+{
+ FAIL_IF_FALSE(m_continueScopeDepth, "'continue' is only valid inside a loop statement.");
+ context.jumpToTarget(context.continueTarget());
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseContinueLabelStatement(Context& context)
+{
+ uint32_t labelIndex;
+ READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
+ FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
+ context.jumpToTarget(context.continueLabelTarget(labelIndex));
+ return UNUSED;
+}
+
+template <class Context>
+ContextStatement WASMFunctionParser::parseSwitchStatement(Context& context)
+{
+ context.startSwitch();
+ uint32_t numberOfCases;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfCases, "Cannot read the number of cases.");
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ ContextJumpTarget compare;
+ context.jumpToTarget(compare);
+
+ Vector<int64_t> cases;
+ Vector<ContextJumpTarget> targets;
+ cases.reserveInitialCapacity(numberOfCases);
+ targets.reserveInitialCapacity(numberOfCases);
+ bool hasDefault = false;
+ ContextJumpTarget defaultTarget;
+
+ m_breakScopeDepth++;
+ for (uint32_t i = 0; i < numberOfCases; ++i) {
+ WASMSwitchCase switchCase;
+ READ_SWITCH_CASE_OR_FAIL(switchCase, "Cannot read the switch case.");
+ switch (switchCase) {
+ case WASMSwitchCase::CaseWithNoStatements:
+ case WASMSwitchCase::CaseWithStatement:
+ case WASMSwitchCase::CaseWithBlockStatement: {
+ uint32_t value;
+ READ_COMPACT_INT32_OR_FAIL(value, "Cannot read the value of the switch case.");
+ cases.uncheckedAppend(value);
+ ContextJumpTarget target;
+ context.linkTarget(target);
+ targets.uncheckedAppend(target);
+ if (switchCase == WASMSwitchCase::CaseWithStatement) {
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ } else if (switchCase == WASMSwitchCase::CaseWithBlockStatement) {
+ parseBlockStatement(context);
+ PROPAGATE_ERROR();
+ }
+ break;
+ }
+ case WASMSwitchCase::DefaultWithNoStatements:
+ case WASMSwitchCase::DefaultWithStatement:
+ case WASMSwitchCase::DefaultWithBlockStatement: {
+ FAIL_IF_FALSE(i == numberOfCases - 1, "The default case must be the last case.");
+ hasDefault = true;
+ context.linkTarget(defaultTarget);
+ if (switchCase == WASMSwitchCase::DefaultWithStatement) {
+ parseStatement(context);
+ PROPAGATE_ERROR();
+ } else if (switchCase == WASMSwitchCase::DefaultWithBlockStatement) {
+ parseBlockStatement(context);
+ PROPAGATE_ERROR();
+ }
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ if (!hasDefault)
+ context.linkTarget(defaultTarget);
+
+ m_breakScopeDepth--;
+
+ context.jumpToTarget(context.breakTarget());
+ context.linkTarget(compare);
+
+ context.buildSwitch(expression, cases, targets, defaultTarget);
+
+ context.linkTarget(context.breakTarget());
+ context.endSwitch();
+ return UNUSED;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseExpression(Context& context, WASMExpressionType expressionType)
+{
+ switch (expressionType) {
+ case WASMExpressionType::I32:
+ return parseExpressionI32(context);
+ case WASMExpressionType::F32:
+ return parseExpressionF32(context);
+ case WASMExpressionType::F64:
+ return parseExpressionF64(context);
+ case WASMExpressionType::Void:
+ return parseExpressionVoid(context);
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseExpressionI32(Context& context)
+{
+ bool hasImmediate;
+ WASMOpExpressionI32 op;
+ WASMOpExpressionI32WithImmediate opWithImmediate;
+ uint8_t immediate;
+ READ_OP_EXPRESSION_I32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the int32 expression opcode.");
+ if (!hasImmediate) {
+ switch (op) {
+ case WASMOpExpressionI32::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionI32(context);
+ case WASMOpExpressionI32::Immediate:
+ return parseImmediateExpressionI32(context);
+ case WASMOpExpressionI32::GetLocal:
+ return parseGetLocalExpression(context, WASMType::I32);
+ case WASMOpExpressionI32::GetGlobal:
+ return parseGetGlobalExpression(context, WASMType::I32);
+ case WASMOpExpressionI32::SetLocal:
+ return parseSetLocal(context, WASMOpKind::Expression, WASMExpressionType::I32);
+ case WASMOpExpressionI32::SetGlobal:
+ return parseSetGlobal(context, WASMOpKind::Expression, WASMExpressionType::I32);
+ case WASMOpExpressionI32::SLoad8:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::SignExtend);
+ case WASMOpExpressionI32::SLoadWithOffset8:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::SignExtend);
+ case WASMOpExpressionI32::ULoad8:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::ZeroExtend);
+ case WASMOpExpressionI32::ULoadWithOffset8:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::ZeroExtend);
+ case WASMOpExpressionI32::SLoad16:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::SignExtend);
+ case WASMOpExpressionI32::SLoadWithOffset16:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::SignExtend);
+ case WASMOpExpressionI32::ULoad16:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset, MemoryAccessConversion::ZeroExtend);
+ case WASMOpExpressionI32::ULoadWithOffset16:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset, MemoryAccessConversion::ZeroExtend);
+ case WASMOpExpressionI32::Load32:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionI32::LoadWithOffset32:
+ return parseLoad(context, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionI32::Store8:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionI32::StoreWithOffset8:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I8, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionI32::Store16:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionI32::StoreWithOffset16:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I16, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionI32::Store32:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionI32::StoreWithOffset32:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::I32, WASMMemoryType::I32, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionI32::CallInternal:
+ return parseCallInternal(context, WASMOpKind::Expression, WASMExpressionType::I32);
+ case WASMOpExpressionI32::CallIndirect:
+ return parseCallIndirect(context, WASMOpKind::Expression, WASMExpressionType::I32);
+ case WASMOpExpressionI32::CallImport:
+ return parseCallImport(context, WASMOpKind::Expression, WASMExpressionType::I32);
+ case WASMOpExpressionI32::Conditional:
+ return parseConditional(context, WASMExpressionType::I32);
+ case WASMOpExpressionI32::Comma:
+ return parseComma(context, WASMExpressionType::I32);
+ case WASMOpExpressionI32::FromF32:
+ return parseConvertType(context, WASMExpressionType::F32, WASMExpressionType::I32, WASMTypeConversion::ConvertSigned);
+ case WASMOpExpressionI32::FromF64:
+ return parseConvertType(context, WASMExpressionType::F64, WASMExpressionType::I32, WASMTypeConversion::ConvertSigned);
+ case WASMOpExpressionI32::Negate:
+ case WASMOpExpressionI32::BitNot:
+ case WASMOpExpressionI32::CountLeadingZeros:
+ case WASMOpExpressionI32::LogicalNot:
+ case WASMOpExpressionI32::Abs:
+ return parseUnaryExpressionI32(context, op);
+ case WASMOpExpressionI32::Add:
+ case WASMOpExpressionI32::Sub:
+ case WASMOpExpressionI32::Mul:
+ case WASMOpExpressionI32::SDiv:
+ case WASMOpExpressionI32::UDiv:
+ case WASMOpExpressionI32::SMod:
+ case WASMOpExpressionI32::UMod:
+ case WASMOpExpressionI32::BitOr:
+ case WASMOpExpressionI32::BitAnd:
+ case WASMOpExpressionI32::BitXor:
+ case WASMOpExpressionI32::LeftShift:
+ case WASMOpExpressionI32::ArithmeticRightShift:
+ case WASMOpExpressionI32::LogicalRightShift:
+ return parseBinaryExpressionI32(context, op);
+ case WASMOpExpressionI32::EqualI32:
+ case WASMOpExpressionI32::NotEqualI32:
+ case WASMOpExpressionI32::SLessThanI32:
+ case WASMOpExpressionI32::ULessThanI32:
+ case WASMOpExpressionI32::SLessThanOrEqualI32:
+ case WASMOpExpressionI32::ULessThanOrEqualI32:
+ case WASMOpExpressionI32::SGreaterThanI32:
+ case WASMOpExpressionI32::UGreaterThanI32:
+ case WASMOpExpressionI32::SGreaterThanOrEqualI32:
+ case WASMOpExpressionI32::UGreaterThanOrEqualI32:
+ return parseRelationalI32ExpressionI32(context, op);
+ case WASMOpExpressionI32::EqualF32:
+ case WASMOpExpressionI32::NotEqualF32:
+ case WASMOpExpressionI32::LessThanF32:
+ case WASMOpExpressionI32::LessThanOrEqualF32:
+ case WASMOpExpressionI32::GreaterThanF32:
+ case WASMOpExpressionI32::GreaterThanOrEqualF32:
+ return parseRelationalF32ExpressionI32(context, op);
+ case WASMOpExpressionI32::EqualF64:
+ case WASMOpExpressionI32::NotEqualF64:
+ case WASMOpExpressionI32::LessThanF64:
+ case WASMOpExpressionI32::LessThanOrEqualF64:
+ case WASMOpExpressionI32::GreaterThanF64:
+ case WASMOpExpressionI32::GreaterThanOrEqualF64:
+ return parseRelationalF64ExpressionI32(context, op);
+ case WASMOpExpressionI32::SMin:
+ case WASMOpExpressionI32::UMin:
+ case WASMOpExpressionI32::SMax:
+ case WASMOpExpressionI32::UMax:
+ return parseMinOrMaxExpressionI32(context, op);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else {
+ switch (opWithImmediate) {
+ case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionI32(context, immediate);
+ case WASMOpExpressionI32WithImmediate::Immediate:
+ return parseImmediateExpressionI32(context, immediate);
+ case WASMOpExpressionI32WithImmediate::GetLocal:
+ return parseGetLocalExpression(context, WASMType::I32, immediate);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ return 0;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context, uint32_t constantPoolIndex)
+{
+ FAIL_IF_FALSE(constantPoolIndex < m_module->i32Constants().size(), "The constant pool index is incorrect.");
+ return context.buildImmediateI32(m_module->i32Constants()[constantPoolIndex]);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context)
+{
+ uint32_t constantPoolIndex;
+ READ_COMPACT_UINT32_OR_FAIL(constantPoolIndex, "Cannot read the constant pool index.");
+ return parseConstantPoolIndexExpressionI32(context, constantPoolIndex);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context, uint32_t immediate)
+{
+ return context.buildImmediateI32(immediate);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context)
+{
+ uint32_t immediate;
+ READ_COMPACT_UINT32_OR_FAIL(immediate, "Cannot read the immediate.");
+ return parseImmediateExpressionI32(context, immediate);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseUnaryExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ return context.buildUnaryI32(expression, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseBinaryExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression left = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ return context.buildBinaryI32(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseRelationalI32ExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression left = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ return context.buildRelationalI32(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseRelationalF32ExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression left = parseExpressionF32(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionF32(context);
+ PROPAGATE_ERROR();
+ return context.buildRelationalF32(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseRelationalF64ExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ ContextExpression left = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ return context.buildRelationalF64(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseMinOrMaxExpressionI32(Context& context, WASMOpExpressionI32 op)
+{
+ uint32_t numberOfArguments;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfArguments, "Cannot read the number of arguments to min/max.");
+ FAIL_IF_FALSE(numberOfArguments >= 2, "Min/max must be passed at least 2 arguments.");
+ ContextExpression current = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ for (uint32_t i = 1; i < numberOfArguments; ++i) {
+ ContextExpression expression = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ current = context.buildMinOrMaxI32(current, expression, op);
+ }
+ return current;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseExpressionF32(Context& context)
+{
+ bool hasImmediate;
+ WASMOpExpressionF32 op;
+ WASMOpExpressionF32WithImmediate opWithImmediate;
+ uint8_t immediate;
+ READ_OP_EXPRESSION_F32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the float32 expression opcode.");
+ if (!hasImmediate) {
+ switch (op) {
+ case WASMOpExpressionF32::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionF32(context);
+ case WASMOpExpressionF32::Immediate:
+ return parseImmediateExpressionF32(context);
+ case WASMOpExpressionF32::GetLocal:
+ return parseGetLocalExpression(context, WASMType::F32);
+ case WASMOpExpressionF32::GetGlobal:
+ return parseGetGlobalExpression(context, WASMType::F32);
+ case WASMOpExpressionF32::SetLocal:
+ return parseSetLocal(context, WASMOpKind::Expression, WASMExpressionType::F32);
+ case WASMOpExpressionF32::SetGlobal:
+ return parseSetGlobal(context, WASMOpKind::Expression, WASMExpressionType::F32);
+ case WASMOpExpressionF32::Load:
+ return parseLoad(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionF32::LoadWithOffset:
+ return parseLoad(context, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionF32::Store:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionF32::StoreWithOffset:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::F32, WASMMemoryType::F32, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionF32::CallInternal:
+ return parseCallInternal(context, WASMOpKind::Expression, WASMExpressionType::F32);
+ case WASMOpExpressionF32::CallIndirect:
+ return parseCallIndirect(context, WASMOpKind::Expression, WASMExpressionType::F32);
+ case WASMOpExpressionF32::Conditional:
+ return parseConditional(context, WASMExpressionType::F32);
+ case WASMOpExpressionF32::Comma:
+ return parseComma(context, WASMExpressionType::F32);
+ case WASMOpExpressionF32::FromS32:
+ return parseConvertType(context, WASMExpressionType::I32, WASMExpressionType::F32, WASMTypeConversion::ConvertSigned);
+ case WASMOpExpressionF32::FromU32:
+ return parseConvertType(context, WASMExpressionType::I32, WASMExpressionType::F32, WASMTypeConversion::ConvertUnsigned);
+ case WASMOpExpressionF32::FromF64:
+ return parseConvertType(context, WASMExpressionType::F64, WASMExpressionType::F32, WASMTypeConversion::Demote);
+ case WASMOpExpressionF32::Negate:
+ case WASMOpExpressionF32::Abs:
+ case WASMOpExpressionF32::Ceil:
+ case WASMOpExpressionF32::Floor:
+ case WASMOpExpressionF32::Sqrt:
+ return parseUnaryExpressionF32(context, op);
+ case WASMOpExpressionF32::Add:
+ case WASMOpExpressionF32::Sub:
+ case WASMOpExpressionF32::Mul:
+ case WASMOpExpressionF32::Div:
+ return parseBinaryExpressionF32(context, op);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else {
+ switch (opWithImmediate) {
+ case WASMOpExpressionF32WithImmediate::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionF32(context, immediate);
+ case WASMOpExpressionF32WithImmediate::GetLocal:
+ return parseGetLocalExpression(context, WASMType::F32, immediate);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ return 0;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionF32(Context& context, uint32_t constantIndex)
+{
+ FAIL_IF_FALSE(constantIndex < m_module->f32Constants().size(), "The constant pool index is incorrect.");
+ return context.buildImmediateF32(m_module->f32Constants()[constantIndex]);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionF32(Context& context)
+{
+ uint32_t constantIndex;
+ READ_COMPACT_UINT32_OR_FAIL(constantIndex, "Cannot read the constant pool index.");
+ return parseConstantPoolIndexExpressionF32(context, constantIndex);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseImmediateExpressionF32(Context& context)
+{
+ float immediate;
+ READ_FLOAT_OR_FAIL(immediate, "Cannot read the immediate.");
+ return context.buildImmediateF32(immediate);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseUnaryExpressionF32(Context& context, WASMOpExpressionF32 op)
+{
+ ContextExpression expression = parseExpressionF32(context);
+ PROPAGATE_ERROR();
+ return context.buildUnaryF32(expression, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseBinaryExpressionF32(Context& context, WASMOpExpressionF32 op)
+{
+ ContextExpression left = parseExpressionF32(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionF32(context);
+ PROPAGATE_ERROR();
+ return context.buildBinaryF32(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseExpressionF64(Context& context)
+{
+ bool hasImmediate;
+ WASMOpExpressionF64 op;
+ WASMOpExpressionF64WithImmediate opWithImmediate;
+ uint8_t immediate;
+ READ_OP_EXPRESSION_F64_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the float64 expression opcode.");
+ if (!hasImmediate) {
+ switch (op) {
+ case WASMOpExpressionF64::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionF64(context);
+ case WASMOpExpressionF64::Immediate:
+ return parseImmediateExpressionF64(context);
+ case WASMOpExpressionF64::GetLocal:
+ return parseGetLocalExpression(context, WASMType::F64);
+ case WASMOpExpressionF64::GetGlobal:
+ return parseGetGlobalExpression(context, WASMType::F64);
+ case WASMOpExpressionF64::SetLocal:
+ return parseSetLocal(context, WASMOpKind::Expression, WASMExpressionType::F64);
+ case WASMOpExpressionF64::SetGlobal:
+ return parseSetGlobal(context, WASMOpKind::Expression, WASMExpressionType::F64);
+ case WASMOpExpressionF64::Load:
+ return parseLoad(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionF64::LoadWithOffset:
+ return parseLoad(context, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionF64::Store:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::NoOffset);
+ case WASMOpExpressionF64::StoreWithOffset:
+ return parseStore(context, WASMOpKind::Expression, WASMExpressionType::F64, WASMMemoryType::F64, MemoryAccessOffsetMode::WithOffset);
+ case WASMOpExpressionF64::CallInternal:
+ return parseCallInternal(context, WASMOpKind::Expression, WASMExpressionType::F64);
+ case WASMOpExpressionF64::CallImport:
+ return parseCallImport(context, WASMOpKind::Expression, WASMExpressionType::F64);
+ case WASMOpExpressionF64::CallIndirect:
+ return parseCallIndirect(context, WASMOpKind::Expression, WASMExpressionType::F64);
+ case WASMOpExpressionF64::Conditional:
+ return parseConditional(context, WASMExpressionType::F64);
+ case WASMOpExpressionF64::Comma:
+ return parseComma(context, WASMExpressionType::F64);
+ case WASMOpExpressionF64::FromS32:
+ return parseConvertType(context, WASMExpressionType::I32, WASMExpressionType::F64, WASMTypeConversion::ConvertSigned);
+ case WASMOpExpressionF64::FromU32:
+ return parseConvertType(context, WASMExpressionType::I32, WASMExpressionType::F64, WASMTypeConversion::ConvertUnsigned);
+ case WASMOpExpressionF64::FromF32:
+ return parseConvertType(context, WASMExpressionType::F32, WASMExpressionType::F64, WASMTypeConversion::Promote);
+ case WASMOpExpressionF64::Negate:
+ case WASMOpExpressionF64::Abs:
+ case WASMOpExpressionF64::Ceil:
+ case WASMOpExpressionF64::Floor:
+ case WASMOpExpressionF64::Sqrt:
+ case WASMOpExpressionF64::Cos:
+ case WASMOpExpressionF64::Sin:
+ case WASMOpExpressionF64::Tan:
+ case WASMOpExpressionF64::ACos:
+ case WASMOpExpressionF64::ASin:
+ case WASMOpExpressionF64::ATan:
+ case WASMOpExpressionF64::Exp:
+ case WASMOpExpressionF64::Ln:
+ return parseUnaryExpressionF64(context, op);
+ case WASMOpExpressionF64::Add:
+ case WASMOpExpressionF64::Sub:
+ case WASMOpExpressionF64::Mul:
+ case WASMOpExpressionF64::Div:
+ case WASMOpExpressionF64::Mod:
+ case WASMOpExpressionF64::ATan2:
+ case WASMOpExpressionF64::Pow:
+ return parseBinaryExpressionF64(context, op);
+ case WASMOpExpressionF64::Min:
+ case WASMOpExpressionF64::Max:
+ return parseMinOrMaxExpressionF64(context, op);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ } else {
+ switch (opWithImmediate) {
+ case WASMOpExpressionF64WithImmediate::ConstantPoolIndex:
+ return parseConstantPoolIndexExpressionF64(context, immediate);
+ case WASMOpExpressionF64WithImmediate::GetLocal:
+ return parseGetLocalExpression(context, WASMType::F64, immediate);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+ return 0;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionF64(Context& context, uint32_t constantIndex)
+{
+ FAIL_IF_FALSE(constantIndex < m_module->f64Constants().size(), "The constant index is incorrect.");
+ return context.buildImmediateF64(m_module->f64Constants()[constantIndex]);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionF64(Context& context)
+{
+ uint32_t constantIndex;
+ READ_COMPACT_UINT32_OR_FAIL(constantIndex, "Cannot read the constant index.");
+ return parseConstantPoolIndexExpressionF64(context, constantIndex);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseImmediateExpressionF64(Context& context)
+{
+ double immediate;
+ READ_DOUBLE_OR_FAIL(immediate, "Cannot read the immediate.");
+ return context.buildImmediateF64(immediate);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseUnaryExpressionF64(Context& context, WASMOpExpressionF64 op)
+{
+ ContextExpression expression = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ return context.buildUnaryF64(expression, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseBinaryExpressionF64(Context& context, WASMOpExpressionF64 op)
+{
+ ContextExpression left = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ ContextExpression right = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ return context.buildBinaryF64(left, right, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseMinOrMaxExpressionF64(Context& context, WASMOpExpressionF64 op)
+{
+ uint32_t numberOfArguments;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfArguments, "Cannot read the number of arguments to min/max.");
+ FAIL_IF_FALSE(numberOfArguments >= 2, "Min/max must be passed at least 2 arguments.");
+ ContextExpression current = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ for (uint32_t i = 1; i < numberOfArguments; ++i) {
+ ContextExpression expression = parseExpressionF64(context);
+ PROPAGATE_ERROR();
+ current = context.buildMinOrMaxF64(current, expression, op);
+ }
+ return current;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseExpressionVoid(Context& context)
+{
+ WASMOpExpressionVoid op;
+ READ_OP_EXPRESSION_VOID_OR_FAIL(op, "Cannot read the void expression opcode.");
+ switch (op) {
+ case WASMOpExpressionVoid::CallInternal:
+ return parseCallInternal(context, WASMOpKind::Expression, WASMExpressionType::Void);
+ case WASMOpExpressionVoid::CallIndirect:
+ return parseCallIndirect(context, WASMOpKind::Expression, WASMExpressionType::Void);
+ case WASMOpExpressionVoid::CallImport:
+ return parseCallImport(context, WASMOpKind::Expression, WASMExpressionType::Void);
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseGetLocalExpression(Context& context, WASMType type, uint32_t localIndex)
+{
+ FAIL_IF_FALSE(localIndex < m_localTypes.size(), "The local index is incorrect.");
+ FAIL_IF_FALSE(m_localTypes[localIndex] == type, "Expected a local of type " + nameOfType(type) + '.');
+ return context.buildGetLocal(localIndex, type);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseGetLocalExpression(Context& context, WASMType type)
+{
+ uint32_t localIndex;
+ READ_COMPACT_UINT32_OR_FAIL(localIndex, "Cannot read the local index.");
+ return parseGetLocalExpression(context, type, localIndex);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseGetGlobalExpression(Context& context, WASMType type)
+{
+ uint32_t globalIndex;
+ READ_COMPACT_UINT32_OR_FAIL(globalIndex, "Cannot read the global index.");
+ FAIL_IF_FALSE(globalIndex < m_module->globalVariableTypes().size(), "The global index is incorrect.");
+ FAIL_IF_FALSE(m_module->globalVariableTypes()[globalIndex] == type, "Expected a global of type " + nameOfType(type) + '.');
+ return context.buildGetGlobal(globalIndex, type);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseSetLocal(Context& context, WASMOpKind opKind, WASMExpressionType expressionType, uint32_t localIndex)
+{
+ FAIL_IF_FALSE(localIndex < m_localTypes.size(), "The local variable index is incorrect.");
+ WASMType type = m_localTypes[localIndex];
+ if (opKind == WASMOpKind::Expression)
+ FAIL_IF_FALSE(expressionType == WASMExpressionType(type), "The type doesn't match.");
+ ContextExpression expression = parseExpression(context, WASMExpressionType(type));
+ PROPAGATE_ERROR();
+ return context.buildSetLocal(opKind, localIndex, expression, type);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseSetLocal(Context& context, WASMOpKind opKind, WASMExpressionType expressionType)
+{
+ uint32_t localIndex;
+ READ_COMPACT_UINT32_OR_FAIL(localIndex, "Cannot read the local index.");
+ return parseSetLocal(context, opKind, expressionType, localIndex);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseSetGlobal(Context& context, WASMOpKind opKind, WASMExpressionType expressionType, uint32_t globalIndex)
+{
+ FAIL_IF_FALSE(globalIndex < m_module->globalVariableTypes().size(), "The global index is incorrect.");
+ WASMType type = m_module->globalVariableTypes()[globalIndex];
+ if (opKind == WASMOpKind::Expression)
+ FAIL_IF_FALSE(expressionType == WASMExpressionType(type), "The type doesn't match.");
+ ContextExpression expression = parseExpression(context, WASMExpressionType(type));
+ PROPAGATE_ERROR();
+ return context.buildSetGlobal(opKind, globalIndex, expression, type);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseSetGlobal(Context& context, WASMOpKind opKind, WASMExpressionType expressionType)
+{
+ uint32_t globalIndex;
+ READ_COMPACT_UINT32_OR_FAIL(globalIndex, "Cannot read the global index.");
+ return parseSetGlobal(context, opKind, expressionType, globalIndex);
+}
+
+template <class Context>
+ContextMemoryAddress WASMFunctionParser::parseMemoryAddress(Context& context, MemoryAccessOffsetMode offsetMode)
+{
+ uint32_t offset = 0;
+ if (offsetMode == MemoryAccessOffsetMode::WithOffset)
+ READ_COMPACT_UINT32_OR_FAIL(offset, "Cannot read the address offset.");
+ ContextExpression index = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+ return ContextMemoryAddress(index, offset);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseLoad(Context& context, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessOffsetMode offsetMode, MemoryAccessConversion conversion)
+{
+ FAIL_IF_FALSE(m_module->arrayBuffer(), "An ArrayBuffer is not provided.");
+ const ContextMemoryAddress& memoryAddress = parseMemoryAddress(context, offsetMode);
+ PROPAGATE_ERROR();
+ return context.buildLoad(memoryAddress, expressionType, memoryType, conversion);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseStore(Context& context, WASMOpKind opKind, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessOffsetMode offsetMode)
+{
+ FAIL_IF_FALSE(m_module->arrayBuffer(), "An ArrayBuffer is not provided.");
+ const ContextMemoryAddress& memoryAddress = parseMemoryAddress(context, offsetMode);
+ PROPAGATE_ERROR();
+
+ ContextExpression value = parseExpression(context, expressionType);
+ PROPAGATE_ERROR();
+ return context.buildStore(opKind, memoryAddress, expressionType, memoryType, value);
+}
+
+template <class Context>
+ContextExpressionList WASMFunctionParser::parseCallArguments(Context& context, const Vector<WASMType>& arguments)
+{
+ ContextExpressionList argumentList;
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ ContextExpression expression = parseExpression(context, WASMExpressionType(arguments[i]));
+ PROPAGATE_ERROR();
+ context.appendExpressionList(argumentList, expression);
+ }
+ return argumentList;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseCallInternal(Context& context, WASMOpKind opKind, WASMExpressionType returnType)
+{
+ uint32_t functionIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read the function index.");
+ FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect.");
+ const WASMSignature& signature = m_module->signatures()[m_module->functionDeclarations()[functionIndex].signatureIndex];
+ if (opKind == WASMOpKind::Expression)
+ FAIL_IF_FALSE(signature.returnType == returnType, "Wrong return type.");
+
+ ContextExpressionList argumentList = parseCallArguments(context, signature.arguments);
+ PROPAGATE_ERROR();
+ return context.buildCallInternal(functionIndex, argumentList, signature, returnType);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseCallIndirect(Context& context, WASMOpKind opKind, WASMExpressionType returnType)
+{
+ uint32_t functionPointerTableIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionPointerTableIndex, "Cannot read the function pointer table index.");
+ FAIL_IF_FALSE(functionPointerTableIndex < m_module->functionPointerTables().size(), "The function pointer table index is incorrect.");
+ const WASMFunctionPointerTable& functionPointerTable = m_module->functionPointerTables()[functionPointerTableIndex];
+ const WASMSignature& signature = m_module->signatures()[functionPointerTable.signatureIndex];
+ if (opKind == WASMOpKind::Expression)
+ FAIL_IF_FALSE(signature.returnType == returnType, "Wrong return type.");
+
+ ContextExpression index = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ ContextExpressionList argumentList = parseCallArguments(context, signature.arguments);
+ PROPAGATE_ERROR();
+ return context.buildCallIndirect(functionPointerTableIndex, index, argumentList, signature, returnType);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseCallImport(Context& context, WASMOpKind opKind, WASMExpressionType returnType)
+{
+ uint32_t functionImportSignatureIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionImportSignatureIndex, "Cannot read the function import signature index.");
+ FAIL_IF_FALSE(functionImportSignatureIndex < m_module->functionImportSignatures().size(), "The function import signature index is incorrect.");
+ const WASMFunctionImportSignature& functionImportSignature = m_module->functionImportSignatures()[functionImportSignatureIndex];
+ const WASMSignature& signature = m_module->signatures()[functionImportSignature.signatureIndex];
+ if (opKind == WASMOpKind::Expression)
+ FAIL_IF_FALSE(signature.returnType == returnType, "Wrong return type.");
+
+ ContextExpressionList argumentList = parseCallArguments(context, signature.arguments);
+ PROPAGATE_ERROR();
+ return context.buildCallImport(functionImportSignature.functionImportIndex, argumentList, signature, returnType);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConditional(Context& context, WASMExpressionType expressionType)
+{
+ ContextJumpTarget elseTarget;
+ ContextJumpTarget end;
+
+ ContextExpression condition = parseExpressionI32(context);
+ PROPAGATE_ERROR();
+
+ context.jumpToTargetIf(Context::JumpCondition::Zero, condition, elseTarget);
+
+ parseExpression(context, expressionType);
+ PROPAGATE_ERROR();
+
+ context.jumpToTarget(end);
+ context.linkTarget(elseTarget);
+
+ // We use discard() here to decrement the stack top in the baseline JIT.
+ context.discard(UNUSED);
+ parseExpression(context, expressionType);
+ PROPAGATE_ERROR();
+
+ context.linkTarget(end);
+ return UNUSED;
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseComma(Context& context, WASMExpressionType expressionType)
+{
+ WASMExpressionType leftExpressionType;
+ READ_EXPRESSION_TYPE_OR_FAIL(leftExpressionType, "Cannot read the expression type.");
+ ContextExpression leftExpression = parseExpression(context, leftExpressionType);
+ PROPAGATE_ERROR();
+ if (leftExpressionType != WASMExpressionType::Void)
+ context.discard(leftExpression);
+ return parseExpression(context, expressionType);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseConvertType(Context& context, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion conversion)
+{
+ ContextExpression expression = parseExpression(context, fromType);
+ PROPAGATE_ERROR();
+
+ return context.buildConvertType(expression, fromType, toType, conversion);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionParser.h b/Source/JavaScriptCore/wasm/WASMFunctionParser.h
new file mode 100644
index 000000000..7f09e3e85
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFunctionParser.h
@@ -0,0 +1,148 @@
+/*
+ * 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 WASMFunctionParser_h
+#define WASMFunctionParser_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "SourceCode.h"
+#include "WASMReader.h"
+
+#define ContextExpression typename Context::Expression
+#define ContextStatement typename Context::Statement
+#define ContextExpressionList typename Context::ExpressionList
+#define ContextMemoryAddress typename Context::MemoryAddress
+#define ContextJumpTarget typename Context::JumpTarget
+
+namespace JSC {
+
+class CodeBlock;
+class JSWASMModule;
+class VM;
+
+class WASMFunctionParser {
+public:
+ 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:
+ WASMFunctionParser(JSWASMModule* module, const SourceCode& source, size_t functionIndex)
+ : m_module(module)
+ , m_reader(static_cast<WebAssemblySourceProvider*>(source.provider())->data())
+ , m_functionIndex(functionIndex)
+ , m_breakScopeDepth(0)
+ , m_continueScopeDepth(0)
+ , m_labelDepth(0)
+ {
+ }
+
+ template <class Context> bool parseFunction(Context&);
+ bool parseLocalVariables();
+
+ template <class Context> ContextStatement parseStatement(Context&);
+ template <class Context> ContextStatement parseReturnStatement(Context&);
+ template <class Context> ContextStatement parseBlockStatement(Context&);
+ template <class Context> ContextStatement parseIfStatement(Context&);
+ template <class Context> ContextStatement parseIfElseStatement(Context&);
+ template <class Context> ContextStatement parseWhileStatement(Context&);
+ template <class Context> ContextStatement parseDoStatement(Context&);
+ template <class Context> ContextStatement parseLabelStatement(Context&);
+ template <class Context> ContextStatement parseBreakStatement(Context&);
+ template <class Context> ContextStatement parseBreakLabelStatement(Context&);
+ template <class Context> ContextStatement parseContinueStatement(Context&);
+ template <class Context> ContextStatement parseContinueLabelStatement(Context&);
+ template <class Context> ContextStatement parseSwitchStatement(Context&);
+
+ template <class Context> ContextExpression parseExpression(Context&, WASMExpressionType);
+
+ template <class Context> ContextExpression parseExpressionI32(Context&);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&, uint32_t constantPoolIndex);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&);
+ template <class Context> ContextExpression parseImmediateExpressionI32(Context&, uint32_t immediate);
+ template <class Context> ContextExpression parseImmediateExpressionI32(Context&);
+ template <class Context> ContextExpression parseUnaryExpressionI32(Context&, WASMOpExpressionI32);
+ template <class Context> ContextExpression parseBinaryExpressionI32(Context&, WASMOpExpressionI32);
+ template <class Context> ContextExpression parseRelationalI32ExpressionI32(Context&, WASMOpExpressionI32);
+ template <class Context> ContextExpression parseRelationalF32ExpressionI32(Context&, WASMOpExpressionI32);
+ template <class Context> ContextExpression parseRelationalF64ExpressionI32(Context&, WASMOpExpressionI32);
+ template <class Context> ContextExpression parseMinOrMaxExpressionI32(Context&, WASMOpExpressionI32);
+
+ template <class Context> ContextExpression parseExpressionF32(Context&);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionF32(Context&, uint32_t constantIndex);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionF32(Context&);
+ template <class Context> ContextExpression parseImmediateExpressionF32(Context&);
+ template <class Context> ContextExpression parseUnaryExpressionF32(Context&, WASMOpExpressionF32);
+ template <class Context> ContextExpression parseBinaryExpressionF32(Context&, WASMOpExpressionF32);
+
+ template <class Context> ContextExpression parseExpressionF64(Context&);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionF64(Context&, uint32_t constantIndex);
+ template <class Context> ContextExpression parseConstantPoolIndexExpressionF64(Context&);
+ template <class Context> ContextExpression parseImmediateExpressionF64(Context&);
+ template <class Context> ContextExpression parseUnaryExpressionF64(Context&, WASMOpExpressionF64);
+ template <class Context> ContextExpression parseBinaryExpressionF64(Context&, WASMOpExpressionF64);
+ template <class Context> ContextExpression parseMinOrMaxExpressionF64(Context&, WASMOpExpressionF64);
+
+ template <class Context> ContextExpression parseExpressionVoid(Context&);
+
+ template <class Context> ContextExpression parseGetLocalExpression(Context&, WASMType, uint32_t localIndex);
+ template <class Context> ContextExpression parseGetLocalExpression(Context&, WASMType);
+ template <class Context> ContextExpression parseGetGlobalExpression(Context&, WASMType);
+ template <class Context> ContextExpression parseSetLocal(Context&, WASMOpKind, WASMExpressionType, uint32_t localIndex);
+ template <class Context> ContextExpression parseSetLocal(Context&, WASMOpKind, WASMExpressionType);
+ template <class Context> ContextExpression parseSetGlobal(Context&, WASMOpKind, WASMExpressionType, uint32_t globalIndex);
+ template <class Context> ContextExpression parseSetGlobal(Context&, WASMOpKind, WASMExpressionType);
+ template <class Context> ContextMemoryAddress parseMemoryAddress(Context&, MemoryAccessOffsetMode);
+ template <class Context> ContextExpression parseLoad(Context&, WASMExpressionType, WASMMemoryType, MemoryAccessOffsetMode, MemoryAccessConversion = MemoryAccessConversion::NoConversion);
+ template <class Context> ContextExpression parseStore(Context&, WASMOpKind, WASMExpressionType, WASMMemoryType, MemoryAccessOffsetMode);
+ template <class Context> ContextExpressionList parseCallArguments(Context&, const Vector<WASMType>& arguments);
+ template <class Context> ContextExpression parseCallInternal(Context&, WASMOpKind, WASMExpressionType returnType);
+ template <class Context> ContextExpression parseCallIndirect(Context&, WASMOpKind, WASMExpressionType returnType);
+ template <class Context> ContextExpression parseCallImport(Context&, WASMOpKind, WASMExpressionType returnType);
+ template <class Context> ContextExpression parseConditional(Context&, WASMExpressionType);
+ template <class Context> ContextExpression parseComma(Context&, WASMExpressionType);
+ template <class Context> ContextExpression parseConvertType(Context&, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion);
+
+ JSWASMModule* m_module;
+ WASMReader m_reader;
+ size_t m_functionIndex;
+ String m_errorMessage;
+
+ WASMExpressionType m_returnType;
+ Vector<WASMType> m_localTypes;
+ uint32_t m_numberOfI32LocalVariables;
+ uint32_t m_numberOfF32LocalVariables;
+ uint32_t m_numberOfF64LocalVariables;
+
+ unsigned m_breakScopeDepth;
+ unsigned m_continueScopeDepth;
+ unsigned m_labelDepth;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFunctionParser_h
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h b/Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h
new file mode 100644
index 000000000..edfe42808
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h
@@ -0,0 +1,287 @@
+/*
+ * 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 WASMFunctionSyntaxChecker_h
+#define WASMFunctionSyntaxChecker_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#define UNUSED 0
+
+namespace JSC {
+
+class WASMFunctionSyntaxChecker {
+public:
+ typedef int Expression;
+ typedef int Statement;
+ typedef int ExpressionList;
+ struct MemoryAddress {
+ MemoryAddress(void*) { }
+ MemoryAddress(int, uint32_t) { }
+ };
+ typedef int JumpTarget;
+ enum class JumpCondition { Zero, NonZero };
+
+ void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
+ {
+ m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
+ }
+
+ void endFunction()
+ {
+ ASSERT(!m_tempStackTop);
+ }
+
+ int buildSetLocal(WASMOpKind opKind, uint32_t, int, WASMType)
+ {
+ if (opKind == WASMOpKind::Statement)
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildSetGlobal(WASMOpKind opKind, uint32_t, int, WASMType)
+ {
+ if (opKind == WASMOpKind::Statement)
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ void buildReturn(int, WASMExpressionType returnType)
+ {
+ if (returnType != WASMExpressionType::Void)
+ m_tempStackTop--;
+ }
+
+ int buildImmediateI32(uint32_t)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildImmediateF32(float)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildImmediateF64(double)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildGetLocal(uint32_t, WASMType)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildGetGlobal(uint32_t, WASMType)
+ {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ return UNUSED;
+ }
+
+ int buildConvertType(int, WASMExpressionType, WASMExpressionType, WASMTypeConversion)
+ {
+ return UNUSED;
+ }
+
+ int buildLoad(const MemoryAddress&, WASMExpressionType, WASMMemoryType, MemoryAccessConversion)
+ {
+ return UNUSED;
+ }
+
+ int buildStore(WASMOpKind opKind, const MemoryAddress&, WASMExpressionType, WASMMemoryType, int)
+ {
+ m_tempStackTop -= 2;
+ if (opKind == WASMOpKind::Expression)
+ m_tempStackTop++;
+ return UNUSED;
+ }
+
+ int buildUnaryI32(int, WASMOpExpressionI32)
+ {
+ return UNUSED;
+ }
+
+ int buildUnaryF32(int, WASMOpExpressionF32)
+ {
+ return UNUSED;
+ }
+
+ int buildUnaryF64(int, WASMOpExpressionF64)
+ {
+ return UNUSED;
+ }
+
+ int buildBinaryI32(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildBinaryF32(int, int, WASMOpExpressionF32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildBinaryF64(int, int, WASMOpExpressionF64)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildRelationalI32(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildRelationalF32(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildRelationalF64(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildMinOrMaxI32(int, int, WASMOpExpressionI32)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildMinOrMaxF64(int, int, WASMOpExpressionF64)
+ {
+ m_tempStackTop--;
+ return UNUSED;
+ }
+
+ int buildCallInternal(uint32_t, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ size_t argumentCount = signature.arguments.size();
+ updateTempStackHeightForCall(argumentCount);
+ m_tempStackTop -= argumentCount;
+ if (returnType != WASMExpressionType::Void) {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ }
+ return UNUSED;
+ }
+
+ int buildCallImport(uint32_t, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ size_t argumentCount = signature.arguments.size();
+ updateTempStackHeightForCall(argumentCount);
+ m_tempStackTop -= argumentCount;
+ if (returnType != WASMExpressionType::Void) {
+ m_tempStackTop++;
+ updateTempStackHeight();
+ }
+ return UNUSED;
+ }
+
+ int buildCallIndirect(uint32_t, int, int, const WASMSignature& signature, WASMExpressionType returnType)
+ {
+ size_t argumentCount = signature.arguments.size();
+ updateTempStackHeightForCall(argumentCount);
+ m_tempStackTop -= argumentCount + 1;
+ if (returnType != WASMExpressionType::Void)
+ m_tempStackTop++;
+ return UNUSED;
+ }
+
+ void appendExpressionList(int&, int) { }
+
+ void discard(int)
+ {
+ m_tempStackTop--;
+ }
+
+ void linkTarget(const int&) { }
+ void jumpToTarget(const int&) { }
+ void jumpToTargetIf(JumpCondition, int, const int&)
+ {
+ m_tempStackTop--;
+ }
+
+ void startLoop() { }
+ void endLoop() { }
+ void startSwitch() { }
+ void endSwitch() { }
+ void startLabel() { }
+ void endLabel() { }
+
+ int breakTarget() { return UNUSED; }
+ int continueTarget() { return UNUSED; }
+ int breakLabelTarget(uint32_t) { return UNUSED; }
+ int continueLabelTarget(uint32_t) { return UNUSED; }
+
+ void buildSwitch(int, const Vector<int64_t>&, const Vector<int>&, const int&)
+ {
+ m_tempStackTop--;
+ }
+
+ unsigned stackHeight()
+ {
+ return m_numberOfLocals + m_tempStackHeight;
+ }
+
+private:
+ void updateTempStackHeight()
+ {
+ if (m_tempStackTop > m_tempStackHeight)
+ m_tempStackHeight = m_tempStackTop;
+ }
+
+ void updateTempStackHeightForCall(size_t argumentCount)
+ {
+ // Boxed arguments + this argument + call frame header + maximum padding.
+ m_tempStackTop += argumentCount + 1 + JSStack::CallFrameHeaderSize + 1;
+ updateTempStackHeight();
+ m_tempStackTop -= argumentCount + 1 + JSStack::CallFrameHeaderSize + 1;
+ }
+
+ unsigned m_numberOfLocals;
+ unsigned m_tempStackTop { 0 };
+ unsigned m_tempStackHeight { 0 };
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMFunctionSyntaxChecker_h
diff --git a/Source/JavaScriptCore/wasm/WASMModuleParser.cpp b/Source/JavaScriptCore/wasm/WASMModuleParser.cpp
new file mode 100644
index 000000000..8ce35f483
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMModuleParser.cpp
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WASMModuleParser.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSArrayBuffer.h"
+#include "JSCInlines.h"
+#include "JSWASMModule.h"
+#include "StrongInlines.h"
+#include "WASMConstants.h"
+#include "WASMFunctionParser.h"
+#include <wtf/MathExtras.h>
+
+#define FAIL_WITH_MESSAGE(errorMessage) do { m_errorMessage = errorMessage; return; } while (0)
+#define READ_UINT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readUInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_FLOAT_OR_FAIL(result, errorMessage) do { if (!m_reader.readFloat(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_DOUBLE_OR_FAIL(result, errorMessage) do { if (!m_reader.readDouble(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_COMPACT_UINT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readCompactUInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_STRING_OR_FAIL(result, errorMessage) do { if (!m_reader.readString(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_TYPE_OR_FAIL(result, errorMessage) do { if (!m_reader.readType(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_EXPRESSION_TYPE_OR_FAIL(result, errorMessage) do { if (!m_reader.readExpressionType(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define READ_EXPORT_FORMAT_OR_FAIL(result, errorMessage) do { if (!m_reader.readExportFormat(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define FAIL_IF_FALSE(condition, errorMessage) do { if (!(condition)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
+#define PROPAGATE_ERROR() do { if (!m_errorMessage.isNull()) return; } while (0)
+
+namespace JSC {
+
+WASMModuleParser::WASMModuleParser(VM& vm, JSGlobalObject* globalObject, const SourceCode& source, JSObject* imports, JSArrayBuffer* arrayBuffer)
+ : m_vm(vm)
+ , m_globalObject(vm, globalObject)
+ , m_source(source)
+ , m_imports(vm, imports)
+ , m_reader(static_cast<WebAssemblySourceProvider*>(source.provider())->data())
+ , m_module(vm, JSWASMModule::create(vm, globalObject->wasmModuleStructure(), arrayBuffer))
+{
+}
+
+JSWASMModule* WASMModuleParser::parse(ExecState* exec, String& errorMessage)
+{
+ parseModule(exec);
+ if (!m_errorMessage.isNull()) {
+ errorMessage = m_errorMessage;
+ return nullptr;
+ }
+ return m_module.get();
+}
+
+void WASMModuleParser::parseModule(ExecState* exec)
+{
+ uint32_t magicNumber;
+ READ_UINT32_OR_FAIL(magicNumber, "Cannot read the magic number.");
+ FAIL_IF_FALSE(magicNumber == wasmMagicNumber, "The magic number is incorrect.");
+
+ uint32_t outputSizeInASMJS;
+ READ_UINT32_OR_FAIL(outputSizeInASMJS, "Cannot read the output size in asm.js format.");
+
+ parseConstantPoolSection();
+ PROPAGATE_ERROR();
+ parseSignatureSection();
+ PROPAGATE_ERROR();
+ parseFunctionImportSection(exec);
+ PROPAGATE_ERROR();
+ parseGlobalSection(exec);
+ PROPAGATE_ERROR();
+ parseFunctionDeclarationSection();
+ PROPAGATE_ERROR();
+ parseFunctionPointerTableSection();
+ PROPAGATE_ERROR();
+ parseFunctionDefinitionSection();
+ PROPAGATE_ERROR();
+ parseExportSection();
+ PROPAGATE_ERROR();
+
+ FAIL_IF_FALSE(!m_module->arrayBuffer() || m_module->arrayBuffer()->impl()->byteLength() < (1u << 31), "The ArrayBuffer's length must be less than 2^31.");
+}
+
+void WASMModuleParser::parseConstantPoolSection()
+{
+ uint32_t numberOfI32Constants;
+ uint32_t numberOfF32Constants;
+ uint32_t numberOfF64Constants;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfI32Constants, "Cannot read the number of int32 constants.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfF32Constants, "Cannot read the number of float32 constants.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfF64Constants, "Cannot read the number of float64 constants.");
+ m_module->i32Constants().reserveInitialCapacity(numberOfI32Constants);
+ m_module->f32Constants().reserveInitialCapacity(numberOfF32Constants);
+ m_module->f64Constants().reserveInitialCapacity(numberOfF64Constants);
+
+ for (uint32_t i = 0; i < numberOfI32Constants; ++i) {
+ uint32_t constant;
+ READ_COMPACT_UINT32_OR_FAIL(constant, "Cannot read an int32 constant.");
+ m_module->i32Constants().uncheckedAppend(constant);
+ }
+ for (uint32_t i = 0; i < numberOfF32Constants; ++i) {
+ float constant;
+ READ_FLOAT_OR_FAIL(constant, "Cannot read a float32 constant.");
+ m_module->f32Constants().uncheckedAppend(constant);
+ }
+ for (uint32_t i = 0; i < numberOfF64Constants; ++i) {
+ double constant;
+ READ_DOUBLE_OR_FAIL(constant, "Cannot read a float64 constant.");
+ m_module->f64Constants().uncheckedAppend(constant);
+ }
+}
+
+void WASMModuleParser::parseSignatureSection()
+{
+ uint32_t numberOfSignatures;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfSignatures, "Cannot read the number of signatures.");
+ m_module->signatures().reserveInitialCapacity(numberOfSignatures);
+ for (uint32_t signatureIndex = 0; signatureIndex < numberOfSignatures; ++signatureIndex) {
+ WASMSignature signature;
+ READ_EXPRESSION_TYPE_OR_FAIL(signature.returnType, "Cannot read the return type.");
+ uint32_t argumentCount;
+ READ_COMPACT_UINT32_OR_FAIL(argumentCount, "Cannot read the number of arguments.");
+ signature.arguments.reserveInitialCapacity(argumentCount);
+ for (uint32_t argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
+ WASMType type;
+ READ_TYPE_OR_FAIL(type, "Cannot read the type of an argument.");
+ signature.arguments.uncheckedAppend(type);
+ }
+ m_module->signatures().uncheckedAppend(signature);
+ }
+}
+
+void WASMModuleParser::parseFunctionImportSection(ExecState* exec)
+{
+ uint32_t numberOfFunctionImports;
+ uint32_t numberOfFunctionImportSignatures;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImports, "Cannot read the number of function imports.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImportSignatures, "Cannot read the number of function import signatures.");
+ m_module->functionImports().reserveInitialCapacity(numberOfFunctionImports);
+ m_module->functionImportSignatures().reserveInitialCapacity(numberOfFunctionImportSignatures);
+ m_module->importedFunctions().reserveInitialCapacity(numberOfFunctionImports);
+
+ for (uint32_t functionImportIndex = 0; functionImportIndex < numberOfFunctionImports; ++functionImportIndex) {
+ WASMFunctionImport functionImport;
+ READ_STRING_OR_FAIL(functionImport.functionName, "Cannot read the function import name.");
+ m_module->functionImports().uncheckedAppend(functionImport);
+
+ uint32_t numberOfSignatures;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfSignatures, "Cannot read the number of signatures.");
+ FAIL_IF_FALSE(numberOfSignatures <= numberOfFunctionImportSignatures - m_module->functionImportSignatures().size(), "The number of signatures is incorrect.");
+
+ for (uint32_t i = 0; i < numberOfSignatures; ++i) {
+ WASMFunctionImportSignature functionImportSignature;
+ READ_COMPACT_UINT32_OR_FAIL(functionImportSignature.signatureIndex, "Cannot read the signature index.");
+ FAIL_IF_FALSE(functionImportSignature.signatureIndex < m_module->signatures().size(), "The signature index is incorrect.");
+ functionImportSignature.functionImportIndex = functionImportIndex;
+ m_module->functionImportSignatures().uncheckedAppend(functionImportSignature);
+ }
+
+ JSValue value;
+ getImportedValue(exec, functionImport.functionName, value);
+ PROPAGATE_ERROR();
+ FAIL_IF_FALSE(value.isFunction(), "\"" + functionImport.functionName + "\" is not a function.");
+ JSFunction* function = jsCast<JSFunction*>(value.asCell());
+ m_module->importedFunctions().uncheckedAppend(WriteBarrier<JSFunction>(m_vm, m_module.get(), function));
+ }
+ FAIL_IF_FALSE(m_module->functionImportSignatures().size() == numberOfFunctionImportSignatures, "The number of function import signatures is incorrect.");
+}
+
+void WASMModuleParser::parseGlobalSection(ExecState* exec)
+{
+ uint32_t numberOfInternalI32GlobalVariables;
+ uint32_t numberOfInternalF32GlobalVariables;
+ uint32_t numberOfInternalF64GlobalVariables;
+ uint32_t numberOfImportedI32GlobalVariables;
+ uint32_t numberOfImportedF32GlobalVariables;
+ uint32_t numberOfImportedF64GlobalVariables;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfInternalI32GlobalVariables, "Cannot read the number of internal int32 global variables.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfInternalF32GlobalVariables, "Cannot read the number of internal float32 global variables.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfInternalF64GlobalVariables, "Cannot read the number of internal float64 global variables.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfImportedI32GlobalVariables, "Cannot read the number of imported int32 global variables.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfImportedF32GlobalVariables, "Cannot read the number of imported float32 global variables.");
+ READ_COMPACT_UINT32_OR_FAIL(numberOfImportedF64GlobalVariables, "Cannot read the number of imported float64 global variables.");
+ uint32_t numberOfGlobalVariables = numberOfInternalI32GlobalVariables + numberOfInternalF32GlobalVariables + numberOfInternalF64GlobalVariables +
+ numberOfImportedI32GlobalVariables + numberOfImportedF32GlobalVariables + numberOfImportedF64GlobalVariables;
+
+ Vector<WASMType>& globalVariableTypes = m_module->globalVariableTypes();
+ globalVariableTypes.reserveInitialCapacity(numberOfGlobalVariables);
+ Vector<JSWASMModule::GlobalVariable>& globalVariables = m_module->globalVariables();
+ globalVariables.reserveInitialCapacity(numberOfGlobalVariables);
+ for (uint32_t i = 0; i < numberOfInternalI32GlobalVariables; ++i) {
+ globalVariableTypes.uncheckedAppend(WASMType::I32);
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0));
+ }
+ for (uint32_t i = 0; i < numberOfInternalF32GlobalVariables; ++i) {
+ globalVariableTypes.uncheckedAppend(WASMType::F32);
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0.0f));
+ }
+ for (uint32_t i = 0; i < numberOfInternalF64GlobalVariables; ++i) {
+ globalVariableTypes.uncheckedAppend(WASMType::F64);
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0.0));
+ }
+ for (uint32_t i = 0; i < numberOfImportedI32GlobalVariables; ++i) {
+ String importName;
+ READ_STRING_OR_FAIL(importName, "Cannot read the import name of an int32 global variable.");
+ globalVariableTypes.uncheckedAppend(WASMType::I32);
+ JSValue value;
+ getImportedValue(exec, importName, value);
+ PROPAGATE_ERROR();
+ FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol.");
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(value.toInt32(exec)));
+ }
+ for (uint32_t i = 0; i < numberOfImportedF32GlobalVariables; ++i) {
+ String importName;
+ READ_STRING_OR_FAIL(importName, "Cannot read the import name of a float32 global variable.");
+ globalVariableTypes.uncheckedAppend(WASMType::F32);
+ JSValue value;
+ getImportedValue(exec, importName, value);
+ PROPAGATE_ERROR();
+ FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol.");
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(static_cast<float>(value.toNumber(exec))));
+ }
+ for (uint32_t i = 0; i < numberOfImportedF64GlobalVariables; ++i) {
+ String importName;
+ READ_STRING_OR_FAIL(importName, "Cannot read the import name of a float64 global variable.");
+ globalVariableTypes.uncheckedAppend(WASMType::F64);
+ JSValue value;
+ getImportedValue(exec, importName, value);
+ PROPAGATE_ERROR();
+ FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol.");
+ globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(value.toNumber(exec)));
+ }
+}
+
+void WASMModuleParser::parseFunctionDeclarationSection()
+{
+ uint32_t numberOfFunctionDeclarations;
+ 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.");
+ FAIL_IF_FALSE(functionDeclaration.signatureIndex < m_module->signatures().size(), "The signature index is incorrect.");
+ m_module->functionDeclarations().uncheckedAppend(functionDeclaration);
+ }
+}
+
+void WASMModuleParser::parseFunctionPointerTableSection()
+{
+ uint32_t numberOfFunctionPointerTables;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionPointerTables, "Cannot read the number of function pointer tables.");
+ m_module->functionPointerTables().reserveInitialCapacity(numberOfFunctionPointerTables);
+ for (uint32_t i = 0; i < numberOfFunctionPointerTables; ++i) {
+ WASMFunctionPointerTable functionPointerTable;
+ READ_COMPACT_UINT32_OR_FAIL(functionPointerTable.signatureIndex, "Cannot read the signature index.");
+ FAIL_IF_FALSE(functionPointerTable.signatureIndex < m_module->signatures().size(), "The signature index is incorrect.");
+ uint32_t numberOfFunctions;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfFunctions, "Cannot read the number of functions of a function pointer table.");
+ FAIL_IF_FALSE(hasOneBitSet(numberOfFunctions), "The number of functions must be a power of two.");
+ functionPointerTable.functionIndices.reserveInitialCapacity(numberOfFunctions);
+ functionPointerTable.functions.reserveInitialCapacity(numberOfFunctions);
+ for (uint32_t j = 0; j < numberOfFunctions; ++j) {
+ uint32_t functionIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read a function index of a function pointer table.");
+ FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect.");
+ FAIL_IF_FALSE(m_module->functionDeclarations()[functionIndex].signatureIndex == functionPointerTable.signatureIndex, "The signature of the function doesn't match that of the function pointer table.");
+ functionPointerTable.functionIndices.uncheckedAppend(functionIndex);
+ }
+ m_module->functionPointerTables().uncheckedAppend(functionPointerTable);
+ }
+}
+
+void WASMModuleParser::parseFunctionDefinitionSection()
+{
+ for (size_t functionIndex = 0; functionIndex < m_module->functionDeclarations().size(); ++functionIndex) {
+ parseFunctionDefinition(functionIndex);
+ PROPAGATE_ERROR();
+ }
+
+ for (WASMFunctionPointerTable& functionPointerTable : m_module->functionPointerTables()) {
+ for (size_t i = 0; i < functionPointerTable.functionIndices.size(); ++i)
+ functionPointerTable.functions.uncheckedAppend(m_module->functions()[functionPointerTable.functionIndices[i]].get());
+ }
+}
+
+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, stackHeight, errorMessage)) {
+ m_errorMessage = errorMessage;
+ return;
+ }
+ m_reader.setOffset(endOffsetInSource);
+
+ 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()
+{
+ WASMExportFormat exportFormat;
+ READ_EXPORT_FORMAT_OR_FAIL(exportFormat, "Cannot read the export format.");
+ switch (exportFormat) {
+ case WASMExportFormat::Default: {
+ uint32_t functionIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read the function index.");
+ FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect.");
+ // FIXME: Export the function.
+ break;
+ }
+ case WASMExportFormat::Record: {
+ uint32_t numberOfExports;
+ READ_COMPACT_UINT32_OR_FAIL(numberOfExports, "Cannot read the number of exports.");
+ for (uint32_t exportIndex = 0; exportIndex < numberOfExports; ++exportIndex) {
+ String exportName;
+ READ_STRING_OR_FAIL(exportName, "Cannot read the function export name.");
+ uint32_t functionIndex;
+ READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read the function index.");
+ FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect.");
+ Identifier identifier = Identifier::fromString(&m_vm, exportName);
+ m_module->putDirect(m_vm, identifier, m_module->functions()[functionIndex].get());
+ }
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void WASMModuleParser::getImportedValue(ExecState* exec, const String& importName, JSValue& value)
+{
+ FAIL_IF_FALSE(m_imports, "Accessing property of non-object.");
+ Identifier identifier = Identifier::fromString(&m_vm, importName);
+ PropertySlot slot(m_imports.get(), PropertySlot::InternalMethodType::Get);
+ if (!m_imports->getPropertySlot(exec, identifier, slot))
+ FAIL_WITH_MESSAGE("Can't find a property named \"" + importName + '"');
+ FAIL_IF_FALSE(slot.isValue(), "\"" + importName + "\" is not a data property.");
+ // We only retrieve data properties. So, this does not cause any user-observable effect.
+ value = slot.getValue(exec, identifier);
+}
+
+JSWASMModule* parseWebAssembly(ExecState* exec, const SourceCode& source, JSObject* imports, JSArrayBuffer* arrayBuffer, String& errorMessage)
+{
+ WASMModuleParser moduleParser(exec->vm(), exec->lexicalGlobalObject(), source, imports, arrayBuffer);
+ return moduleParser.parse(exec, errorMessage);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WASMModuleParser.h b/Source/JavaScriptCore/wasm/WASMModuleParser.h
new file mode 100644
index 000000000..5017bc1ce
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMModuleParser.h
@@ -0,0 +1,77 @@
+/*
+ * 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 WASMModuleParser_h
+#define WASMModuleParser_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "Strong.h"
+#include "WASMReader.h"
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class ExecState;
+class JSArrayBuffer;
+class JSGlobalObject;
+class JSWASMModule;
+class SourceCode;
+class VM;
+
+class WASMModuleParser {
+public:
+ WASMModuleParser(VM&, JSGlobalObject*, const SourceCode&, JSObject* imports, JSArrayBuffer*);
+ JSWASMModule* parse(ExecState*, String& errorMessage);
+
+private:
+ void parseModule(ExecState*);
+ void parseConstantPoolSection();
+ void parseSignatureSection();
+ void parseFunctionImportSection(ExecState*);
+ void parseGlobalSection(ExecState*);
+ void parseFunctionDeclarationSection();
+ void parseFunctionPointerTableSection();
+ void parseFunctionDefinitionSection();
+ void parseFunctionDefinition(size_t functionIndex);
+ void parseExportSection();
+ void getImportedValue(ExecState*, const String& importName, JSValue&);
+
+ VM& m_vm;
+ Strong<JSGlobalObject> m_globalObject;
+ const SourceCode& m_source;
+ Strong<JSObject> m_imports;
+ WASMReader m_reader;
+ Strong<JSWASMModule> m_module;
+ String m_errorMessage;
+};
+
+JS_EXPORT_PRIVATE JSWASMModule* parseWebAssembly(ExecState*, const SourceCode&, JSObject* imports, JSArrayBuffer*, String& errorMessage);
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMModuleParser_h
diff --git a/Source/JavaScriptCore/wasm/WASMReader.cpp b/Source/JavaScriptCore/wasm/WASMReader.cpp
new file mode 100644
index 000000000..f6ac8e2fc
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMReader.cpp
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ * =========================================================================
+ *
+ * Copyright (c) 2015 by the repository authors of
+ * WebAssembly/polyfill-prototype-1.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "WASMReader.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include <wtf/text/StringBuilder.h>
+
+#define CHECK_READ(length) do { if (m_cursor + length > m_buffer.end()) return false; } while (0)
+
+namespace JSC {
+
+bool WASMReader::readUInt32(uint32_t& result)
+{
+ CHECK_READ(4);
+ result = m_cursor[0] | m_cursor[1] << 8 | m_cursor[2] << 16 | m_cursor[3] << 24;
+ m_cursor += 4;
+ return true;
+}
+
+bool WASMReader::readFloat(float& result)
+{
+ CHECK_READ(4);
+ union {
+ uint8_t bytes[4];
+ float floatValue;
+ } u = {
+#if CPU(BIG_ENDIAN)
+ { m_cursor[3], m_cursor[2], m_cursor[1], m_cursor[0] }
+#else
+ { m_cursor[0], m_cursor[1], m_cursor[2], m_cursor[3] }
+#endif
+ };
+ result = u.floatValue;
+ m_cursor += 4;
+ return true;
+}
+
+bool WASMReader::readDouble(double& result)
+{
+ CHECK_READ(8);
+ union {
+ uint8_t bytes[8];
+ double doubleValue;
+ } u = {
+#if CPU(BIG_ENDIAN)
+ { m_cursor[7], m_cursor[6], m_cursor[5], m_cursor[4], m_cursor[3], m_cursor[2], m_cursor[1], m_cursor[0] }
+#else
+ { m_cursor[0], m_cursor[1], m_cursor[2], m_cursor[3], m_cursor[4], m_cursor[5], m_cursor[6], m_cursor[7] }
+#endif
+ };
+ result = u.doubleValue;
+ m_cursor += 8;
+ return true;
+}
+
+bool WASMReader::readCompactInt32(uint32_t& result)
+{
+ uint32_t sum = 0;
+ unsigned shift = 0;
+ do {
+ CHECK_READ(1);
+ uint8_t byte = *m_cursor++;
+ if (byte < 0x80) {
+ sum |= byte << shift;
+ int signExtend = (32 - 7) - shift;
+ if (signExtend > 0)
+ result = int32_t(sum) << signExtend >> signExtend;
+ else
+ result = int32_t(sum);
+ return true;
+ }
+ sum |= (byte & firstSevenBitsMask) << shift;
+ shift += 7;
+ } while (shift < 35);
+ return false;
+}
+
+bool WASMReader::readCompactUInt32(uint32_t& result)
+{
+ uint32_t sum = 0;
+ unsigned shift = 0;
+ do {
+ CHECK_READ(1);
+ uint32_t byte = *m_cursor++;
+ if (byte < 0x80) {
+ if ((shift == 28 && byte >= 0x10) || (shift && !byte))
+ return false;
+ result = sum | (byte << shift);
+ return true;
+ }
+ sum |= (byte & firstSevenBitsMask) << shift;
+ shift += 7;
+ } while (shift < 35);
+ return false;
+}
+
+bool WASMReader::readString(String& result)
+{
+ StringBuilder builder;
+ while (true) {
+ CHECK_READ(1);
+ char c = *m_cursor++;
+ if (!c)
+ break;
+ builder.append(c);
+ }
+ result = builder.toString();
+ return true;
+}
+
+bool WASMReader::readType(WASMType& result)
+{
+ return readByte<WASMType>(result, static_cast<uint8_t>(WASMType::NumberOfTypes));
+}
+
+bool WASMReader::readExpressionType(WASMExpressionType& result)
+{
+ return readByte<WASMExpressionType>(result, static_cast<uint8_t>(WASMExpressionType::NumberOfExpressionTypes));
+}
+
+bool WASMReader::readExportFormat(WASMExportFormat& result)
+{
+ return readByte<WASMExportFormat>(result, static_cast<uint8_t>(WASMExportFormat::NumberOfExportFormats));
+}
+
+template <class T> bool WASMReader::readByte(T& result, uint8_t numberOfValues)
+{
+ CHECK_READ(1);
+ uint8_t byte = *m_cursor++;
+ if (byte >= numberOfValues)
+ return false;
+ result = T(byte);
+ return true;
+}
+
+bool WASMReader::readOpStatement(bool& hasImmediate, WASMOpStatement& op, WASMOpStatementWithImmediate& opWithImmediate, uint8_t& immediate)
+{
+ return readOp(hasImmediate, op, opWithImmediate, immediate,
+ static_cast<uint8_t>(WASMOpStatement::NumberOfWASMOpStatements),
+ static_cast<uint8_t>(WASMOpStatementWithImmediate::NumberOfWASMOpStatementWithImmediates));
+}
+
+bool WASMReader::readOpExpressionI32(bool& hasImmediate, WASMOpExpressionI32& op, WASMOpExpressionI32WithImmediate& opWithImmediate, uint8_t& immediate)
+{
+ return readOp(hasImmediate, op, opWithImmediate, immediate,
+ static_cast<uint8_t>(WASMOpExpressionI32::NumberOfWASMOpExpressionI32s),
+ static_cast<uint8_t>(WASMOpExpressionI32WithImmediate::NumberOfWASMOpExpressionI32WithImmediates));
+}
+
+bool WASMReader::readOpExpressionF32(bool& hasImmediate, WASMOpExpressionF32& op, WASMOpExpressionF32WithImmediate& opWithImmediate, uint8_t& immediate)
+{
+ return readOp(hasImmediate, op, opWithImmediate, immediate,
+ static_cast<uint8_t>(WASMOpExpressionF32::NumberOfWASMOpExpressionF32s),
+ static_cast<uint8_t>(WASMOpExpressionF32WithImmediate::NumberOfWASMOpExpressionF32WithImmediates));
+}
+
+bool WASMReader::readOpExpressionF64(bool& hasImmediate, WASMOpExpressionF64& op, WASMOpExpressionF64WithImmediate& opWithImmediate, uint8_t& immediate)
+{
+ return readOp(hasImmediate, op, opWithImmediate, immediate,
+ static_cast<uint8_t>(WASMOpExpressionF64::NumberOfWASMOpExpressionF64s),
+ static_cast<uint8_t>(WASMOpExpressionF64WithImmediate::NumberOfWASMOpExpressionF64WithImmediates));
+}
+
+bool WASMReader::readOpExpressionVoid(WASMOpExpressionVoid& op)
+{
+ return readByte<WASMOpExpressionVoid>(op,
+ static_cast<uint8_t>(WASMOpExpressionVoid::NumberOfWASMOpExpressionVoids));
+}
+
+bool WASMReader::readVariableTypes(bool& hasImmediate, WASMVariableTypes& variableTypes, WASMVariableTypesWithImmediate& variableTypesWithImmediate, uint8_t& immediate)
+{
+ return readOp(hasImmediate, variableTypes, variableTypesWithImmediate, immediate,
+ static_cast<uint8_t>(WASMVariableTypes::NumberOfVariableTypes),
+ static_cast<uint8_t>(WASMVariableTypesWithImmediate::NumberOfVariableTypesWithImmediates));
+}
+
+template <class T, class TWithImmediate>
+bool WASMReader::readOp(bool& hasImmediate, T& op, TWithImmediate& opWithImmediate, uint8_t& immediate, uint8_t numberOfValues, uint8_t numberOfValuesWithImmediate)
+{
+ CHECK_READ(1);
+ uint8_t byte = *m_cursor++;
+
+ if (!(byte & hasImmediateInOpFlag)) {
+ if (byte >= numberOfValues)
+ return false;
+ hasImmediate = false;
+ op = T(byte);
+ return true;
+ }
+
+ uint8_t byteWithoutImmediate = (byte >> immediateBits) & (opWithImmediateLimit - 1);
+ if (byteWithoutImmediate >= numberOfValuesWithImmediate)
+ return false;
+ hasImmediate = true;
+ opWithImmediate = TWithImmediate(byteWithoutImmediate);
+ immediate = byte & (immediateLimit - 1);
+ return true;
+}
+
+bool WASMReader::readSwitchCase(WASMSwitchCase& result)
+{
+ return readByte<WASMSwitchCase>(result, static_cast<uint8_t>(WASMSwitchCase::NumberOfSwitchCases));
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WASMReader.h b/Source/JavaScriptCore/wasm/WASMReader.h
new file mode 100644
index 000000000..83dc29681
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WASMReader.h
@@ -0,0 +1,79 @@
+/*
+ * 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 WASMReader_h
+#define WASMReader_h
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "WASMConstants.h"
+#include "WASMFormat.h"
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class WASMReader {
+public:
+ WASMReader(const Vector<uint8_t>& buffer)
+ : m_buffer(buffer)
+ , m_cursor(buffer.data())
+ {
+ }
+
+ unsigned offset() const { return m_cursor - m_buffer.data(); }
+ void setOffset(unsigned offset) { m_cursor = m_buffer.data() + offset; }
+
+ bool readUInt32(uint32_t& result);
+ bool readFloat(float& result);
+ bool readDouble(double& result);
+ bool readCompactInt32(uint32_t& result);
+ bool readCompactUInt32(uint32_t& result);
+ bool readString(String& result);
+ bool readType(WASMType& result);
+ bool readExpressionType(WASMExpressionType& result);
+ bool readExportFormat(WASMExportFormat& result);
+ bool readOpStatement(bool& hasImmediate, WASMOpStatement&, WASMOpStatementWithImmediate&, uint8_t& immediate);
+ bool readOpExpressionI32(bool& hasImmediate, WASMOpExpressionI32&, WASMOpExpressionI32WithImmediate&, uint8_t& immediate);
+ bool readOpExpressionF32(bool& hasImmediate, WASMOpExpressionF32&, WASMOpExpressionF32WithImmediate&, uint8_t& immediate);
+ bool readOpExpressionF64(bool& hasImmediate, WASMOpExpressionF64&, WASMOpExpressionF64WithImmediate&, uint8_t& immediate);
+ bool readOpExpressionVoid(WASMOpExpressionVoid&);
+ bool readVariableTypes(bool& hasImmediate, WASMVariableTypes&, WASMVariableTypesWithImmediate&, uint8_t& immediate);
+ bool readSwitchCase(WASMSwitchCase& result);
+
+private:
+ static const uint32_t firstSevenBitsMask = 0x7f;
+
+ template <class T> bool readByte(T& result, uint8_t numberOfValues);
+ template <class T, class TWithImmediate> bool readOp(bool& hasImmediate, T&, TWithImmediate&, uint8_t& immediate, uint8_t numberOfValues, uint8_t numberOfValuesWithImmediate);
+
+ const Vector<uint8_t>& m_buffer;
+ const uint8_t* m_cursor;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
+
+#endif // WASMReader_h