i64.eqz should use an Int64 zero
[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(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(Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info)
92     : Parser(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->arguments), "can't add ", m_signature->arguments.size(), " 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 == OpType::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_SIMPLE_BINARY_OP(CREATE_CASE)
205 #undef CREATE_CASE
206
207     case OpType::F32ConvertUI64: return unaryCase<OpType::F32ConvertUI64>();
208     case OpType::F64ConvertUI64: return unaryCase<OpType::F64ConvertUI64>();
209     case OpType::F32Nearest: return unaryCase<OpType::F32Nearest>();
210     case OpType::F64Nearest: return unaryCase<OpType::F64Nearest>();
211     case OpType::F32Trunc: return unaryCase<OpType::F32Trunc>();
212     case OpType::F64Trunc: return unaryCase<OpType::F64Trunc>();
213     case OpType::I32Ctz: return unaryCase<OpType::I32Ctz>();
214     case OpType::I64Ctz: return unaryCase<OpType::I64Ctz>();
215     case OpType::I32Popcnt: return unaryCase<OpType::I32Popcnt>();
216     case OpType::I64Popcnt: return unaryCase<OpType::I64Popcnt>();
217     case OpType::I32TruncSF32: return unaryCase<OpType::I32TruncSF32>();
218     case OpType::I32TruncUF32: return unaryCase<OpType::I32TruncUF32>();
219     case OpType::I32TruncSF64: return unaryCase<OpType::I32TruncSF64>();
220     case OpType::I32TruncUF64: return unaryCase<OpType::I32TruncUF64>();
221     case OpType::I64TruncSF32: return unaryCase<OpType::I64TruncSF32>();
222     case OpType::I64TruncUF32: return unaryCase<OpType::I64TruncUF32>();
223     case OpType::I64TruncSF64: return unaryCase<OpType::I64TruncSF64>();
224     case OpType::I64TruncUF64: return unaryCase<OpType::I64TruncUF64>();
225 #define CREATE_CASE(name, id, b3op, inc) case OpType::name: return unaryCase<OpType::name>();
226     FOR_EACH_WASM_SIMPLE_UNARY_OP(CREATE_CASE)
227 #undef CREATE_CASE
228
229     case OpType::Select: {
230         ExpressionType condition;
231         ExpressionType zero;
232         ExpressionType nonZero;
233
234         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition");
235         WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero");
236         WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero");
237
238         ExpressionType result;
239         WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result));
240
241         m_expressionStack.append(result);
242         return { };
243     }
244
245 #define CREATE_CASE(name, id, b3op, inc) case OpType::name:
246     FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
247         uint32_t alignment;
248         uint32_t offset;
249         ExpressionType pointer;
250         ExpressionType result;
251         WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
252         WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
253         WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
254         WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(op), pointer, result, offset));
255         m_expressionStack.append(result);
256         return { };
257     }
258
259     FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
260         uint32_t alignment;
261         uint32_t offset;
262         ExpressionType value;
263         ExpressionType pointer;
264         WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
265         WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
266         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
267         WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
268         WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(op), pointer, value, offset));
269         return { };
270     }
271 #undef CREATE_CASE
272
273     case OpType::F32Const: {
274         uint32_t constant;
275         WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant");
276         m_expressionStack.append(m_context.addConstant(F32, constant));
277         return { };
278     }
279
280     case OpType::I32Const: {
281         int32_t constant;
282         WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant");
283         m_expressionStack.append(m_context.addConstant(I32, constant));
284         return { };
285     }
286
287     case OpType::F64Const: {
288         uint64_t constant;
289         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
290         m_expressionStack.append(m_context.addConstant(F64, constant));
291         return { };
292     }
293
294     case OpType::I64Const: {
295         int64_t constant;
296         WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant");
297         m_expressionStack.append(m_context.addConstant(I64, constant));
298         return { };
299     }
300
301     case OpType::GetLocal: {
302         uint32_t index;
303         ExpressionType result;
304         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
305         WASM_PARSER_FAIL_IF(!m_context.getLocal(index, result), "can't get_local at index", index);
306         m_expressionStack.append(result);
307         return { };
308     }
309
310     case OpType::SetLocal: {
311         uint32_t index;
312         ExpressionType value;
313         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
314         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
315         WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
316         return { };
317     }
318
319     case OpType::TeeLocal: {
320         uint32_t index;
321         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
322         WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
323         WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
324         return { };
325     }
326
327     case OpType::GetGlobal: {
328         uint32_t index;
329         ExpressionType result;
330         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
331         WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
332         m_expressionStack.append(result);
333         return { };
334     }
335
336     case OpType::SetGlobal: {
337         uint32_t index;
338         ExpressionType value;
339         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
340         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
341         WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
342         return m_context.setGlobal(index, value);
343     }
344
345     case OpType::Call: {
346         uint32_t functionIndex;
347         WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
348         WASM_PARSER_FAIL_IF(functionIndex >= m_functionIndexSpace.size, "call function index ", functionIndex, " exceeds function index space ", m_functionIndexSpace.size);
349
350         const Signature* calleeSignature = m_functionIndexSpace.buffer.get()[functionIndex].signature;
351         WASM_PARSER_FAIL_IF(calleeSignature->arguments.size() > m_expressionStack.size(), "call function index ", functionIndex, " has ", calleeSignature->arguments.size(), " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
352
353         size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature->arguments.size();
354         Vector<ExpressionType> args;
355         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature->arguments.size()), "can't allocate enough memory for call's ", calleeSignature->arguments.size(), " arguments");
356         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
357             args.uncheckedAppend(m_expressionStack[i]);
358         m_expressionStack.shrink(firstArgumentIndex);
359
360         ExpressionType result = Context::emptyExpression;
361         WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result));
362
363         if (result != Context::emptyExpression)
364             m_expressionStack.append(result);
365
366             return { };
367     }
368
369     case OpType::CallIndirect: {
370         uint32_t signatureIndex;
371         uint8_t reserved;
372         WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
373         WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
374         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
375         WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
376         WASM_PARSER_FAIL_IF(m_info.signatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.signatures.size());
377
378         const Signature* calleeSignature = &m_info.signatures[signatureIndex];
379         size_t argumentCount = calleeSignature->arguments.size() + 1; // Add the callee's index.
380         WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
381
382         Vector<ExpressionType> args;
383         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
384         size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
385         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
386             args.uncheckedAppend(m_expressionStack[i]);
387         m_expressionStack.shrink(firstArgumentIndex);
388
389         ExpressionType result = Context::emptyExpression;
390         WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
391
392         if (result != Context::emptyExpression)
393             m_expressionStack.append(result);
394
395         return { };
396     }
397
398     case OpType::Block: {
399         Type inlineSignature;
400         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature");
401         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
402         m_expressionStack = ExpressionList();
403         return { };
404     }
405
406     case OpType::Loop: {
407         Type inlineSignature;
408         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature");
409         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
410         m_expressionStack = ExpressionList();
411         return { };
412     }
413
414     case OpType::If: {
415         Type inlineSignature;
416         ExpressionType condition;
417         ControlType control;
418         WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature");
419         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
420         WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control));
421         m_controlStack.append({ WTFMove(m_expressionStack), control });
422         m_expressionStack = ExpressionList();
423         return { };
424     }
425
426     case OpType::Else: {
427         WASM_PARSER_FAIL_IF(m_controlStack.isEmpty(), "can't use else block at the top-level of a function");
428         WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
429         m_expressionStack.shrink(0);
430         return { };
431     }
432
433     case OpType::Br:
434     case OpType::BrIf: {
435         uint32_t target;
436         ExpressionType condition = Context::emptyExpression;
437         WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
438         WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
439         if (op == OpType::BrIf)
440             WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
441         else
442             m_unreachableBlocks = 1;
443
444         ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
445
446         WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
447         return { };
448     }
449
450     case OpType::BrTable: {
451         uint32_t numberOfTargets;
452         ExpressionType condition;
453         uint32_t defaultTarget;
454         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
455         WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
456
457         Vector<ControlType*> targets;
458         WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets");
459         for (uint32_t i = 0; i < numberOfTargets; ++i) {
460             uint32_t target;
461             WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table");
462             WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size());
463             targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
464         }
465
466         WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
467         WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
468         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
469         WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
470
471         m_unreachableBlocks = 1;
472         return { };
473     }
474
475     case OpType::Return: {
476         return addReturn();
477     }
478
479     case OpType::End: {
480         ControlEntry data = m_controlStack.takeLast();
481         // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
482         // That's a little too effectful for me but I don't have a better API right now.
483         // see: https://bugs.webkit.org/show_bug.cgi?id=164353
484         WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
485         m_expressionStack.swap(data.enclosedExpressionStack);
486         return { };
487     }
488
489     case OpType::Unreachable: {
490         WASM_TRY_ADD_TO_CONTEXT(addUnreachable());
491         m_unreachableBlocks = 1;
492         return { };
493     }
494
495     case OpType::Drop: {
496         WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack");
497         m_expressionStack.takeLast();
498         return { };
499     }
500
501     case OpType::Nop: {
502         return { };
503     }
504
505     case OpType::GrowMemory:
506         return fail("not yet implemented: grow_memory"); // FIXME: Not yet implemented.
507
508     case OpType::CurrentMemory:
509         return fail("not yet implemented: current_memory"); // FIXME: Not yet implemented.
510
511     }
512
513     ASSERT_NOT_REACHED();
514 }
515
516 template<typename Context>
517 auto FunctionParser<Context>::parseUnreachableExpression(OpType op) -> PartialResult
518 {
519     ASSERT(m_unreachableBlocks);
520     switch (op) {
521     case OpType::Else: {
522         if (m_unreachableBlocks > 1)
523             return { };
524
525         ControlEntry& data = m_controlStack.last();
526         m_unreachableBlocks = 0;
527         WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
528         m_expressionStack.shrink(0);
529         return { };
530     }
531
532     case OpType::End: {
533         if (m_unreachableBlocks == 1) {
534             ControlEntry data = m_controlStack.takeLast();
535             WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
536             m_expressionStack.swap(data.enclosedExpressionStack);
537         }
538         m_unreachableBlocks--;
539         return { };
540     }
541
542     case OpType::Loop:
543     case OpType::If:
544     case OpType::Block: {
545         m_unreachableBlocks++;
546         return { };
547     }
548
549     // two immediate cases
550     case OpType::Br:
551     case OpType::BrIf: {
552         uint32_t unused;
553         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
554         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get br / br_if in unreachable context");
555         return { };
556     }
557
558     // one immediate cases
559     case OpType::F32Const:
560     case OpType::I32Const:
561     case OpType::F64Const:
562     case OpType::I64Const:
563     case OpType::SetLocal:
564     case OpType::GetLocal: {
565         uint32_t unused;
566         WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get const / local in unreachable context");
567         return { };
568     }
569
570     default:
571         break;
572     }
573     return { };
574 }
575
576 } } // namespace JSC::Wasm
577
578 #endif // ENABLE(WEBASSEMBLY)