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