WebAssembly: Make WebAssembly.instantiate/compile truly asynchronous
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmFunctionParser.h
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 #pragma once
27
28 #if ENABLE(WEBASSEMBLY)
29
30 #include "WasmParser.h"
31 #include <wtf/DataLog.h>
32
33 namespace JSC { namespace Wasm {
34
35 enum class BlockType {
36     If,
37     Block,
38     Loop,
39     TopLevel
40 };
41
42 template<typename Context>
43 class FunctionParser : public Parser<void> {
44 public:
45     typedef typename Context::ExpressionType ExpressionType;
46     typedef typename Context::ControlType ControlType;
47     typedef typename Context::ExpressionList ExpressionList;
48
49     FunctionParser(VM*, Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const ModuleInformation&, const Vector<SignatureIndex>&);
50
51     Result WARN_UNUSED_RETURN parse();
52
53     struct ControlEntry {
54         ExpressionList enclosedExpressionStack;
55         ControlType controlData;
56     };
57
58 private:
59     static const bool verbose = false;
60
61     PartialResult WARN_UNUSED_RETURN parseBody();
62     PartialResult WARN_UNUSED_RETURN parseExpression(OpType);
63     PartialResult WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
64     PartialResult WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
65
66 #define WASM_TRY_POP_EXPRESSION_STACK_INTO(result, what) do {                               \
67         WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \
68         result = m_expressionStack.takeLast();                                              \
69     } while (0)
70
71     template<OpType>
72     PartialResult WARN_UNUSED_RETURN unaryCase();
73
74     template<OpType>
75     PartialResult WARN_UNUSED_RETURN binaryCase();
76
77 #define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression)
78
79     // FIXME add a macro as above for WASM_TRY_APPEND_TO_CONTROL_STACK https://bugs.webkit.org/show_bug.cgi?id=165862
80
81     Context& m_context;
82     ExpressionList m_expressionStack;
83     Vector<ControlEntry> m_controlStack;
84     const Signature* m_signature;
85     const ModuleInformation& m_info;
86     const Vector<SignatureIndex>& m_moduleSignatureIndicesToUniquedSignatureIndices;
87     unsigned m_unreachableBlocks { 0 };
88 };
89
90 template<typename Context>
91 FunctionParser<Context>::FunctionParser(VM* vm, Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ModuleInformation& info, const Vector<SignatureIndex>& moduleSignatureIndicesToUniquedSignatureIndices)
92     : Parser(vm, functionStart, functionLength)
93     , m_context(context)
94     , m_signature(signature)
95     , m_info(info)
96     , m_moduleSignatureIndicesToUniquedSignatureIndices(moduleSignatureIndicesToUniquedSignatureIndices)
97 {
98     if (verbose)
99         dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength);
100 }
101
102 template<typename Context>
103 auto FunctionParser<Context>::parse() -> Result
104 {
105     uint32_t localCount;
106
107     WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature), "can't add ", m_signature->argumentCount(), " arguments to Function");
108     WASM_PARSER_FAIL_IF(!parseVarUInt32(localCount), "can't get local count");
109     WASM_PARSER_FAIL_IF(localCount == std::numeric_limits<uint32_t>::max(), "Function section's local count is too big ", localCount);
110
111     for (uint32_t i = 0; i < localCount; ++i) {
112         uint32_t numberOfLocals;
113         Type typeOfLocal;
114
115         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i);
116         WASM_PARSER_FAIL_IF(numberOfLocals == std::numeric_limits<uint32_t>::max(), "Function section's ", i, "th local group count is too big ", numberOfLocals);
117         WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
118         WASM_TRY_ADD_TO_CONTEXT(addLocal(typeOfLocal, numberOfLocals));
119     }
120
121     WASM_FAIL_IF_HELPER_FAILS(parseBody());
122
123     return { };
124 }
125
126 template<typename Context>
127 auto FunctionParser<Context>::parseBody() -> PartialResult
128 {
129     m_controlStack.append({ ExpressionList(), m_context.addTopLevel(m_signature->returnType()) });
130     uint8_t op;
131     while (m_controlStack.size()) {
132         WASM_PARSER_FAIL_IF(!parseUInt8(op), "can't decode opcode");
133         WASM_PARSER_FAIL_IF(!isValidOpType(op), "invalid opcode ", op);
134
135         if (verbose) {
136             dataLogLn("processing op (", m_unreachableBlocks, "): ",  RawPointer(reinterpret_cast<void*>(op)), ", ", makeString(static_cast<OpType>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
137             m_context.dump(m_controlStack, &m_expressionStack);
138         }
139
140         if (m_unreachableBlocks)
141             WASM_FAIL_IF_HELPER_FAILS(parseUnreachableExpression(static_cast<OpType>(op)));
142         else
143             WASM_FAIL_IF_HELPER_FAILS(parseExpression(static_cast<OpType>(op)));
144     }
145
146     ASSERT(op == OpType::End);
147     return { };
148 }
149
150 template<typename Context>
151 template<OpType op>
152 auto FunctionParser<Context>::binaryCase() -> PartialResult
153 {
154     ExpressionType right;
155     ExpressionType left;
156     ExpressionType result;
157
158     WASM_TRY_POP_EXPRESSION_STACK_INTO(right, "binary right");
159     WASM_TRY_POP_EXPRESSION_STACK_INTO(left, "binary left");
160     WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result));
161
162     m_expressionStack.append(result);
163     return { };
164 }
165
166 template<typename Context>
167 template<OpType op>
168 auto FunctionParser<Context>::unaryCase() -> PartialResult
169 {
170     ExpressionType value;
171     ExpressionType result;
172
173     WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "unary");
174     WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(value, result));
175
176     m_expressionStack.append(result);
177     return { };
178 }
179
180 template<typename Context>
181 auto FunctionParser<Context>::parseExpression(OpType op) -> PartialResult
182 {
183     switch (op) {
184 #define CREATE_CASE(name, id, b3op, inc) case OpType::name: return binaryCase<OpType::name>();
185     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
186 #undef CREATE_CASE
187
188 #define CREATE_CASE(name, id, b3op, inc) case OpType::name: return unaryCase<OpType::name>();
189     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
190 #undef CREATE_CASE
191
192     case Select: {
193         ExpressionType condition;
194         ExpressionType zero;
195         ExpressionType nonZero;
196
197         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition");
198         WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero");
199         WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero");
200
201         ExpressionType result;
202         WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result));
203
204         m_expressionStack.append(result);
205         return { };
206     }
207
208 #define CREATE_CASE(name, id, b3op, inc) case OpType::name:
209     FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
210         uint32_t alignment;
211         uint32_t offset;
212         ExpressionType pointer;
213         ExpressionType result;
214         WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
215         // FIXME validate alignment. https://bugs.webkit.org/show_bug.cgi?id=168836
216         WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
217         WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
218         WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(op), pointer, result, offset));
219         m_expressionStack.append(result);
220         return { };
221     }
222
223     FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
224         uint32_t alignment;
225         uint32_t offset;
226         ExpressionType value;
227         ExpressionType pointer;
228         WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
229         // FIXME validate alignment. https://bugs.webkit.org/show_bug.cgi?id=168836
230         WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
231         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
232         WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
233         WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(op), pointer, value, offset));
234         return { };
235     }
236 #undef CREATE_CASE
237
238     case F32Const: {
239         uint32_t constant;
240         WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant");
241         m_expressionStack.append(m_context.addConstant(F32, constant));
242         return { };
243     }
244
245     case I32Const: {
246         int32_t constant;
247         WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant");
248         m_expressionStack.append(m_context.addConstant(I32, constant));
249         return { };
250     }
251
252     case F64Const: {
253         uint64_t constant;
254         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
255         m_expressionStack.append(m_context.addConstant(F64, constant));
256         return { };
257     }
258
259     case I64Const: {
260         int64_t constant;
261         WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant");
262         m_expressionStack.append(m_context.addConstant(I64, constant));
263         return { };
264     }
265
266     case GetLocal: {
267         uint32_t index;
268         ExpressionType result;
269         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
270         WASM_TRY_ADD_TO_CONTEXT(getLocal(index, result));
271         m_expressionStack.append(result);
272         return { };
273     }
274
275     case SetLocal: {
276         uint32_t index;
277         ExpressionType value;
278         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
279         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
280         WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
281         return { };
282     }
283
284     case TeeLocal: {
285         uint32_t index;
286         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
287         WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
288         WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
289         return { };
290     }
291
292     case GetGlobal: {
293         uint32_t index;
294         ExpressionType result;
295         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
296         WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
297         m_expressionStack.append(result);
298         return { };
299     }
300
301     case SetGlobal: {
302         uint32_t index;
303         ExpressionType value;
304         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
305         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
306         WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
307         return { };
308     }
309
310     case Call: {
311         uint32_t functionIndex;
312         WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
313         WASM_PARSER_FAIL_IF(functionIndex >= m_info.functionIndexSpaceSize(), "call function index ", functionIndex, " exceeds function index space ", m_info.functionIndexSpaceSize());
314
315         SignatureIndex calleeSignatureIndex = m_info.signatureIndexFromFunctionIndexSpace(functionIndex);
316         const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
317         WASM_PARSER_FAIL_IF(calleeSignature->argumentCount() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->argumentCount(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
318
319         size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->argumentCount();
320         Vector<ExpressionType> args;
321         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->argumentCount()), "can't allocate enough memory for call's ", calleeSignature->argumentCount(), " arguments");
322         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
323             args.uncheckedAppend(m_expressionStack[i]);
324         m_expressionStack.shrink(firstArgumentIndex);
325
326         ExpressionType result = Context::emptyExpression;
327         WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result));
328
329         if (result != Context::emptyExpression)
330             m_expressionStack.append(result);
331
332         return { };
333     }
334
335     case CallIndirect: {
336         uint32_t signatureIndex;
337         uint8_t reserved;
338         WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
339         WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
340         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
341         WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
342         WASM_PARSER_FAIL_IF(m_moduleSignatureIndicesToUniquedSignatureIndices.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_moduleSignatureIndicesToUniquedSignatureIndices.size());
343
344         SignatureIndex calleeSignatureIndex = m_moduleSignatureIndicesToUniquedSignatureIndices[signatureIndex];
345         const Signature* calleeSignature = SignatureInformation::get(m_vm, calleeSignatureIndex);
346         size_t argumentCount = calleeSignature->argumentCount() + 1; // Add the callee's index.
347         WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
348
349         Vector<ExpressionType> args;
350         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
351         size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
352         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
353             args.uncheckedAppend(m_expressionStack[i]);
354         m_expressionStack.shrink(firstArgumentIndex);
355
356         ExpressionType result = Context::emptyExpression;
357         WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, calleeSignatureIndex, args, result));
358
359         if (result != Context::emptyExpression)
360             m_expressionStack.append(result);
361
362         return { };
363     }
364
365     case Block: {
366         Type inlineSignature;
367         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature");
368         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
369         m_expressionStack = ExpressionList();
370         return { };
371     }
372
373     case Loop: {
374         Type inlineSignature;
375         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature");
376         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
377         m_expressionStack = ExpressionList();
378         return { };
379     }
380
381     case If: {
382         Type inlineSignature;
383         ExpressionType condition;
384         ControlType control;
385         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature");
386         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
387         WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control));
388         m_controlStack.append({ WTFMove(m_expressionStack), control });
389         m_expressionStack = ExpressionList();
390         return { };
391     }
392
393     case Else: {
394         WASM_PARSER_FAIL_IF(m_controlStack.size() == 1, "can't use else block at the top-level of a function");
395         WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
396         m_expressionStack.shrink(0);
397         return { };
398     }
399
400     case Br:
401     case BrIf: {
402         uint32_t target;
403         ExpressionType condition = Context::emptyExpression;
404         WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
405         WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
406         if (op == BrIf)
407             WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
408         else
409             m_unreachableBlocks = 1;
410
411         ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
412
413         WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
414         return { };
415     }
416
417     case BrTable: {
418         uint32_t numberOfTargets;
419         uint32_t defaultTarget;
420         ExpressionType condition;
421         Vector<ControlType*> targets;
422
423         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
424         WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
425
426         WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets");
427         for (uint32_t i = 0; i < numberOfTargets; ++i) {
428             uint32_t target;
429             WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table");
430             WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size());
431             targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
432         }
433
434         WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
435         WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
436
437         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
438         WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
439
440         m_unreachableBlocks = 1;
441         return { };
442     }
443
444     case Return: {
445         ExpressionList returnValues;
446         if (m_signature->returnType() != Void) {
447             ExpressionType returnValue;
448             WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return");
449             returnValues.append(returnValue);
450         }
451
452         WASM_TRY_ADD_TO_CONTEXT(addReturn(m_controlStack[0].controlData, returnValues));
453         m_unreachableBlocks = 1;
454         return { };
455     }
456
457     case End: {
458         ControlEntry data = m_controlStack.takeLast();
459         // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
460         // That's a little too effectful for me but I don't have a better API right now.
461         // see: https://bugs.webkit.org/show_bug.cgi?id=164353
462         WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
463         m_expressionStack.swap(data.enclosedExpressionStack);
464         return { };
465     }
466
467     case Unreachable: {
468         WASM_TRY_ADD_TO_CONTEXT(addUnreachable());
469         m_unreachableBlocks = 1;
470         return { };
471     }
472
473     case Drop: {
474         WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack");
475         m_expressionStack.takeLast();
476         return { };
477     }
478
479     case Nop: {
480         return { };
481     }
482
483     case GrowMemory: {
484         WASM_PARSER_FAIL_IF(!m_info.memory, "grow_memory is only valid if a memory is defined or imported");
485
486         uint8_t reserved;
487         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory");
488         WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for grow_memory must be zero");
489
490         ExpressionType delta;
491         WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "expect an i32 argument to grow_memory on the stack");
492
493         ExpressionType result;
494         WASM_TRY_ADD_TO_CONTEXT(addGrowMemory(delta, result));
495         m_expressionStack.append(result);
496
497         return { };
498     }
499
500     case CurrentMemory: {
501         WASM_PARSER_FAIL_IF(!m_info.memory, "current_memory is only valid if a memory is defined or imported");
502
503         uint8_t reserved;
504         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for current_memory");
505         WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for current_memory must be zero");
506
507         ExpressionType result;
508         WASM_TRY_ADD_TO_CONTEXT(addCurrentMemory(result));
509         m_expressionStack.append(result);
510
511         return { };
512     }
513     }
514
515     ASSERT_NOT_REACHED();
516     return { };
517 }
518
519 // FIXME: We should try to use the same decoder function for both unreachable and reachable code. https://bugs.webkit.org/show_bug.cgi?id=165965
520 template<typename Context>
521 auto FunctionParser<Context>::parseUnreachableExpression(OpType op) -> PartialResult
522 {
523     ASSERT(m_unreachableBlocks);
524 #define CREATE_CASE(name, id, b3op, inc) case OpType::name:
525     switch (op) {
526     case Else: {
527         if (m_unreachableBlocks > 1)
528             return { };
529
530         ControlEntry& data = m_controlStack.last();
531         m_unreachableBlocks = 0;
532         WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
533         m_expressionStack.shrink(0);
534         return { };
535     }
536
537     case End: {
538         if (m_unreachableBlocks == 1) {
539             ControlEntry data = m_controlStack.takeLast();
540             WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
541             m_expressionStack.swap(data.enclosedExpressionStack);
542         }
543         m_unreachableBlocks--;
544         return { };
545     }
546
547     case Loop:
548     case If:
549     case Block: {
550         m_unreachableBlocks++;
551         Type unused;
552         WASM_PARSER_FAIL_IF(!parseResultType(unused), "can't get inline type for ", op, " in unreachable context");
553         return { };
554     }
555
556     case BrTable: {
557         uint32_t numberOfTargets;
558         uint32_t unused;
559         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table in unreachable context");
560         WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
561
562         for (uint32_t i = 0; i < numberOfTargets; ++i)
563             WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get ", i, "th target for br_table in unreachable context");
564
565         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get default target for br_table in unreachable context");
566         return { };
567     }
568
569     case CallIndirect: {
570         uint32_t unused;
571         uint8_t unused2;
572         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get call_indirect's signature index in unreachable context");
573         WASM_PARSER_FAIL_IF(!parseVarUInt1(unused2), "can't get call_indirect's reserved byte in unreachable context");
574         return { };
575     }
576
577     case F32Const: {
578         uint32_t unused;
579         WASM_PARSER_FAIL_IF(!parseUInt32(unused), "can't parse 32-bit floating-point constant");
580         return { };
581     }
582
583     case F64Const: {
584         uint64_t constant;
585         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
586         return { };
587     }
588
589     // two immediate cases
590     FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE)
591     FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
592         uint32_t unused;
593         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get first immediate for ", op, " in unreachable context");
594         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get second immediate for ", op, " in unreachable context");
595         return { };
596     }
597
598     // one immediate cases
599     case I32Const:
600     case I64Const:
601     case SetLocal:
602     case GetLocal:
603     case TeeLocal:
604     case GetGlobal:
605     case SetGlobal:
606     case Br:
607     case BrIf:
608     case Call: {
609         uint32_t unused;
610         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get immediate for ", op, " in unreachable context");
611         return { };
612     }
613
614     case GrowMemory:
615     case CurrentMemory: {
616         uint8_t reserved;
617         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory/current_memory");
618         return { };
619     }
620
621     // no immediate cases
622     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
623     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
624     case Unreachable:
625     case Nop:
626     case Return:
627     case Select:
628     case Drop: {
629         return { };
630     }
631     }
632 #undef CREATE_CASE
633     RELEASE_ASSERT_NOT_REACHED();
634 }
635
636 } } // namespace JSC::Wasm
637
638 #endif // ENABLE(WEBASSEMBLY)