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