[WASM-References] Rename anyfunc to funcref
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmFormat.h
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
46 namespace JSC {
47
48 namespace B3 {
49 class Compilation;
50 }
51
52 namespace Wasm {
53
54 struct CompilationContext;
55 struct ModuleInformation;
56
57 enum class TableElementType : uint8_t {
58     Anyref,
59     Funcref
60 };
61
62 inline 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
79 inline bool isSubtype(Type sub, Type parent)
80 {
81     if (sub == parent)
82         return true;
83     return sub == Funcref && parent == Anyref;
84 }
85     
86 enum 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
94 template<typename Int>
95 inline 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
107 static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
108 static_assert(static_cast<int>(ExternalKind::Table)    == 1, "Wasm needs Table to have the value 1");
109 static_assert(static_cast<int>(ExternalKind::Memory)   == 2, "Wasm needs Memory to have the value 2");
110 static_assert(static_cast<int>(ExternalKind::Global)   == 3, "Wasm needs Global to have the value 3");
111
112 inline 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
124 struct 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
131 struct Export {
132     const Name field;
133     ExternalKind kind;
134     unsigned kindIndex; // Index in the vector of the corresponding kind.
135 };
136
137 String makeString(const Name& characters);
138
139 struct 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
159 struct FunctionData {
160     size_t start;
161     size_t end;
162     Vector<uint8_t> data;
163 };
164
165 class 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
176 public:
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
195 private:
196     uint32_t m_bits;
197     Type m_type;
198 };
199
200 struct 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
215 struct 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
226 class TableInformation {
227 public:
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
250 private:
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     
258 struct CustomSection {
259     Name name;
260     Vector<uint8_t> payload;
261 };
262
263 enum class NameType : uint8_t {
264     Module = 0,
265     Function = 1,
266     Local = 2,
267 };
268     
269 template<typename Int>
270 inline 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
281 struct UnlinkedWasmToWasmCall {
282     CodeLocationNearCall<WasmEntryPtrTag> callLocation;
283     size_t functionIndexSpace;
284 };
285
286 struct Entrypoint {
287     std::unique_ptr<B3::Compilation> compilation;
288     RegisterAtOffsetList calleeSaveRegisters;
289 };
290
291 struct 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.
299 struct 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 };
308 using FunctionIndexSpace = Vector<WasmToWasmImportableFunction>;
309
310 } } // namespace JSC::Wasm
311
312 #endif // ENABLE(WEBASSEMBLY)