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