2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "WasmModuleParser.h"
29 #if ENABLE(WEBASSEMBLY)
31 #include "IdentifierInlines.h"
32 #include "WasmFormat.h"
33 #include "WasmMemory.h"
35 #include "WasmSections.h"
39 namespace JSC { namespace Wasm {
41 static const bool verbose = false;
43 bool ModuleParser::parse()
45 m_module = std::make_unique<ModuleInformation>();
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";
52 if (!consumeCharacter(0) || !consumeString("asm")) {
53 m_errorMessage = "Modules doesn't start with '\\0asm'";
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";
64 if (versionNumber != expectedVersionNumber) {
65 // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
66 m_errorMessage = "unexpected version number";
72 dataLogLn("Passed processing header.");
74 Sections::Section previousSection = Sections::Unknown;
75 while (m_offset < length()) {
77 dataLogLn("Starting to parse next section at offset: ", m_offset);
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";
87 dataLogLn("Section byte: ", sectionByte);
89 Sections::Section section = Sections::Unknown;
91 if (sectionByte < Sections::Unknown)
92 section = static_cast<Sections::Section>(sectionByte);
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";
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";
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";
114 auto end = m_offset + sectionLength;
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: { \
121 dataLogLn("Parsing " DESCRIPTION); \
122 if (!parse ## NAME()) { \
123 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
128 FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
129 #undef WASM_SECTION_PARSE
131 case Sections::Unknown: {
133 dataLogLn("Unknown section, skipping.");
134 // Ignore section's name LEB and bytes: they're already included in sectionLength.
135 m_offset += sectionLength;
141 dataLogLn("Finished parsing section.");
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";
149 previousSection = section;
157 bool ModuleParser::parseType()
160 if (!parseVarUInt32(count))
163 dataLogLn("count: ", count);
164 if (!m_module->signatures.tryReserveCapacity(count))
167 for (uint32_t i = 0; i < count; ++i) {
169 if (!parseInt7(type))
175 dataLogLn("Got function type.");
177 uint32_t argumentCount;
178 if (!parseVarUInt32(argumentCount))
182 dataLogLn("argumentCount: ", argumentCount);
184 Vector<Type> argumentTypes;
185 if (!argumentTypes.tryReserveCapacity(argumentCount))
188 for (unsigned i = 0; i != argumentCount; ++i) {
190 if (!parseResultType(argumentType))
192 argumentTypes.uncheckedAppend(argumentType);
196 if (!parseVarUInt1(returnCount))
201 dataLogLn(returnCount);
205 if (!parseValueType(value))
207 returnType = static_cast<Type>(value);
209 returnType = Type::Void;
211 m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
216 bool ModuleParser::parseImport()
218 uint32_t importCount;
219 if (!parseVarUInt32(importCount))
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.
226 for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
232 if (!parseVarUInt32(moduleLen)
233 || !consumeUTF8String(moduleString, moduleLen))
235 imp.module = Identifier::fromString(m_vm, moduleString);
236 if (!parseVarUInt32(fieldLen)
237 || !consumeUTF8String(fieldString, fieldLen))
239 imp.field = Identifier::fromString(m_vm, fieldString);
240 if (!parseExternalKind(imp.kind))
243 case External::Function: {
244 uint32_t functionSignatureIndex;
245 if (!parseVarUInt32(functionSignatureIndex)
246 || functionSignatureIndex >= m_module->signatures.size())
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);
254 case External::Table: {
255 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
258 case External::Memory: {
259 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
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.
269 m_module->imports.uncheckedAppend(imp);
275 bool ModuleParser::parseFunction()
278 if (!parseVarUInt32(count)
279 || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
280 || !m_functionLocationInBinary.tryReserveCapacity(count)
281 || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count))
284 for (uint32_t i = 0; i != count; ++i) {
286 if (!parseVarUInt32(typeNumber)
287 || typeNumber >= m_module->signatures.size())
290 Signature* signature = &m_module->signatures[typeNumber];
291 // The Code section fixes up start and end.
294 m_module->internalFunctionSignatures.uncheckedAppend(signature);
295 m_functionLocationInBinary.uncheckedAppend({ start, end });
296 m_functionIndexSpace.uncheckedAppend(signature);
302 bool ModuleParser::parseTable()
308 bool ModuleParser::parseMemory()
311 if (!parseVarUInt1(count))
319 if (!parseVarUInt1(flags)
320 || !parseVarUInt32(size)
321 || size > maxPageCount)
324 uint32_t capacity = maxPageCount;
326 if (!parseVarUInt32(capacity)
328 || capacity > maxPageCount)
332 capacity *= pageSize;
335 Vector<unsigned> pinnedSizes = { 0 };
336 m_module->memory = std::make_unique<Memory>(size, capacity, pinnedSizes);
337 return m_module->memory->memory();
340 bool ModuleParser::parseGlobal()
342 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
346 bool ModuleParser::parseExport()
348 uint32_t exportCount;
349 if (!parseVarUInt32(exportCount)
350 || !m_module->exports.tryReserveCapacity(exportCount))
353 for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
357 if (!parseVarUInt32(fieldLen)
358 || !consumeUTF8String(fieldString, fieldLen))
360 exp.field = Identifier::fromString(m_vm, fieldString);
361 if (!parseExternalKind(exp.kind))
364 case External::Function: {
365 if (!parseVarUInt32(exp.functionIndex)
366 || exp.functionIndex >= m_functionIndexSpace.size())
370 case External::Table: {
371 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
374 case External::Memory: {
375 // FIXME https://bugs.webkit.org/show_bug.cgi?id=164134
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.
385 m_module->exports.uncheckedAppend(exp);
391 bool ModuleParser::parseStart()
393 // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
397 bool ModuleParser::parseElement()
399 // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
403 bool ModuleParser::parseCode()
406 if (!parseVarUInt32(count)
407 || count != m_functionLocationInBinary.size())
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)
417 m_functionLocationInBinary[i].start = m_offset;
418 m_functionLocationInBinary[i].end = m_offset + functionSize;
419 m_offset = m_functionLocationInBinary[i].end;
425 bool ModuleParser::parseData()
427 // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
431 } } // namespace JSC::Wasm
433 #endif // ENABLE(WEBASSEMBLY)