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