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, " with signature: ", signature);
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 TableGet: {
285 WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
286 ExpressionType result, idx;
287 WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.get");
288 WASM_TRY_ADD_TO_CONTEXT(addTableGet(idx, result));
289 m_expressionStack.append(result);
290 return { };
291 }
292
293 case TableSet: {
294 WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
295 ExpressionType val, idx;
296 WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
297 WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.set");
298 WASM_TRY_ADD_TO_CONTEXT(addTableSet(idx, val));
299 return { };
300 }
301
302 case RefNull: {
303 WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
304 m_expressionStack.append(m_context.addConstant(Anyref, JSValue::encode(jsNull())));
305 return { };
306 }
307
308 case RefIsNull: {
309 WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
310 ExpressionType result, value;
311 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "ref.is_null");
312 WASM_TRY_ADD_TO_CONTEXT(addRefIsNull(value, result));
313 m_expressionStack.append(result);
314 return { };
315 }
316
317 case GetLocal: {
318 uint32_t index;
319 ExpressionType result;
320 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
321 WASM_TRY_ADD_TO_CONTEXT(getLocal(index, result));
322 m_expressionStack.append(result);
323 return { };
324 }
325
326 case SetLocal: {
327 uint32_t index;
328 ExpressionType value;
329 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
330 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
331 WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
332 return { };
333 }
334
335 case TeeLocal: {
336 uint32_t index;
337 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
338 WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
339 WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
340 return { };
341 }
342
343 case GetGlobal: {
344 uint32_t index;
345 ExpressionType result;
346 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
347 WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
348 m_expressionStack.append(result);
349 return { };
350 }
351
352 case SetGlobal: {
353 uint32_t index;
354 ExpressionType value;
355 WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
356 WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
357 WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
358 return { };
359 }
360
361 case Call: {
362 uint32_t functionIndex;
363 WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't parse call's function index");
364 WASM_PARSER_FAIL_IF(functionIndex >= m_info.functionIndexSpaceSize(), "call function index ", functionIndex, " exceeds function index space ", m_info.functionIndexSpaceSize());
365
366 SignatureIndex calleeSignatureIndex = m_info.signatureIndexFromFunctionIndexSpace(functionIndex);
367 const Signature& calleeSignature = SignatureInformation::get(calleeSignatureIndex);
368 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");
369
370 size_t firstArgumentIndex = m_expressionStack.size() - calleeSignature.argumentCount();
371 Vector<ExpressionType> args;
372 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature.argumentCount()), "can't allocate enough memory for call's ", calleeSignature.argumentCount(), " arguments");
373 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
374 args.uncheckedAppend(m_expressionStack[i]);
375 m_expressionStack.shrink(firstArgumentIndex);
376
377 ExpressionType result = Context::emptyExpression();
378 WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, result));
379
380 if (result != Context::emptyExpression())
381 m_expressionStack.append(result);
382
383 return { };
384 }
385
386 case CallIndirect: {
387 uint32_t signatureIndex;
388 uint8_t reserved;
389 WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
390 WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
391 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
392 WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
393 WASM_PARSER_FAIL_IF(m_info.usedSignatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.usedSignatures.size());
394 WASM_PARSER_FAIL_IF(m_info.tableInformation.type() != TableElementType::Funcref, "call_indirect is only valid when a table has type anyfunc");
395
396 const Signature& calleeSignature = m_info.usedSignatures[signatureIndex].get();
397 size_t argumentCount = calleeSignature.argumentCount() + 1; // Add the callee's index.
398 WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
399
400 Vector<ExpressionType> args;
401 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
402 size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
403 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
404 args.uncheckedAppend(m_expressionStack[i]);
405 m_expressionStack.shrink(firstArgumentIndex);
406
407 ExpressionType result = Context::emptyExpression();
408 WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
409
410 if (result != Context::emptyExpression())
411 m_expressionStack.append(result);
412
413 return { };
414 }
415
416 case Block: {
417 Type inlineSignature;
418 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get block's inline signature");
419 m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
420 m_expressionStack = ExpressionList();
421 return { };
422 }
423
424 case Loop: {
425 Type inlineSignature;
426 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get loop's inline signature");
427 m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
428 m_expressionStack = ExpressionList();
429 return { };
430 }
431
432 case If: {
433 Type inlineSignature;
434 ExpressionType condition;
435 ControlType control;
436 WASM_PARSER_FAIL_IF(!parseResultType(inlineSignature), "can't get if's inline signature");
437 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
438 WASM_TRY_ADD_TO_CONTEXT(addIf(condition, inlineSignature, control));
439 m_controlStack.append({ WTFMove(m_expressionStack), control });
440 m_expressionStack = ExpressionList();
441 return { };
442 }
443
444 case Else: {
445 WASM_PARSER_FAIL_IF(m_controlStack.size() == 1, "can't use else block at the top-level of a function");
446 WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
447 m_expressionStack.shrink(0);
448 return { };
449 }
450
451 case Br:
452 case BrIf: {
453 uint32_t target;
454 ExpressionType condition = Context::emptyExpression();
455 WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
456 WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
457 if (m_currentOpcode == BrIf)
458 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
459 else
460 m_unreachableBlocks = 1;
461
462 ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
463
464 WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
465 return { };
466 }
467
468 case BrTable: {
469 uint32_t numberOfTargets;
470 uint32_t defaultTarget;
471 ExpressionType condition;
472 Vector<ControlType*> targets;
473
474 WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
475 WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
476
477 WASM_PARSER_FAIL_IF(!targets.tryReserveCapacity(numberOfTargets), "can't allocate memory for ", numberOfTargets, " br_table targets");
478 for (uint32_t i = 0; i < numberOfTargets; ++i) {
479 uint32_t target;
480 WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get ", i, "th target for br_table");
481 WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br_table's ", i, "th target ", target, " exceeds control stack size ", m_controlStack.size());
482 targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
483 }
484
485 WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
486 WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
487
488 WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
489 WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
490
491 m_unreachableBlocks = 1;
492 return { };
493 }
494
495 case Return: {
496 ExpressionList returnValues;
497 if (m_signature.returnType() != Void) {
498 ExpressionType returnValue;
499 WASM_TRY_POP_EXPRESSION_STACK_INTO(returnValue, "return");
500 returnValues.append(returnValue);
501 }
502
503 WASM_TRY_ADD_TO_CONTEXT(addReturn(m_controlStack[0].controlData, returnValues));
504 m_unreachableBlocks = 1;
505 return { };
506 }
507
508 case End: {
509 ControlEntry data = m_controlStack.takeLast();
510 // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
511 // That's a little too effectful for me but I don't have a better API right now.
512 // see: https://bugs.webkit.org/show_bug.cgi?id=164353
513 WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
514 m_expressionStack.swap(data.enclosedExpressionStack);
515 return { };
516 }
517
518 case Unreachable: {
519 WASM_TRY_ADD_TO_CONTEXT(addUnreachable());
520 m_unreachableBlocks = 1;
521 return { };
522 }
523
524 case Drop: {
525 WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack");
526 auto expression = m_expressionStack.takeLast();
527 m_toKillAfterExpression.append(expression);
528 return { };
529 }
530
531 case Nop: {
532 return { };
533 }
534
535 case GrowMemory: {
536 WASM_PARSER_FAIL_IF(!m_info.memory, "grow_memory is only valid if a memory is defined or imported");
537
538 uint8_t reserved;
539 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory");
540 WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for grow_memory must be zero");
541
542 ExpressionType delta;
543 WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "expect an i32 argument to grow_memory on the stack");
544
545 ExpressionType result;
546 WASM_TRY_ADD_TO_CONTEXT(addGrowMemory(delta, result));
547 m_expressionStack.append(result);
548
549 return { };
550 }
551
552 case CurrentMemory: {
553 WASM_PARSER_FAIL_IF(!m_info.memory, "current_memory is only valid if a memory is defined or imported");
554
555 uint8_t reserved;
556 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for current_memory");
557 WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for current_memory must be zero");
558
559 ExpressionType result;
560 WASM_TRY_ADD_TO_CONTEXT(addCurrentMemory(result));
561 m_expressionStack.append(result);
562
563 return { };
564 }
565 }
566
567 ASSERT_NOT_REACHED();
568 return { };
569}
570
571// 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
572template<typename Context>
573auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult
574{
575 ASSERT(m_unreachableBlocks);
576#define CREATE_CASE(name, id, b3op, inc) case OpType::name:
577 switch (m_currentOpcode) {
578 case Else: {
579 if (m_unreachableBlocks > 1)
580 return { };
581
582 ControlEntry& data = m_controlStack.last();
583 m_unreachableBlocks = 0;
584 WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
585 m_expressionStack.shrink(0);
586 return { };
587 }
588
589 case End: {
590 if (m_unreachableBlocks == 1) {
591 ControlEntry data = m_controlStack.takeLast();
592 WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
593 m_expressionStack.swap(data.enclosedExpressionStack);
594 }
595 m_unreachableBlocks--;
596 return { };
597 }
598
599 case Loop:
600 case If:
601 case Block: {
602 m_unreachableBlocks++;
603 Type unused;
604 WASM_PARSER_FAIL_IF(!parseResultType(unused), "can't get inline type for ", m_currentOpcode, " in unreachable context");
605 return { };
606 }
607
608 case BrTable: {
609 uint32_t numberOfTargets;
610 uint32_t unused;
611 WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table in unreachable context");
612 WASM_PARSER_FAIL_IF(numberOfTargets == std::numeric_limits<uint32_t>::max(), "br_table's number of targets is too big ", numberOfTargets);
613
614 for (uint32_t i = 0; i < numberOfTargets; ++i)
615 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get ", i, "th target for br_table in unreachable context");
616
617 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get default target for br_table in unreachable context");
618 return { };
619 }
620
621 case CallIndirect: {
622 uint32_t unused;
623 uint8_t unused2;
624 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get call_indirect's signature index in unreachable context");
625 WASM_PARSER_FAIL_IF(!parseVarUInt1(unused2), "can't get call_indirect's reserved byte in unreachable context");
626 return { };
627 }
628
629 case F32Const: {
630 uint32_t unused;
631 WASM_PARSER_FAIL_IF(!parseUInt32(unused), "can't parse 32-bit floating-point constant");
632 return { };
633 }
634
635 case F64Const: {
636 uint64_t constant;
637 WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
638 return { };
639 }
640
641 // two immediate cases
642 FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE)
643 FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
644 uint32_t unused;
645 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get first immediate for ", m_currentOpcode, " in unreachable context");
646 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get second immediate for ", m_currentOpcode, " in unreachable context");
647 return { };
648 }
649
650 // one immediate cases
651 case SetLocal:
652 case GetLocal:
653 case TeeLocal:
654 case GetGlobal:
655 case SetGlobal:
656 case Br:
657 case BrIf:
658 case Call: {
659 uint32_t unused;
660 WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get immediate for ", m_currentOpcode, " in unreachable context");
661 return { };
662 }
663
664 case I32Const: {
665 int32_t unused;
666 WASM_PARSER_FAIL_IF(!parseVarInt32(unused), "can't get immediate for ", m_currentOpcode, " in unreachable context");
667 return { };
668 }
669
670 case I64Const: {
671 int64_t unused;
672 WASM_PARSER_FAIL_IF(!parseVarInt64(unused), "can't get immediate for ", m_currentOpcode, " in unreachable context");
673 return { };
674 }
675
676 case TableGet:
677 case TableSet:
678 case RefIsNull:
679 case RefNull: {
680 WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
681 return { };
682 }
683
684 case GrowMemory:
685 case CurrentMemory: {
686 uint8_t reserved;
687 WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory/current_memory");
688 return { };
689 }
690
691 // no immediate cases
692 FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
693 FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
694 case Unreachable:
695 case Nop:
696 case Return:
697 case Select:
698 case Drop: {
699 return { };
700 }
701 }
702#undef CREATE_CASE
703 RELEASE_ASSERT_NOT_REACHED();
704}
705
706} } // namespace JSC::Wasm
707
708#endif // ENABLE(WEBASSEMBLY)
709