/* * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #if ENABLE(WEBASSEMBLY) #include "B3Compilation.h" #include "B3Type.h" #include "CodeLocation.h" #include "Identifier.h" #include "MacroAssemblerCodeRef.h" #include "RegisterAtOffsetList.h" #include "WasmMemoryInformation.h" #include "WasmOps.h" #include "WasmPageCount.h" #include "WasmSignature.h" #include #include #include #include namespace JSC { class JSFunction; namespace Wasm { inline bool isValueType(Type type) { switch (type) { case I32: case I64: case F32: case F64: return true; default: break; } return false; } enum class ExternalKind : uint8_t { // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231 Function = 0, Table = 1, Memory = 2, Global = 3, }; template static bool isValidExternalKind(Int val) { switch (val) { case static_cast(ExternalKind::Function): case static_cast(ExternalKind::Table): case static_cast(ExternalKind::Memory): case static_cast(ExternalKind::Global): return true; default: return false; } } static_assert(static_cast(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0"); static_assert(static_cast(ExternalKind::Table) == 1, "Wasm needs Table to have the value 1"); static_assert(static_cast(ExternalKind::Memory) == 2, "Wasm needs Memory to have the value 2"); static_assert(static_cast(ExternalKind::Global) == 3, "Wasm needs Global to have the value 3"); static inline const char* makeString(ExternalKind kind) { switch (kind) { case ExternalKind::Function: return "Function"; case ExternalKind::Table: return "Table"; case ExternalKind::Memory: return "Memory"; case ExternalKind::Global: return "Global"; } RELEASE_ASSERT_NOT_REACHED(); return "?"; } struct Import { Identifier module; Identifier field; ExternalKind kind; unsigned kindIndex; // Index in the vector of the corresponding kind. }; struct Export { Identifier field; ExternalKind kind; unsigned kindIndex; // Index in the vector of the corresponding kind. }; struct Global { enum Mutability : uint8_t { // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231 Mutable = 1, Immutable = 0 }; enum InitializationType { IsImport, FromGlobalImport, FromExpression }; Mutability mutability; Type type; InitializationType initializationType { IsImport }; uint64_t initialBitsOrImportNumber { 0 }; }; struct FunctionLocationInBinary { size_t start; size_t end; }; class I32InitExpr { enum Type : uint8_t { Global, Const }; I32InitExpr(Type type, uint32_t bits) : m_bits(bits) , m_type(type) { } public: I32InitExpr() = delete; static I32InitExpr globalImport(uint32_t globalImportNumber) { return I32InitExpr(Global, globalImportNumber); } static I32InitExpr constValue(uint32_t constValue) { return I32InitExpr(Const, constValue); } bool isConst() const { return m_type == Const; } bool isGlobalImport() const { return m_type == Global; } uint32_t constValue() const { RELEASE_ASSERT(isConst()); return m_bits; } uint32_t globalImportIndex() const { RELEASE_ASSERT(isGlobalImport()); return m_bits; } private: uint32_t m_bits; Type m_type; }; struct Segment { uint32_t sizeInBytes; I32InitExpr offset; // Bytes are allocated at the end. uint8_t& byte(uint32_t pos) { ASSERT(pos < sizeInBytes); return *reinterpret_cast(reinterpret_cast(this) + sizeof(Segment) + pos); } static Segment* create(I32InitExpr, uint32_t); static void destroy(Segment*); typedef std::unique_ptr Ptr; static Ptr adoptPtr(Segment*); }; struct Element { uint32_t offset; Vector functionIndices; }; class TableInformation { public: TableInformation() { ASSERT(!*this); } TableInformation(uint32_t initial, std::optional maximum, bool isImport) : m_initial(initial) , m_maximum(maximum) , m_isImport(isImport) , m_isValid(true) { ASSERT(*this); } explicit operator bool() const { return m_isValid; } bool isImport() const { return m_isImport; } uint32_t initial() const { return m_initial; } std::optional maximum() const { return m_maximum; } private: uint32_t m_initial; std::optional m_maximum; bool m_isImport { false }; bool m_isValid { false }; }; struct CustomSection { String name; Vector payload; }; struct ModuleInformation { Vector imports; Vector importFunctionSignatureIndices; Vector internalFunctionSignatureIndices; MemoryInformation memory; Vector exports; std::optional startFunctionIndexSpace; Vector data; Vector elements; TableInformation tableInformation; Vector globals; unsigned firstInternalGlobal { 0 }; Vector customSections; size_t functionIndexSpaceSize() const { return importFunctionSignatureIndices.size() + internalFunctionSignatureIndices.size(); } bool isImportedFunctionFromFunctionIndexSpace(size_t functionIndex) const { ASSERT(functionIndex < functionIndexSpaceSize()); return functionIndex < importFunctionSignatureIndices.size(); } SignatureIndex signatureIndexFromFunctionIndexSpace(size_t functionIndex) const { return isImportedFunctionFromFunctionIndexSpace(functionIndex) ? importFunctionSignatureIndices[functionIndex] : internalFunctionSignatureIndices[functionIndex - importFunctionSignatureIndices.size()]; } uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); } bool hasMemory() const { return !!memory; } ~ModuleInformation(); }; struct UnlinkedWasmToWasmCall { CodeLocationCall callLocation; size_t functionIndex; enum class Target : uint8_t { ToJs, ToWasm, } target; }; struct Entrypoint { std::unique_ptr compilation; RegisterAtOffsetList calleeSaveRegisters; }; struct WasmInternalFunction { CodeLocationDataLabelPtr wasmCalleeMoveLocation; CodeLocationDataLabelPtr jsToWasmCalleeMoveLocation; Entrypoint wasmEntrypoint; Entrypoint jsToWasmEntrypoint; }; struct WasmExitStubs { MacroAssemblerCodeRef wasmToJs; MacroAssemblerCodeRef wasmToWasm; }; // WebAssembly direct calls and call_indirect use indices into "function index space". This space starts with all imports, and then all internal functions. // CallableFunction and FunctionIndexSpace are only meant as fast lookup tables for these opcodes, and do not own code. struct CallableFunction { CallableFunction() = default; CallableFunction(SignatureIndex signatureIndex, void* code = nullptr) : signatureIndex(signatureIndex) , code(code) { } // FIXME pack the SignatureIndex and the code pointer into one 64-bit value. https://bugs.webkit.org/show_bug.cgi?id=165511 SignatureIndex signatureIndex { Signature::invalidIndex }; void* code { nullptr }; }; typedef Vector FunctionIndexSpace; } } // namespace JSC::Wasm #endif // ENABLE(WEBASSEMBLY)