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
57using BlockSignature = const Signature*;
58
59enum class TableElementType : uint8_t {
60 Anyref,
61 Funcref
62};
63
64inline bool isValueType(Type type)
65{
66 switch (type) {
67 case I32:
68 case I64:
69 case F32:
70 case F64:
71 return true;
72 case Anyref:
73 case Funcref:
74 return Options::useWebAssemblyReferences();
75 default:
76 break;
77 }
78 return false;
79}
80
81inline bool isSubtype(Type sub, Type parent)
82{
83 if (sub == parent)
84 return true;
85 return sub == Funcref && parent == Anyref;
86}
87
88enum class ExternalKind : uint8_t {
89 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
90 Function = 0,
91 Table = 1,
92 Memory = 2,
93 Global = 3,
94};
95
96template<typename Int>
97inline bool isValidExternalKind(Int val)
98{
99 switch (val) {
100 case static_cast<Int>(ExternalKind::Function):
101 case static_cast<Int>(ExternalKind::Table):
102 case static_cast<Int>(ExternalKind::Memory):
103 case static_cast<Int>(ExternalKind::Global):
104 return true;
105 }
106 return false;
107}
108
109static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
110static_assert(static_cast<int>(ExternalKind::Table) == 1, "Wasm needs Table to have the value 1");
111static_assert(static_cast<int>(ExternalKind::Memory) == 2, "Wasm needs Memory to have the value 2");
112static_assert(static_cast<int>(ExternalKind::Global) == 3, "Wasm needs Global to have the value 3");
113
114inline const char* makeString(ExternalKind kind)
115{
116 switch (kind) {
117 case ExternalKind::Function: return "function";
118 case ExternalKind::Table: return "table";
119 case ExternalKind::Memory: return "memory";
120 case ExternalKind::Global: return "global";
121 }
122 RELEASE_ASSERT_NOT_REACHED();
123 return "?";
124}
125
126struct Import {
127 WTF_MAKE_STRUCT_FAST_ALLOCATED;
128 const Name module;
129 const Name field;
130 ExternalKind kind;
131 unsigned kindIndex; // Index in the vector of the corresponding kind.
132};
133
134struct Export {
135 WTF_MAKE_STRUCT_FAST_ALLOCATED;
136 const Name field;
137 ExternalKind kind;
138 unsigned kindIndex; // Index in the vector of the corresponding kind.
139};
140
141String makeString(const Name& characters);
142
143struct Global {
144 WTF_MAKE_STRUCT_FAST_ALLOCATED;
145 enum Mutability : uint8_t {
146 // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
147 Mutable = 1,
148 Immutable = 0
149 };
150
151 enum InitializationType {
152 IsImport,
153 FromGlobalImport,
154 FromRefFunc,
155 FromExpression
156 };
157
158 Mutability mutability;
159 Type type;
160 InitializationType initializationType { IsImport };
161 uint64_t initialBitsOrImportNumber { 0 };
162};
163
164struct FunctionData {
165 WTF_MAKE_STRUCT_FAST_ALLOCATED;
166 size_t start;
167 size_t end;
168 Vector<uint8_t> data;
169};
170
171class I32InitExpr {
172 WTF_MAKE_FAST_ALLOCATED;
173 enum Type : uint8_t {
174 Global,
175 Const
176 };
177
178 I32InitExpr(Type type, uint32_t bits)
179 : m_bits(bits)
180 , m_type(type)
181 { }
182
183public:
184 I32InitExpr() = delete;
185
186 static I32InitExpr globalImport(uint32_t globalImportNumber) { return I32InitExpr(Global, globalImportNumber); }
187 static I32InitExpr constValue(uint32_t constValue) { return I32InitExpr(Const, constValue); }
188
189 bool isConst() const { return m_type == Const; }
190 bool isGlobalImport() const { return m_type == Global; }
191 uint32_t constValue() const
192 {
193 RELEASE_ASSERT(isConst());
194 return m_bits;
195 }
196 uint32_t globalImportIndex() const
197 {
198 RELEASE_ASSERT(isGlobalImport());
199 return m_bits;
200 }
201
202private:
203 uint32_t m_bits;
204 Type m_type;
205};
206
207struct Segment {
208 WTF_MAKE_STRUCT_FAST_ALLOCATED;
209 uint32_t sizeInBytes;
210 I32InitExpr offset;
211 // Bytes are allocated at the end.
212 uint8_t& byte(uint32_t pos)
213 {
214 ASSERT(pos < sizeInBytes);
215 return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(Segment) + pos);
216 }
217 static Segment* create(I32InitExpr, uint32_t);
218 static void destroy(Segment*);
219 typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
220 static Ptr adoptPtr(Segment*);
221};
222
223struct Element {
224 WTF_MAKE_STRUCT_FAST_ALLOCATED;
225 Element(uint32_t tableIndex, I32InitExpr offset)
226 : tableIndex(tableIndex)
227 , offset(offset)
228 { }
229
230 uint32_t tableIndex;
231 I32InitExpr offset;
232 Vector<uint32_t> functionIndices;
233};
234
235class TableInformation {
236 WTF_MAKE_FAST_ALLOCATED;
237public:
238 TableInformation()
239 {
240 ASSERT(!*this);
241 }
242
243 TableInformation(uint32_t initial, Optional<uint32_t> maximum, bool isImport, TableElementType type)
244 : m_initial(initial)
245 , m_maximum(maximum)
246 , m_isImport(isImport)
247 , m_isValid(true)
248 , m_type(type)
249 {
250 ASSERT(*this);
251 }
252
253 explicit operator bool() const { return m_isValid; }
254 bool isImport() const { return m_isImport; }
255 uint32_t initial() const { return m_initial; }
256 Optional<uint32_t> maximum() const { return m_maximum; }
257 TableElementType type() const { return m_type; }
258 Wasm::Type wasmType() const { return m_type == TableElementType::Funcref ? Type::Funcref : Type::Anyref; }
259
260private:
261 uint32_t m_initial;
262 Optional<uint32_t> m_maximum;
263 bool m_isImport { false };
264 bool m_isValid { false };
265 TableElementType m_type;
266};
267
268struct CustomSection {
269 WTF_MAKE_STRUCT_FAST_ALLOCATED;
270 Name name;
271 Vector<uint8_t> payload;
272};
273
274enum class NameType : uint8_t {
275 Module = 0,
276 Function = 1,
277 Local = 2,
278};
279
280template<typename Int>
281inline bool isValidNameType(Int val)
282{
283 switch (val) {
284 case static_cast<Int>(NameType::Module):
285 case static_cast<Int>(NameType::Function):
286 case static_cast<Int>(NameType::Local):
287 return true;
288 }
289 return false;
290}
291
292struct UnlinkedWasmToWasmCall {
293 WTF_MAKE_STRUCT_FAST_ALLOCATED;
294 CodeLocationNearCall<WasmEntryPtrTag> callLocation;
295 size_t functionIndexSpace;
296};
297
298struct Entrypoint {
299 WTF_MAKE_STRUCT_FAST_ALLOCATED;
300 std::unique_ptr<B3::Compilation> compilation;
301 RegisterAtOffsetList calleeSaveRegisters;
302};
303
304struct InternalFunction {
305 WTF_MAKE_STRUCT_FAST_ALLOCATED;
306 CodeLocationDataLabelPtr<WasmEntryPtrTag> calleeMoveLocation;
307 Entrypoint entrypoint;
308};
309
310// WebAssembly direct calls and call_indirect use indices into "function index space". This space starts
311// with all imports, and then all internal functions. WasmToWasmImportableFunction and FunctionIndexSpace are only
312// meant as fast lookup tables for these opcodes and do not own code.
313struct WasmToWasmImportableFunction {
314 WTF_MAKE_STRUCT_FAST_ALLOCATED;
315 using LoadLocation = MacroAssemblerCodePtr<WasmEntryPtrTag>*;
316 static ptrdiff_t offsetOfSignatureIndex() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, signatureIndex); }
317 static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WasmToWasmImportableFunction, entrypointLoadLocation); }
318
319 // FIXME: Pack signature index and code pointer into one 64-bit value. See <https://bugs.webkit.org/show_bug.cgi?id=165511>.
320 SignatureIndex signatureIndex { Signature::invalidIndex };
321 LoadLocation entrypointLoadLocation;
322};
323using FunctionIndexSpace = Vector<WasmToWasmImportableFunction>;
324
325} } // namespace JSC::Wasm
326
327#endif // ENABLE(WEBASSEMBLY)
328