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