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