WebAssembly: improve compilation error messages
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmFormat.h
1 /*
2  * Copyright (C) 2015 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 "B3Compilation.h"
31 #include "B3Type.h"
32 #include "CodeLocation.h"
33 #include "Identifier.h"
34 #include "MacroAssemblerCodeRef.h"
35 #include "RegisterAtOffsetList.h"
36 #include "WasmMemoryInformation.h"
37 #include "WasmOps.h"
38 #include "WasmPageCount.h"
39 #include <memory>
40 #include <wtf/FastMalloc.h>
41 #include <wtf/Optional.h>
42 #include <wtf/Vector.h>
43
44 namespace JSC {
45
46 class JSFunction;
47
48 namespace Wasm {
49
50 inline bool isValueType(Type type)
51 {
52     switch (type) {
53     case I32:
54     case I64:
55     case F32:
56     case F64:
57         return true;
58     default:
59         break;
60     }
61     return false;
62 }
63     
64 enum class ExternalKind : uint8_t {
65     // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
66     Function = 0,
67     Table = 1,
68     Memory = 2,
69     Global = 3,
70 };
71
72 template<typename Int>
73 static bool isValidExternalKind(Int val)
74 {
75     switch (val) {
76     case static_cast<Int>(ExternalKind::Function):
77     case static_cast<Int>(ExternalKind::Table):
78     case static_cast<Int>(ExternalKind::Memory):
79     case static_cast<Int>(ExternalKind::Global):
80         return true;
81     default:
82         return false;
83     }
84 }
85
86 static_assert(static_cast<int>(ExternalKind::Function) == 0, "Wasm needs Function to have the value 0");
87 static_assert(static_cast<int>(ExternalKind::Table)    == 1, "Wasm needs Table to have the value 1");
88 static_assert(static_cast<int>(ExternalKind::Memory)   == 2, "Wasm needs Memory to have the value 2");
89 static_assert(static_cast<int>(ExternalKind::Global)   == 3, "Wasm needs Global to have the value 3");
90
91 static inline const char* makeString(ExternalKind kind)
92 {
93     switch (kind) {
94     case ExternalKind::Function: return "Function";
95     case ExternalKind::Table: return "Table";
96     case ExternalKind::Memory: return "Memory";
97     case ExternalKind::Global: return "Global";
98     }
99     RELEASE_ASSERT_NOT_REACHED();
100     return "?";
101 }
102
103 struct Signature {
104     Type returnType;
105     Vector<Type> arguments;
106 };
107
108 struct Import {
109     Identifier module;
110     Identifier field;
111     ExternalKind kind;
112     unsigned kindIndex; // Index in the vector of the corresponding kind.
113 };
114
115 struct Export {
116     Identifier field;
117     ExternalKind kind;
118     unsigned kindIndex; // Index in the vector of the corresponding kind.
119 };
120
121 struct Global {
122     enum Mutability : uint8_t {
123         // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
124         Mutable = 1,
125         Immutable = 0
126     };
127
128     enum InitializationType {
129         IsImport,
130         FromGlobalImport,
131         FromExpression
132     };
133
134     Mutability mutability;
135     Type type;
136     InitializationType initializationType { IsImport };
137     uint64_t initialBitsOrImportNumber { 0 };
138 };
139
140 struct FunctionLocationInBinary {
141     size_t start;
142     size_t end;
143 };
144
145 struct Segment {
146     uint32_t offset;
147     uint32_t sizeInBytes;
148     // Bytes are allocated at the end.
149     static Segment* make(uint32_t offset, uint32_t sizeInBytes)
150     {
151         auto allocated = tryFastCalloc(sizeof(Segment) + sizeInBytes, 1);
152         Segment* segment;
153         if (!allocated.getValue(segment))
154             return nullptr;
155         segment->offset = offset;
156         segment->sizeInBytes = sizeInBytes;
157         return segment;
158     }
159     static void destroy(Segment *segment)
160     {
161         fastFree(segment);
162     }
163     uint8_t& byte(uint32_t pos)
164     {
165         ASSERT(pos < sizeInBytes);
166         return *reinterpret_cast<uint8_t*>(reinterpret_cast<char*>(this) + sizeof(offset) + sizeof(sizeInBytes) + pos);
167     }
168     typedef std::unique_ptr<Segment, decltype(&Segment::destroy)> Ptr;
169     static Ptr makePtr(Segment* segment)
170     {
171         return Ptr(segment, &Segment::destroy);
172     }
173 };
174
175 struct Element {
176     uint32_t offset;
177     Vector<uint32_t> functionIndices;
178 };
179
180 class TableInformation {
181 public:
182     TableInformation()
183     {
184         ASSERT(!*this);
185     }
186
187     TableInformation(uint32_t initial, std::optional<uint32_t> maximum, bool isImport)
188         : m_initial(initial)
189         , m_maximum(maximum)
190         , m_isImport(isImport)
191         , m_isValid(true)
192     {
193         ASSERT(*this);
194     }
195
196     explicit operator bool() const { return m_isValid; }
197     bool isImport() const { return m_isImport; }
198     uint32_t initial() const { return m_initial; }
199     std::optional<uint32_t> maximum() const { return m_maximum; }
200
201 private:
202     uint32_t m_initial;
203     std::optional<uint32_t> m_maximum;
204     bool m_isImport { false };
205     bool m_isValid { false };
206 };
207
208 struct ModuleInformation {
209     Vector<Signature> signatures;
210     Vector<Import> imports;
211     Vector<Signature*> importFunctions;
212     Vector<Signature*> internalFunctionSignatures;
213     MemoryInformation memory;
214     Vector<Export> exports;
215     std::optional<uint32_t> startFunctionIndexSpace;
216     Vector<Segment::Ptr> data;
217     Vector<Element> elements;
218     TableInformation tableInformation;
219     Vector<Global> globals;
220     unsigned firstInternalGlobal { 0 };
221
222     ~ModuleInformation();
223 };
224
225 struct UnlinkedWasmToWasmCall {
226     CodeLocationCall callLocation;
227     size_t functionIndex;
228 };
229
230 struct Entrypoint {
231     std::unique_ptr<B3::Compilation> compilation;
232     RegisterAtOffsetList calleeSaveRegisters;
233 };
234
235 struct WasmInternalFunction {
236     CodeLocationDataLabelPtr wasmCalleeMoveLocation;
237     CodeLocationDataLabelPtr jsToWasmCalleeMoveLocation;
238
239     Entrypoint wasmEntrypoint;
240     Entrypoint jsToWasmEntrypoint;
241 };
242
243 typedef MacroAssemblerCodeRef WasmToJSStub;
244
245 // WebAssembly direct calls and call_indirect use indices into "function index space". This space starts with all imports, and then all internal functions.
246 // CallableFunction and FunctionIndexSpace are only meant as fast lookup tables for these opcodes, and do not own code.
247 struct CallableFunction {
248     CallableFunction() = default;
249
250     CallableFunction(Signature* signature, void* code = nullptr)
251         : signature(signature)
252         , code(code)
253     {
254     }
255
256     // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures),
257     // and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
258     Signature* signature { nullptr }; 
259     void* code { nullptr };
260 };
261 typedef Vector<CallableFunction> FunctionIndexSpace;
262
263
264 struct ImmutableFunctionIndexSpace {
265     MallocPtr<CallableFunction> buffer;
266     size_t size;
267 };
268
269 } } // namespace JSC::Wasm
270
271 #endif // ENABLE(WEBASSEMBLY)