af133a4c7a507dad57ef579a5f5d571cff587c8c
[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 "IdentifierInlines.h"
32 #include "WasmFormat.h"
33 #include "WasmMemory.h"
34 #include "WasmOps.h"
35 #include "WasmSections.h"
36
37 #include <sys/mman.h>
38
39 namespace JSC { namespace Wasm {
40
41 static const bool verbose = false;
42
43 bool ModuleParser::parse()
44 {
45     m_module = std::make_unique<ModuleInformation>();
46
47     const size_t minSize = 8;
48     if (length() < minSize) {
49         m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";
50         return false;
51     }
52     if (!consumeCharacter(0) || !consumeString("asm")) {
53         m_errorMessage = "Modules doesn't start with '\\0asm'";
54         return false;
55     }
56
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 != expectedVersionNumber) {
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         }
128         FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
129 #undef WASM_SECTION_PARSE
130
131         case Sections::Unknown: {
132             if (verbose)
133                 dataLogLn("Unknown section, skipping.");
134             // Ignore section's name LEB and bytes: they're already included in sectionLength.
135             m_offset += sectionLength;
136             break;
137         }
138         }
139
140         if (verbose)
141             dataLogLn("Finished parsing section.");
142
143         if (end != m_offset) {
144             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
145             m_errorMessage = "parsing ended before the end of the section";
146             return false;
147         }
148
149         previousSection = section;
150     }
151
152     // TODO
153     m_failed = false;
154     return true;
155 }
156
157 bool ModuleParser::parseType()
158 {
159     uint32_t count;
160     if (!parseVarUInt32(count))
161         return false;
162     if (verbose)
163         dataLogLn("count: ", count);
164     if (!m_module->signatures.tryReserveCapacity(count))
165         return false;
166
167     for (uint32_t i = 0; i < count; ++i) {
168         int8_t type;
169         if (!parseInt7(type))
170             return false;
171         if (type != Func)
172             return false;
173
174         if (verbose)
175             dataLogLn("Got function type.");
176
177         uint32_t argumentCount;
178         if (!parseVarUInt32(argumentCount))
179             return false;
180
181         if (verbose)
182             dataLogLn("argumentCount: ", argumentCount);
183
184         Vector<Type> argumentTypes;
185         if (!argumentTypes.tryReserveCapacity(argumentCount))
186             return false;
187
188         for (unsigned i = 0; i != argumentCount; ++i) {
189             Type argumentType;
190             if (!parseResultType(argumentType))
191                 return false;
192             argumentTypes.uncheckedAppend(argumentType);
193         }
194
195         uint8_t returnCount;
196         if (!parseVarUInt1(returnCount))
197             return false;
198         Type returnType;
199
200         if (verbose)
201             dataLogLn(returnCount);
202
203         if (returnCount) {
204             Type value;
205             if (!parseValueType(value))
206                 return false;
207             returnType = static_cast<Type>(value);
208         } else
209             returnType = Type::Void;
210
211         m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
212     }
213     return true;
214 }
215
216 bool ModuleParser::parseImport()
217 {
218     uint32_t importCount;
219     if (!parseVarUInt32(importCount))
220         return false;
221     if (!m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
222         || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
223         || !m_functionIndexSpace.tryReserveCapacity(importCount)) // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
224         return false;
225
226     for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
227         Import imp;
228         uint32_t moduleLen;
229         uint32_t fieldLen;
230         String moduleString;
231         String fieldString;
232         if (!parseVarUInt32(moduleLen)
233             || !consumeUTF8String(moduleString, moduleLen))
234             return false;
235         imp.module = Identifier::fromString(m_vm, moduleString);
236         if (!parseVarUInt32(fieldLen)
237             || !consumeUTF8String(fieldString, fieldLen))
238             return false;
239         imp.field = Identifier::fromString(m_vm, fieldString);
240         if (!parseExternalKind(imp.kind))
241             return false;
242         switch (imp.kind) {
243         case External::Function: {
244             uint32_t functionSignatureIndex;
245             if (!parseVarUInt32(functionSignatureIndex)
246                 || functionSignatureIndex >= m_module->signatures.size())
247                 return false;
248             imp.kindIndex = m_module->importFunctions.size();
249             Signature* signature = &m_module->signatures[functionSignatureIndex];
250             m_module->importFunctions.uncheckedAppend(signature);
251             m_functionIndexSpace.uncheckedAppend(signature);
252             break;
253         }
254         case External::Table: {
255             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
256             break;
257         }
258         case External::Memory: {
259             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
260             break;
261         }
262         case External::Global: {
263             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
264             // In the MVP, only immutable global variables can be imported.
265             break;
266         }
267         }
268
269         m_module->imports.uncheckedAppend(imp);
270     }
271
272     return true;
273 }
274
275 bool ModuleParser::parseFunction()
276 {
277     uint32_t count;
278     if (!parseVarUInt32(count)
279         || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
280         || !m_functionLocationInBinary.tryReserveCapacity(count)
281         || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count))
282         return false;
283
284     for (uint32_t i = 0; i != count; ++i) {
285         uint32_t typeNumber;
286         if (!parseVarUInt32(typeNumber)
287             || typeNumber >= m_module->signatures.size())
288             return false;
289
290         Signature* signature = &m_module->signatures[typeNumber];
291         // The Code section fixes up start and end.
292         size_t start = 0;
293         size_t end = 0;
294         m_module->internalFunctionSignatures.uncheckedAppend(signature);
295         m_functionLocationInBinary.uncheckedAppend({ start, end });
296         m_functionIndexSpace.uncheckedAppend(signature);
297     }
298
299     return true;
300 }
301
302 bool ModuleParser::parseTable()
303 {
304     // FIXME
305     return true;
306 }
307
308 bool ModuleParser::parseMemory()
309 {
310     uint8_t count;
311     if (!parseVarUInt1(count))
312         return false;
313
314     if (!count)
315         return true;
316
317     uint8_t flags;
318     uint32_t size;
319     if (!parseVarUInt1(flags)
320         || !parseVarUInt32(size)
321         || size > maxPageCount)
322         return false;
323
324     uint32_t capacity = maxPageCount;
325     if (flags) {
326         if (!parseVarUInt32(capacity)
327             || size > capacity
328             || capacity > maxPageCount)
329             return false;
330     }
331
332     capacity *= pageSize;
333     size *= pageSize;
334
335     Vector<unsigned> pinnedSizes = { 0 };
336     m_module->memory = std::make_unique<Memory>(size, capacity, pinnedSizes);
337     return m_module->memory->memory();
338 }
339
340 bool ModuleParser::parseGlobal()
341 {
342     // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
343     return true;
344 }
345
346 bool ModuleParser::parseExport()
347 {
348     uint32_t exportCount;
349     if (!parseVarUInt32(exportCount)
350         || !m_module->exports.tryReserveCapacity(exportCount))
351         return false;
352
353     for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
354         Export exp;
355         uint32_t fieldLen;
356         String fieldString;
357         if (!parseVarUInt32(fieldLen)
358             || !consumeUTF8String(fieldString, fieldLen))
359             return false;
360         exp.field = Identifier::fromString(m_vm, fieldString);
361         if (!parseExternalKind(exp.kind))
362             return false;
363         switch (exp.kind) {
364         case External::Function: {
365             if (!parseVarUInt32(exp.functionIndex)
366                 || exp.functionIndex >= m_functionIndexSpace.size())
367                 return false;
368             break;
369         }
370         case External::Table: {
371             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
372             break;
373         }
374         case External::Memory: {
375             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
376             break;
377         }
378         case External::Global: {
379             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
380             // In the MVP, only immutable global variables can be exported.
381             break;
382         }
383         }
384
385         m_module->exports.uncheckedAppend(exp);
386     }
387
388     return true;
389 }
390
391 bool ModuleParser::parseStart()
392 {
393     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
394     return true;
395 }
396
397 bool ModuleParser::parseElement()
398 {
399     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
400     return true;
401 }
402
403 bool ModuleParser::parseCode()
404 {
405     uint32_t count;
406     if (!parseVarUInt32(count)
407         || count != m_functionLocationInBinary.size())
408         return false;
409
410     for (uint32_t i = 0; i != count; ++i) {
411         uint32_t functionSize;
412         if (!parseVarUInt32(functionSize)
413             || functionSize > length()
414             || functionSize > length() - m_offset)
415             return false;
416
417         m_functionLocationInBinary[i].start = m_offset;
418         m_functionLocationInBinary[i].end = m_offset + functionSize;
419         m_offset = m_functionLocationInBinary[i].end;
420     }
421
422     return true;
423 }
424
425 bool ModuleParser::parseData()
426 {
427     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
428     return true;
429 }
430
431 } } // namespace JSC::Wasm
432
433 #endif // ENABLE(WEBASSEMBLY)