WebAssembly JS API: implement more sections
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmModuleParser.cpp
1 /*
2  * Copyright (C) 2016 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 #include "config.h"
27 #include "WasmModuleParser.h"
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "WasmFormat.h"
32 #include "WasmMemory.h"
33 #include "WasmOps.h"
34 #include "WasmSections.h"
35
36 #include <sys/mman.h>
37
38 namespace JSC { namespace Wasm {
39
40 static const bool verbose = false;
41
42 bool ModuleParser::parse()
43 {
44     m_module = std::make_unique<ModuleInformation>();
45
46     const size_t minSize = 8;
47     if (length() < minSize) {
48         m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";
49         return false;
50     }
51     if (!consumeCharacter(0) || !consumeString("asm")) {
52         m_errorMessage = "Modules doesn't start with '\\0asm'";
53         return false;
54     }
55
56     // Skip the version number for now since we don't do anything with it.
57     uint32_t versionNumber;
58     if (!parseUInt32(versionNumber)) {
59         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
60         m_errorMessage = "couldn't parse version number";
61         return false;
62     }
63
64     if (versionNumber != magicNumber) {
65         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
66         m_errorMessage = "unexpected version number";
67         return false;
68     }
69
70
71     if (verbose)
72         dataLogLn("Passed processing header.");
73
74     Sections::Section previousSection = Sections::Unknown;
75     while (m_offset < length()) {
76         if (verbose)
77             dataLogLn("Starting to parse next section at offset: ", m_offset);
78
79         uint8_t sectionByte;
80         if (!parseUInt7(sectionByte)) {
81             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
82             m_errorMessage = "couldn't get section byte";
83             return false;
84         }
85
86         if (verbose)
87             dataLogLn("Section byte: ", sectionByte);
88
89         Sections::Section section = Sections::Unknown;
90         if (sectionByte) {
91             if (sectionByte < Sections::Unknown)
92                 section = static_cast<Sections::Section>(sectionByte);
93         }
94
95         if (!Sections::validateOrder(previousSection, section)) {
96             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
97             m_errorMessage = "invalid section order";
98             return false;
99         }
100
101         uint32_t sectionLength;
102         if (!parseVarUInt32(sectionLength)) {
103             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
104             m_errorMessage = "couldn't get section length";
105             return false;
106         }
107
108         if (sectionLength > length() - m_offset) {
109             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
110             m_errorMessage = "section content would overflow Module's size";
111             return false;
112         }
113
114         auto end = m_offset + sectionLength;
115
116         switch (section) {
117         // FIXME improve error message in macro below https://bugs.webkit.org/show_bug.cgi?id=163919
118 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \
119         case Sections::NAME: { \
120             if (verbose) \
121                 dataLogLn("Parsing " DESCRIPTION); \
122             if (!parse ## NAME()) { \
123                 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
124                 return false; \
125             } \
126         } break;
127         FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
128 #undef WASM_SECTION_PARSE
129
130         case Sections::Unknown: {
131             if (verbose)
132                 dataLogLn("Unknown section, skipping.");
133             // Ignore section's name LEB and bytes: they're already included in sectionLength.
134             m_offset += sectionLength;
135             break;
136         }
137         }
138
139         if (verbose)
140             dataLogLn("Finished parsing section.");
141
142         if (end != m_offset) {
143             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
144             m_errorMessage = "parsing ended before the end of the section";
145             return false;
146         }
147
148         previousSection = section;
149     }
150
151     // TODO
152     m_failed = false;
153     return true;
154 }
155
156 bool ModuleParser::parseType()
157 {
158     uint32_t count;
159     if (!parseVarUInt32(count))
160         return false;
161     if (verbose)
162         dataLogLn("count: ", count);
163     if (!m_module->signatures.tryReserveCapacity(count))
164         return false;
165
166     for (uint32_t i = 0; i < count; ++i) {
167         int8_t type;
168         if (!parseInt7(type))
169             return false;
170         if (type != -0x20) // Function type constant.
171             return false;
172
173         if (verbose)
174             dataLogLn("Got function type.");
175
176         uint32_t argumentCount;
177         if (!parseVarUInt32(argumentCount))
178             return false;
179
180         if (verbose)
181             dataLogLn("argumentCount: ", argumentCount);
182
183         Vector<Type> argumentTypes;
184         if (!argumentTypes.tryReserveCapacity(argumentCount))
185             return false;
186
187         for (unsigned i = 0; i != argumentCount; ++i) {
188             uint8_t argumentType;
189             if (!parseUInt7(argumentType) || !isValueType(static_cast<Type>(argumentType)))
190                 return false;
191             argumentTypes.uncheckedAppend(static_cast<Type>(argumentType));
192         }
193
194         uint8_t returnCount;
195         if (!parseVarUInt1(returnCount))
196             return false;
197         Type returnType;
198
199         if (verbose)
200             dataLogLn(returnCount);
201
202         if (returnCount) {
203             Type value;
204             if (!parseValueType(value))
205                 return false;
206             returnType = static_cast<Type>(value);
207         } else
208             returnType = Type::Void;
209
210         m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
211     }
212     return true;
213 }
214
215 bool ModuleParser::parseImport()
216 {
217     uint32_t importCount;
218     if (!parseVarUInt32(importCount))
219         return false;
220     if (!m_module->imports.tryReserveCapacity(importCount))
221         return false;
222
223     for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
224         Import i;
225         uint32_t moduleLen;
226         uint32_t fieldLen;
227         if (!parseVarUInt32(moduleLen))
228             return false;
229         if (!consumeUTF8String(i.module, moduleLen))
230             return false;
231         if (!parseVarUInt32(fieldLen))
232             return false;
233         if (!consumeUTF8String(i.field, fieldLen))
234             return false;
235         if (!parseExternalKind(i.kind))
236             return false;
237         switch (i.kind) {
238         case External::Function: {
239             uint32_t functionSignatureIndex;
240             if (!parseVarUInt32(functionSignatureIndex))
241                 return false;
242             if (functionSignatureIndex > m_module->signatures.size())
243                 return false;
244             i.functionSignature = &m_module->signatures[functionSignatureIndex];
245         } break;
246         case External::Table:
247             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
248             break;
249         case External::Memory:
250             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
251             break;
252         case External::Global:
253             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
254             // In the MVP, only immutable global variables can be imported.
255             break;
256         }
257
258         m_module->imports.uncheckedAppend(i);
259     }
260
261     return true;
262 }
263
264 bool ModuleParser::parseFunction()
265 {
266     uint32_t count;
267     if (!parseVarUInt32(count))
268         return false;
269     if (!m_module->functions.tryReserveCapacity(count))
270         return false;
271
272     for (uint32_t i = 0; i != count; ++i) {
273         uint32_t typeNumber;
274         if (!parseVarUInt32(typeNumber))
275             return false;
276
277         if (typeNumber >= m_module->signatures.size())
278             return false;
279
280         m_module->functions.uncheckedAppend({ &m_module->signatures[typeNumber], 0, 0 });
281     }
282
283     return true;
284 }
285
286 bool ModuleParser::parseTable()
287 {
288     // FIXME
289     return true;
290 }
291
292 bool ModuleParser::parseMemory()
293 {
294     uint8_t flags;
295     if (!parseVarUInt1(flags))
296         return false;
297
298     uint32_t size;
299     if (!parseVarUInt32(size))
300         return false;
301     if (size > maxPageCount)
302         return false;
303
304     uint32_t capacity = maxPageCount;
305     if (flags) {
306         if (!parseVarUInt32(capacity))
307             return false;
308         if (size > capacity || capacity > maxPageCount)
309             return false;
310     }
311
312     capacity *= pageSize;
313     size *= pageSize;
314
315     Vector<unsigned> pinnedSizes = { 0 };
316     m_module->memory = std::make_unique<Memory>(size, capacity, pinnedSizes);
317     return m_module->memory->memory();
318 }
319
320 bool ModuleParser::parseGlobal()
321 {
322     // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
323     return true;
324 }
325
326 bool ModuleParser::parseExport()
327 {
328     uint32_t exportCount;
329     if (!parseVarUInt32(exportCount))
330         return false;
331     if (!m_module->exports.tryReserveCapacity(exportCount))
332         return false;
333
334     for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
335         Export e;
336         uint32_t fieldLen;
337         if (!parseVarUInt32(fieldLen))
338             return false;
339         if (!consumeUTF8String(e.field, fieldLen))
340             return false;
341         if (!parseExternalKind(e.kind))
342             return false;
343         switch (e.kind) {
344         case External::Function: {
345             uint32_t functionSignatureIndex;
346             if (!parseVarUInt32(functionSignatureIndex))
347                 return false;
348             if (functionSignatureIndex > m_module->signatures.size())
349                 return false;
350             e.functionSignature = &m_module->signatures[functionSignatureIndex];
351         } break;
352         case External::Table:
353             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
354             break;
355         case External::Memory:
356             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
357             break;
358         case External::Global:
359             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
360             // In the MVP, only immutable global variables can be exported.
361             break;
362         }
363
364         m_module->exports.uncheckedAppend(e);
365     }
366
367     return true;
368 }
369
370 bool ModuleParser::parseStart()
371 {
372     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
373     return true;
374 }
375
376 bool ModuleParser::parseElement()
377 {
378     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
379     return true;
380 }
381
382 bool ModuleParser::parseCode()
383 {
384     uint32_t count;
385     if (!parseVarUInt32(count))
386         return false;
387
388     if (count != m_module->functions.size())
389         return false;
390
391     for (uint32_t i = 0; i != count; ++i) {
392         uint32_t functionSize;
393         if (!parseVarUInt32(functionSize))
394             return false;
395         if (functionSize > length() || functionSize > length() - m_offset)
396             return false;
397
398         FunctionInformation& info = m_module->functions[i];
399         info.start = m_offset;
400         info.end = m_offset + functionSize;
401         m_offset = info.end;
402     }
403
404     return true;
405 }
406
407 bool ModuleParser::parseData()
408 {
409     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
410     return true;
411 }
412
413 } } // namespace JSC::Wasm
414
415 #endif // ENABLE(WEBASSEMBLY)