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