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