/* * Copyright (C) 2015-2018 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 "B3Type.h" #include "CodeLocation.h" #include "Identifier.h" #include "MacroAssemblerCodeRef.h" #include "RegisterAtOffsetList.h" #include "WasmMemoryInformation.h" #include "WasmName.h" #include "WasmNameSection.h" #include "WasmOps.h" #include "WasmPageCount.h" #include "WasmSignature.h" #include #include #include #include #include namespace JSC { namespace B3 { class Compilation; } namespace Wasm { struct CompilationContext; struct ModuleInformation; using BlockSignature = const Signature*; enum class TableElementType : uint8_t { Externref, Funcref }; inline bool isValueType(Type type) { switch (type) { case I32: case I64: case F32: case F64: return true; case Externref: case Funcref: return Options::useWebAssemblyReferences(); default: break; } return false; } inline bool isRefType(Type type) { return type == Externref || type == Funcref; } 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 inline 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; } 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"); 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 { WTF_MAKE_STRUCT_FAST_ALLOCATED; const Name module; const Name field; ExternalKind kind; unsigned kindIndex; // Index in the vector of the corresponding kind. }; struct Export { WTF_MAKE_STRUCT_FAST_ALLOCATED; const Name field; ExternalKind kind; unsigned kindIndex; // Index in the vector of the corresponding kind. }; String makeString(const Name& characters); struct GlobalInformation { WTF_MAKE_STRUCT_FAST_ALLOCATED; enum Mutability : uint8_t { // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231 Mutable = 1, Immutable = 0 }; enum InitializationType : uint8_t { IsImport, FromGlobalImport, FromRefFunc, FromExpression }; enum class BindingMode : uint8_t { EmbeddedInInstance = 0, Portable, }; Mutability mutability; Type type; InitializationType initializationType { IsImport }; BindingMode bindingMode { BindingMode::EmbeddedInInstance }; uint64_t initialBitsOrImportNumber { 0 }; }; struct FunctionData { WTF_MAKE_STRUCT_FAST_ALLOCATED; size_t start; size_t end; Vector data; }; class I32InitExpr { WTF_MAKE_FAST_ALLOCATED; 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 { WTF_MAKE_STRUCT_FAST_ALLOCATED; enum class Kind : uint8_t { Active, Passive, }; Kind kind; uint32_t sizeInBytes; Optional offsetIfActive; // 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 void destroy(Segment*); typedef std::unique_ptr Ptr; static Segment::Ptr create(Optional, uint32_t, Kind); bool isActive() const { return kind == Kind::Active; } bool isPassive() const { return kind == Kind::Passive; } }; struct Element { WTF_MAKE_STRUCT_FAST_ALLOCATED; // nullFuncIndex represents the case when an element segment (of type funcref) // contains a null element. constexpr static uint32_t nullFuncIndex = UINT32_MAX; enum class Kind : uint8_t { Active, Passive, Declared, }; Element(Element::Kind kind, TableElementType elementType, Optional tableIndex, Optional initExpr) : kind(kind) , elementType(elementType) , tableIndexIfActive(WTFMove(tableIndex)) , offsetIfActive(WTFMove(initExpr)) { } Element(Element::Kind kind, TableElementType elemType) : Element(kind, elemType, WTF::nullopt, WTF::nullopt) { } uint32_t length() const { return functionIndices.size(); } bool isActive() const { return kind == Kind::Active; } bool isPassive() const { return kind == Kind::Passive; } static bool isNullFuncIndex(uint32_t idx) { return idx == nullFuncIndex; } Kind kind; TableElementType elementType; Optional tableIndexIfActive; Optional offsetIfActive; // Index may be nullFuncIndex. Vector functionIndices; }; class TableInformation { WTF_MAKE_FAST_ALLOCATED; public: TableInformation() { ASSERT(!*this); } TableInformation(uint32_t initial, Optional maximum, bool isImport, TableElementType type) : m_initial(initial) , m_maximum(maximum) , m_isImport(isImport) , m_isValid(true) , m_type(type) { ASSERT(*this); } explicit operator bool() const { return m_isValid; } bool isImport() const { return m_isImport; } uint32_t initial() const { return m_initial; } Optional maximum() const { return m_maximum; } TableElementType type() const { return m_type; } Wasm::Type wasmType() const { return m_type == TableElementType::Funcref ? Type::Funcref : Type::Externref; } private: uint32_t m_initial; Optional m_maximum; bool m_isImport { false }; bool m_isValid { false }; TableElementType m_type; }; struct CustomSection { WTF_MAKE_STRUCT_FAST_ALLOCATED; Name name; Vector payload; }; enum class NameType : uint8_t { Module = 0, Function = 1, Local = 2, }; template inline bool isValidNameType(Int val) { switch (val) { case static_cast(NameType::Module): case static_cast(NameType::Function): case static_cast(NameType::Local): return true; } return false; } struct UnlinkedWasmToWasmCall { WTF_MAKE_STRUCT_FAST_ALLOCATED; CodeLocationNearCall callLocation; size_t functionIndexSpace; }; struct Entrypoint { WTF_MAKE_STRUCT_FAST_ALLOCATED; std::unique_ptr compilation; RegisterAtOffsetList calleeSaveRegisters; }; struct InternalFunction { WTF_MAKE_STRUCT_FAST_ALLOCATED; CodeLocationDataLabelPtr calleeMoveLocation; Entrypoint entrypoint; }; // WebAssembly direct calls and call_indirect use indices into "function index space". This space starts // with all imports, and then all internal functions. WasmToWasmImportableFunction and FunctionIndexSpace are only // meant as fast lookup tables for these opcodes and do not own code. struct WasmToWasmImportableFunction { WTF_MAKE_STRUCT_FAST_ALLOCATED; using LoadLocation = MacroAssemblerCodePtr*; static ptrdiff_t offsetOfSignatureIndex() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, signatureIndex); } static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, entrypointLoadLocation); } // FIXME: Pack signature index and code pointer into one 64-bit value. See . SignatureIndex signatureIndex { Signature::invalidIndex }; LoadLocation entrypointLoadLocation; }; using FunctionIndexSpace = Vector; } } // namespace JSC::Wasm #endif // ENABLE(WEBASSEMBLY)