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