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