223912294f9efd924bb4399b8b9be457ebcf7f50
[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 "JSWebAssemblyTable.h"
33 #include "WasmFormat.h"
34 #include "WasmMemoryInformation.h"
35 #include "WasmOps.h"
36 #include "WasmSections.h"
37
38 #include <sys/mman.h>
39
40 namespace JSC { namespace Wasm {
41
42 ALWAYS_INLINE I32InitExpr makeI32InitExpr(uint8_t opcode, uint32_t bits)
43 {
44     RELEASE_ASSERT(opcode == I32Const || opcode == GetGlobal);
45     if (opcode == I32Const)
46         return I32InitExpr::constValue(bits);
47     return I32InitExpr::globalImport(bits);
48 }
49
50 auto ModuleParser::parse() -> Result
51 {
52     m_result.module = std::make_unique<ModuleInformation>();
53     const size_t minSize = 8;
54     uint32_t versionNumber;
55
56     WASM_PARSER_FAIL_IF(length() < minSize, "expected a module of at least ", minSize, " bytes");
57     WASM_PARSER_FAIL_IF(!consumeCharacter(0) || !consumeString("asm"), "modules doesn't start with '\\0asm'");
58     WASM_PARSER_FAIL_IF(!parseUInt32(versionNumber), "can't parse version number");
59     if (versionNumber != 0xD) // FIXME Stop supporting version 0xD temporarily. https://bugs.webkit.org/show_bug.cgi?id=168788
60         WASM_PARSER_FAIL_IF(versionNumber != expectedVersionNumber, "unexpected version number ", versionNumber, " expected ", expectedVersionNumber);
61
62     Section previousSection = Section::Custom;
63     while (m_offset < length()) {
64         uint8_t sectionByte;
65
66         WASM_PARSER_FAIL_IF(!parseUInt7(sectionByte), "can't get section byte");
67
68         Section section = Section::Custom;
69         if (sectionByte) {
70             if (isValidSection(sectionByte))
71                 section = static_cast<Section>(sectionByte);
72         }
73
74         uint32_t sectionLength;
75         WASM_PARSER_FAIL_IF(!validateOrder(previousSection, section), "invalid section order, ", previousSection, " followed by ", section);
76         WASM_PARSER_FAIL_IF(!parseVarUInt32(sectionLength), "can't get ", section, " section's length");
77         WASM_PARSER_FAIL_IF(sectionLength > length() - m_offset, section, "section of size ", sectionLength, " would overflow Module's size");
78
79         auto end = m_offset + sectionLength;
80
81         switch (section) {
82 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION)                   \
83         case Section::NAME: {                                       \
84             WASM_FAIL_IF_HELPER_FAILS(parse ## NAME());             \
85             break;                                                  \
86         }
87         FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
88 #undef WASM_SECTION_PARSE
89
90         case Section::Custom: {
91             WASM_FAIL_IF_HELPER_FAILS(parseCustom(sectionLength));
92             break;
93         }
94         }
95
96         WASM_PARSER_FAIL_IF(end != m_offset, "parsing ended before the end of ", section, " section");
97
98         previousSection = section;
99     }
100
101     return WTFMove(m_result);
102 }
103
104 auto ModuleParser::parseType() -> PartialResult
105 {
106     uint32_t count;
107
108     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count");
109     WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Type section's count is too big ", count);
110     WASM_PARSER_FAIL_IF(!m_result.moduleSignatureIndicesToUniquedSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
111     WASM_PARSER_FAIL_IF(!m_result.module->usedSignatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
112
113     for (uint32_t i = 0; i < count; ++i) {
114         int8_t type;
115         uint32_t argumentCount;
116         Vector<Type> argumentTypes;
117
118         WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type");
119         WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type);
120         WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count");
121         WASM_PARSER_FAIL_IF(argumentCount == std::numeric_limits<uint32_t>::max(), i, "th argument count is too big ", argumentCount);
122         RefPtr<Signature> maybeSignature = Signature::tryCreate(argumentCount);
123         WASM_PARSER_FAIL_IF(!maybeSignature, "can't allocate enough memory for Type section's ", i, "th signature");
124         Ref<Signature> signature = maybeSignature.releaseNonNull();
125
126         for (unsigned i = 0; i < argumentCount; ++i) {
127             Type argumentType;
128             WASM_PARSER_FAIL_IF(!parseResultType(argumentType), "can't get ", i, "th argument Type");
129             signature->argument(i) = argumentType;
130         }
131
132         uint8_t returnCount;
133         WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count");
134         Type returnType;
135         if (returnCount) {
136             Type value;
137             WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
138             returnType = static_cast<Type>(value);
139         } else
140             returnType = Type::Void;
141         signature->returnType() = returnType;
142
143         std::pair<SignatureIndex, Ref<Signature>> result = SignatureInformation::adopt(WTFMove(signature));
144         m_result.moduleSignatureIndicesToUniquedSignatureIndices.uncheckedAppend(result.first);
145         m_result.module->usedSignatures.uncheckedAppend(WTFMove(result.second));
146     }
147     return { };
148 }
149
150 auto ModuleParser::parseImport() -> PartialResult
151 {
152     uint32_t importCount;
153     WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count");
154     WASM_PARSER_FAIL_IF(importCount == std::numeric_limits<uint32_t>::max(), "Import section's count is too big ", importCount);
155     WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below.
156     WASM_PARSER_FAIL_IF(!m_result.module->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below.
157     WASM_PARSER_FAIL_IF(!m_result.module->importFunctionSignatureIndices.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import function signatures"); // FIXME this over-allocates when we fix the FIXMEs below.
158
159     for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) {
160         Import imp;
161         uint32_t moduleLen;
162         uint32_t fieldLen;
163         String moduleString;
164         String fieldString;
165
166         WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length");
167         WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen);
168         imp.module = moduleString;
169
170         WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'");
171         WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'");
172         imp.field = fieldString;
173
174         WASM_PARSER_FAIL_IF(!parseExternalKind(imp.kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'");
175         switch (imp.kind) {
176         case ExternalKind::Function: {
177             uint32_t functionSignatureIndex;
178             WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'");
179             WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_result.moduleSignatureIndicesToUniquedSignatureIndices.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_result.moduleSignatureIndicesToUniquedSignatureIndices.size(), " in module '", moduleString, "' field '", fieldString, "'");
180             imp.kindIndex = m_result.module->importFunctionSignatureIndices.size();
181             SignatureIndex signatureIndex = m_result.moduleSignatureIndicesToUniquedSignatureIndices[functionSignatureIndex];
182             m_result.module->importFunctionSignatureIndices.uncheckedAppend(signatureIndex);
183             break;
184         }
185         case ExternalKind::Table: {
186             bool isImport = true;
187             PartialResult result = parseTableHelper(isImport);
188             if (UNLIKELY(!result))
189                 return result.getUnexpected();
190             break;
191         }
192         case ExternalKind::Memory: {
193             bool isImport = true;
194             PartialResult result = parseMemoryHelper(isImport);
195             if (UNLIKELY(!result))
196                 return result.getUnexpected();
197             break;
198         }
199         case ExternalKind::Global: {
200             Global global;
201             WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
202             WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported");
203
204             imp.kindIndex = m_result.module->globals.size();
205             m_result.module->globals.uncheckedAppend(WTFMove(global));
206             break;
207         }
208         }
209
210         m_result.module->imports.uncheckedAppend(imp);
211     }
212
213     m_result.module->firstInternalGlobal = m_result.module->globals.size();
214     return { };
215 }
216
217 auto ModuleParser::parseFunction() -> PartialResult
218 {
219     uint32_t count;
220     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count");
221     WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Function section's count is too big ", count);
222     WASM_PARSER_FAIL_IF(!m_result.module->internalFunctionSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures");
223     WASM_PARSER_FAIL_IF(!m_result.functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations");
224
225     for (uint32_t i = 0; i < count; ++i) {
226         uint32_t typeNumber;
227         WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number");
228         WASM_PARSER_FAIL_IF(typeNumber >= m_result.moduleSignatureIndicesToUniquedSignatureIndices.size(), i, "th Function type number is invalid ", typeNumber);
229
230         SignatureIndex signatureIndex = m_result.moduleSignatureIndicesToUniquedSignatureIndices[typeNumber];
231         // The Code section fixes up start and end.
232         size_t start = 0;
233         size_t end = 0;
234         m_result.module->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex);
235         m_result.functionLocationInBinary.uncheckedAppend({ start, end });
236     }
237
238     return { };
239 }
240
241 auto ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult
242 {
243     ASSERT(!maximum);
244
245     uint8_t flags;
246     WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags");
247     WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count");
248
249     if (flags) {
250         uint32_t maximumInt;
251         WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count");
252         WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt);
253         maximum = maximumInt;
254     }
255
256     return { };
257 }
258
259 auto ModuleParser::parseTableHelper(bool isImport) -> PartialResult
260 {
261     WASM_PARSER_FAIL_IF(m_hasTable, "Table section cannot exist if an Import has a table");
262
263     m_hasTable = true;
264
265     int8_t type;
266     WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type");
267     WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type);
268
269     uint32_t initial;
270     std::optional<uint32_t> maximum;
271     PartialResult limits = parseResizableLimits(initial, maximum);
272     if (UNLIKELY(!limits))
273         return limits.getUnexpected();
274     WASM_PARSER_FAIL_IF(!JSWebAssemblyTable::isValidSize(initial), "Table's initial page count of ", initial, " is invalid");
275
276     ASSERT(!maximum || *maximum >= initial);
277
278     m_result.module->tableInformation = TableInformation(initial, maximum, isImport);
279
280     return { };
281 }
282
283 auto ModuleParser::parseTable() -> PartialResult
284 {
285     uint32_t count;
286     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count");
287     WASM_PARSER_FAIL_IF(count != 1, "Table count of ", count, " is invalid, only 1 is allowed for now");
288
289     bool isImport = false;
290     PartialResult result = parseTableHelper(isImport);
291     if (UNLIKELY(!result))
292         return result.getUnexpected();
293
294     return { };
295 }
296
297 auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult
298 {
299     WASM_PARSER_FAIL_IF(!!m_result.module->memory, "Memory section cannot exist if an Import has a memory");
300
301     PageCount initialPageCount;
302     PageCount maximumPageCount;
303     {
304         uint32_t initial;
305         std::optional<uint32_t> maximum;
306         PartialResult limits = parseResizableLimits(initial, maximum);
307         if (UNLIKELY(!limits))
308             return limits.getUnexpected();
309         ASSERT(!maximum || *maximum >= initial);
310         WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid");
311
312         initialPageCount = PageCount(initial);
313
314         if (maximum) {
315             WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid");
316             maximumPageCount = PageCount(*maximum);
317         }
318     }
319     ASSERT(initialPageCount);
320     ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
321
322     m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, isImport);
323     return { };
324 }
325
326 auto ModuleParser::parseMemory() -> PartialResult
327 {
328     uint8_t count;
329     WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count");
330
331     if (!count)
332         return { };
333
334     WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one");
335
336     bool isImport = false;
337     return parseMemoryHelper(isImport);
338 }
339
340 auto ModuleParser::parseGlobal() -> PartialResult
341 {
342     uint32_t globalCount;
343     WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count");
344     WASM_PARSER_FAIL_IF(!m_result.module->globals.tryReserveCapacity(globalCount + m_result.module->firstInternalGlobal), "can't allocate memory for ", globalCount + m_result.module->firstInternalGlobal, " globals");
345
346     for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) {
347         Global global;
348         uint8_t initOpcode;
349
350         WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global));
351         Type typeForInitOpcode;
352         WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber, typeForInitOpcode));
353         if (initOpcode == GetGlobal)
354             global.initializationType = Global::FromGlobalImport;
355         else
356             global.initializationType = Global::FromExpression;
357         WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
358
359         m_result.module->globals.uncheckedAppend(WTFMove(global));
360     }
361
362     return { };
363 }
364
365 auto ModuleParser::parseExport() -> PartialResult
366 {
367     uint32_t exportCount;
368     WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count");
369     WASM_PARSER_FAIL_IF(exportCount == std::numeric_limits<uint32_t>::max(), "Export section's count is too big ", exportCount);
370     WASM_PARSER_FAIL_IF(!m_result.module->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports");
371
372     HashSet<String> exportNames;
373     for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) {
374         Export exp;
375         uint32_t fieldLen;
376         String fieldString;
377
378         WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length");
379         WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen);
380         WASM_PARSER_FAIL_IF(exportNames.contains(fieldString), "duplicate export: '", fieldString, "'");
381         exportNames.add(fieldString);
382         exp.field = fieldString;
383
384         WASM_PARSER_FAIL_IF(!parseExternalKind(exp.kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'");
385         WASM_PARSER_FAIL_IF(!parseVarUInt32(exp.kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'");
386         switch (exp.kind) {
387         case ExternalKind::Function: {
388             WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.module->functionIndexSpaceSize(), exportNumber, "th Export has invalid function number ", exp.kindIndex, " it exceeds the function index space ", m_result.module->functionIndexSpaceSize(), ", named '", fieldString, "'");
389             break;
390         }
391         case ExternalKind::Table: {
392             WASM_PARSER_FAIL_IF(!m_hasTable, "can't export a non-existent Table");
393             WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Table ", exp.kindIndex, " only zero-index Table is currently supported");
394             break;
395         }
396         case ExternalKind::Memory: {
397             WASM_PARSER_FAIL_IF(!m_result.module->memory, "can't export a non-existent Memory");
398             WASM_PARSER_FAIL_IF(exp.kindIndex, "can't export Memory ", exp.kindIndex, " only one Table is currently supported");
399             break;
400         }
401         case ExternalKind::Global: {
402             WASM_PARSER_FAIL_IF(exp.kindIndex >= m_result.module->globals.size(), exportNumber, "th Export has invalid global number ", exp.kindIndex, " it exceeds the globals count ", m_result.module->globals.size(), ", named '", fieldString, "'");
403             WASM_PARSER_FAIL_IF(m_result.module->globals[exp.kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'");
404             break;
405         }
406         }
407
408         m_result.module->exports.uncheckedAppend(exp);
409     }
410
411     return { };
412 }
413
414 auto ModuleParser::parseStart() -> PartialResult
415 {
416     uint32_t startFunctionIndex;
417     WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index");
418     WASM_PARSER_FAIL_IF(startFunctionIndex >= m_result.module->functionIndexSpaceSize(), "Start index ", startFunctionIndex, " exceeds function index space ", m_result.module->functionIndexSpaceSize());
419     SignatureIndex signatureIndex = m_result.module->signatureIndexFromFunctionIndexSpace(startFunctionIndex);
420     const Signature& signature = SignatureInformation::get(signatureIndex);
421     WASM_PARSER_FAIL_IF(signature.argumentCount(), "Start function can't have arguments");
422     WASM_PARSER_FAIL_IF(signature.returnType() != Void, "Start function can't return a value");
423     m_result.module->startFunctionIndexSpace = startFunctionIndex;
424     return { };
425 }
426
427 auto ModuleParser::parseElement() -> PartialResult
428 {
429     WASM_PARSER_FAIL_IF(!m_hasTable, "Element section expects a Table to be present");
430
431     uint32_t elementCount;
432     WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count");
433     WASM_PARSER_FAIL_IF(elementCount == std::numeric_limits<uint32_t>::max(), "Element section's count is too big ", elementCount);
434     WASM_PARSER_FAIL_IF(!m_result.module->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements");
435     for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) {
436         uint32_t tableIndex;
437         uint64_t initExprBits;
438         uint8_t initOpcode;
439         uint32_t indexCount;
440
441         WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
442         WASM_PARSER_FAIL_IF(tableIndex, "Element section can only have one Table for now");
443         Type initExprType;
444         WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
445         WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
446         WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
447         WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
448
449         ASSERT(!!m_result.module->tableInformation);
450
451         Element element(makeI32InitExpr(initOpcode, initExprBits));
452         WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
453
454         for (unsigned index = 0; index < indexCount; ++index) {
455             uint32_t functionIndex;
456             WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index");
457             WASM_PARSER_FAIL_IF(functionIndex >= m_result.module->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_result.module->functionIndexSpaceSize());
458
459             element.functionIndices.uncheckedAppend(functionIndex);
460         }
461
462         m_result.module->elements.uncheckedAppend(WTFMove(element));
463     }
464
465     return { };
466 }
467
468 auto ModuleParser::parseCode() -> PartialResult
469 {
470     uint32_t count;
471     WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count");
472     WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count);
473     WASM_PARSER_FAIL_IF(count != m_result.functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_result.functionLocationInBinary.size());
474
475     for (uint32_t i = 0; i < count; ++i) {
476         uint32_t functionSize;
477         WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size");
478         WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length());
479         WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset);
480
481         m_result.functionLocationInBinary[i].start = m_offset;
482         m_result.functionLocationInBinary[i].end = m_offset + functionSize;
483         m_offset = m_result.functionLocationInBinary[i].end;
484     }
485
486     return { };
487 }
488
489 auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber, Type& resultType) -> PartialResult
490 {
491     WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode");
492
493     switch (opcode) {
494     case I32Const: {
495         int32_t constant;
496         WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const");
497         bitsOrImportNumber = static_cast<uint64_t>(constant);
498         resultType = I32;
499         break;
500     }
501
502     case I64Const: {
503         int64_t constant;
504         WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const");
505         bitsOrImportNumber = constant;
506         resultType = I64;
507         break;
508     }
509
510     case F32Const: {
511         uint32_t constant;
512         WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const");
513         bitsOrImportNumber = constant;
514         resultType = F32;
515         break;
516     }
517
518     case F64Const: {
519         uint64_t constant;
520         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const");
521         bitsOrImportNumber = constant;
522         resultType = F64;
523         break;
524     }
525
526     case GetGlobal: {
527         uint32_t index;
528         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
529
530         WASM_PARSER_FAIL_IF(index >= m_result.module->globals.size(), "get_global's index ", index, " exceeds the number of globals ", m_result.module->globals.size());
531         WASM_PARSER_FAIL_IF(index >= m_result.module->firstInternalGlobal, "get_global import kind index ", index, " exceeds the first internal global ", m_result.module->firstInternalGlobal);
532
533         ASSERT(m_result.module->globals[index].mutability == Global::Immutable);
534         resultType = m_result.module->globals[index].type;
535         bitsOrImportNumber = index;
536         break;
537     }
538
539     default:
540         WASM_PARSER_FAIL_IF(false, "unknown init_expr opcode ", opcode);
541     }
542
543     uint8_t endOpcode;
544     WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode");
545     WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode);
546
547     return { };
548 }
549
550 auto ModuleParser::parseGlobalType(Global& global) -> PartialResult
551 {
552     uint8_t mutability;
553     WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type");
554     WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability");
555     global.mutability = static_cast<Global::Mutability>(mutability);
556     return { };
557 }
558
559 auto ModuleParser::parseData() -> PartialResult
560 {
561     uint32_t segmentCount;
562     WASM_PARSER_FAIL_IF(!m_result.module->memory, "Data section cannot exist without a Memory section or Import");
563     WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count");
564     WASM_PARSER_FAIL_IF(segmentCount == std::numeric_limits<uint32_t>::max(), "Data section's count is too big ", segmentCount);
565     WASM_PARSER_FAIL_IF(!m_result.module->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments");
566
567     for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) {
568         uint32_t index;
569         uint64_t initExprBits;
570         uint8_t initOpcode;
571         uint32_t dataByteLength;
572
573         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ", segmentNumber, "th Data segment's index");
574         WASM_PARSER_FAIL_IF(index, segmentNumber, "th Data segment has non-zero index ", index);
575         Type initExprType;
576         WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
577         WASM_PARSER_FAIL_IF(initExprType != I32, segmentNumber, "th Data segment's init_expr must produce an i32");
578         WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length");
579         WASM_PARSER_FAIL_IF(dataByteLength == std::numeric_limits<uint32_t>::max(), segmentNumber, "th Data segment's data byte length is too big ", dataByteLength);
580
581         Segment* segment = Segment::create(makeI32InitExpr(initOpcode, initExprBits), dataByteLength);
582         WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength);
583         m_result.module->data.uncheckedAppend(Segment::adoptPtr(segment));
584         for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) {
585             uint8_t byte;
586             WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment");
587             segment->byte(dataByte) = byte;
588         }
589     }
590     return { };
591 }
592     
593 auto ModuleParser::parseCustom(uint32_t sectionLength) -> PartialResult
594 {
595     const uint32_t customSectionStartOffset = m_offset;
596
597     CustomSection section;
598     uint32_t customSectionNumber = m_result.module->customSections.size() + 1;
599     uint32_t nameLen;
600     WASM_PARSER_FAIL_IF(!m_result.module->customSections.tryReserveCapacity(customSectionNumber), "can't allocate enough memory for ", customSectionNumber, "th custom section");
601     WASM_PARSER_FAIL_IF(!parseVarUInt32(nameLen), "can't get ", customSectionNumber, "th custom section's name length");
602     WASM_PARSER_FAIL_IF(!consumeUTF8String(section.name, nameLen), "nameLen get ", customSectionNumber, "th custom section's name of length ", nameLen);
603
604     uint32_t payloadBytes = sectionLength - (m_offset - customSectionStartOffset);
605     WASM_PARSER_FAIL_IF(!section.payload.tryReserveCapacity(payloadBytes), "can't allocate enough memory for ", customSectionNumber, "th custom section's ", payloadBytes, " bytes");
606     for (uint32_t byteNumber = 0; byteNumber < payloadBytes; ++byteNumber) {
607         uint8_t byte;
608         WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", byteNumber, "th data byte from ", customSectionNumber, "th custom section");
609         section.payload.uncheckedAppend(byte);
610     }
611     
612     m_result.module->customSections.uncheckedAppend(WTFMove(section));
613
614     return { };
615 }
616
617 } } // namespace JSC::Wasm
618
619 #endif // ENABLE(WEBASSEMBLY)