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