1/*
2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(WEBASSEMBLY)
29
30#include "B3Type.h"
31#include "CodeLocation.h"
32#include "Identifier.h"
33#include "MacroAssemblerCodeRef.h"
34#include "RegisterAtOffsetList.h"
35#include "WasmMemoryInformation.h"
36#include "WasmName.h"
37#include "WasmNameSection.h"
38#include "WasmOps.h"
39#include "WasmPageCount.h"
40#include "WasmSignature.h"
41#include <limits>
42#include <memory>
43#include <wtf/Optional.h>
44#include <wtf/Vector.h>
45
46namespace JSC {
47
48namespace B3 {
49class Compilation;
50}
51
52namespace Wasm {
53
54struct CompilationContext;
55struct ModuleInformation;
56
57enum class TableElementType : uint8_t {
58 Anyref,
59 Funcref
60};
61
62inline bool isValueType(Type type)
63{
64 switch (type) {
65 case I32:
66 case I64:
67 case F32:
68 case F64:
69 return true;
70 case Anyref:
71 return Options::useWebAssemblyReferences();
72 default:
73 break;
74 }
75 return false;
76}
77
78enum class ExternalKind : uint8_t {
79 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
80 Function = 0,
81 Table = 1,
82 Memory = 2,
83 Global = 3,
84};
85
86template<typename Int>
87inline bool isValidExternalKind(Int val)
88{
89 switch (val) {
90 case static_cast<Int>(ExternalKind::Function):
91 case static_cast<Int>(ExternalKind::Table):
92 case static_cast<Int>(ExternalKind::Memory):
93 case static_cast<Int>(ExternalKind::Global):
94 return true;
95 }
96 return false;
97}
98
99static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
100static_assert(static_cast<int>(ExternalKind::Table) == 1, "Wasm needs Table to have the value 1");
101static_assert(static_cast<int>(ExternalKind::Memory) == 2, "Wasm needs Memory to have the value 2");
102static_assert(static_cast<int>(ExternalKind::Global) == 3, "Wasm needs Global to have the value 3");
103
104inline const char* makeString(ExternalKind kind)
105{
106 switch (kind) {
107 case ExternalKind::Function: return "function";
108 case ExternalKind::Table: return "table";
109 case ExternalKind::Memory: return "memory";
110 case ExternalKind::Global: return "global";
111 }
112 RELEASE_ASSERT_NOT_REACHED();
113 return "?";
114}
115
116struct Import {
117 const Name module;
118 const Name field;
119 ExternalKind kind;
120 unsigned kindIndex; // Index in the vector of the corresponding kind.
121};
122
123struct Export {
124 const Name field;
125 ExternalKind kind;
126 unsigned kindIndex; // Index in the vector of the corresponding kind.
127};
128
129String makeString(const Name& characters);
130
131struct Global {
132 enum Mutability : uint8_t {
133 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
134 Mutable = 1,
135 Immutable = 0
136 };
137
138 enum InitializationType {
139 IsImport,
140 FromGlobalImport,
141 FromExpression
142 };
143
144 Mutability mutability;
145 Type type;
146 InitializationType initializationType { IsImport };
147 uint64_t initialBitsOrImportNumber { 0 };
148};
149
150struct FunctionData {
151 size_t start;
152 size_t end;
153 Vector<uint8_t> data;
154};
155
156class I32InitExpr {
157 enum Type : uint8_t {
158 Global,
159 Const
160 };
161
162 I32InitExpr(Type type, uint32_t bits)
163 : m_bits(bits)
164 , m_type(type)
165 { }
166
167public:
168 I32InitExpr() = delete;
169
170 static I32InitExpr globalImport(uint32_t globalImportNumber) { return I32InitExpr(Global, globalImportNumber); }
171 static I32InitExpr constValue(uint32_t constValue) { return I32InitExpr(Const, constValue); }
172
173 bool isConst() const { return m_type == Const; }
174 bool isGlobalImport() const { return m_type == Global; }
175 uint32_t constValue() const
176 {
177 RELEASE_ASSERT(isConst());
178 return m_bits;
179 }
180 uint32_t globalImportIndex() const
181 {
182 RELEASE_ASSERT(isGlobalImport());
183 return m_bits;
184 }
185
186private:
187 uint32_t m_bits;
188 Type m_type;
189};
190
191struct Segment {
192 uint32_t sizeInBytes;
193 I32InitExpr offset;
194 // Bytes are allocated at the end.
195 uint8_t& byte(uint32_t pos)
196 {
197 ASSERT(pos < sizeInBytes);
198 return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(Segment) + pos);
199 }
200 static Segment* create(I32InitExpr, uint32_t);
201 static void destroy(Segment*);
202 typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
203 static Ptr adoptPtr(Segment*);
204};
205
206struct Element {
207 Element(I32InitExpr offset)
208 : offset(offset)
209 { }
210
211 I32InitExpr offset;
212 Vector<uint32_t> functionIndices;
213};
214
215class TableInformation {
216public:
217 TableInformation()
218 {
219 ASSERT(!*this);
220 }
221
222 TableInformation(uint32_t initial, Optional<uint32_t> maximum, bool isImport, TableElementType type)
223 : m_initial(initial)
224 , m_maximum(maximum)
225 , m_isImport(isImport)
226 , m_isValid(true)
227 , m_type(type)
228 {
229 ASSERT(*this);
230 }
231
232 explicit operator bool() const { return m_isValid; }
233 bool isImport() const { return m_isImport; }
234 uint32_t initial() const { return m_initial; }
235 Optional<uint32_t> maximum() const { return m_maximum; }
236 TableElementType type() const { return m_type; }
237
238private:
239 uint32_t m_initial;
240 Optional<uint32_t> m_maximum;
241 bool m_isImport { false };
242 bool m_isValid { false };
243 TableElementType m_type;
244};
245
246struct CustomSection {
247 Name name;
248 Vector<uint8_t> payload;
249};
250
251enum class NameType : uint8_t {
252 Module = 0,
253 Function = 1,
254 Local = 2,
255};
256
257template<typename Int>
258inline bool isValidNameType(Int val)
259{
260 switch (val) {
261 case static_cast<Int>(NameType::Module):
262 case static_cast<Int>(NameType::Function):
263 case static_cast<Int>(NameType::Local):
264 return true;
265 }
266 return false;
267}
268
269struct UnlinkedWasmToWasmCall {
270 CodeLocationNearCall<WasmEntryPtrTag> callLocation;
271 size_t functionIndexSpace;
272};
273
274struct Entrypoint {
275 std::unique_ptr<B3::Compilation> compilation;
276 RegisterAtOffsetList calleeSaveRegisters;
277};
278
279struct InternalFunction {
280 CodeLocationDataLabelPtr<WasmEntryPtrTag> calleeMoveLocation;
281 Entrypoint entrypoint;
282};
283
284// WebAssembly direct calls and call_indirect use indices into "function index space". This space starts
285// with all imports, and then all internal functions. WasmToWasmImportableFunction and FunctionIndexSpace are only
286// meant as fast lookup tables for these opcodes and do not own code.
287struct WasmToWasmImportableFunction {
288 using LoadLocation = MacroAssemblerCodePtr<WasmEntryPtrTag>*;
289 static ptrdiff_t offsetOfSignatureIndex() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, signatureIndex); }
290 static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, entrypointLoadLocation); }
291
292 // FIXME: Pack signature index and code pointer into one 64-bit value. See <https://bugs.webkit.org/show_bug.cgi?id=165511>.
293 SignatureIndex signatureIndex { Signature::invalidIndex };
294 LoadLocation entrypointLoadLocation;
295};
296using FunctionIndexSpace = Vector<WasmToWasmImportableFunction>;
297
298} } // namespace JSC::Wasm
299
300#endif // ENABLE(WEBASSEMBLY)
301