c8b64848feeb49edce6a6ef2393a718eb609e62b
[WebKit-https.git] / Source / JavaScriptCore / wasm / WASMFunctionParser.cpp
1 /*
2  * Copyright (C) 2015 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 #include "config.h"
27 #include "WASMFunctionParser.h"
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "JSWASMModule.h"
32 #include "WASMFunctionCompiler.h"
33 #include "WASMFunctionSyntaxChecker.h"
34
35 #define PROPAGATE_ERROR() do { if (!m_errorMessage.isNull()) return 0; } while (0)
36 #define FAIL_WITH_MESSAGE(errorMessage) do {  m_errorMessage = errorMessage; return 0; } while (0)
37 #define READ_COMPACT_INT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readCompactInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
38 #define READ_COMPACT_UINT32_OR_FAIL(result, errorMessage) do { if (!m_reader.readCompactUInt32(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
39 #define READ_OP_STATEMENT_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpStatement(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
40 #define READ_OP_EXPRESSION_I32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, errorMessage) do { if (!m_reader.readOpExpressionI32(hasImmediate, op, opWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
41 #define READ_VARIABLE_TYPES_OR_FAIL(hasImmediate, variableTypes, variableTypesWithImmediate, immediate, errorMessage) do { if (!m_reader.readVariableTypes(hasImmediate, variableTypes, variableTypesWithImmediate, immediate)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
42 #define READ_SWITCH_CASE_OR_FAIL(result, errorMessage) do { if (!m_reader.readSwitchCase(result)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
43 #define FAIL_IF_FALSE(condition, errorMessage) do { if (!(condition)) FAIL_WITH_MESSAGE(errorMessage); } while (0)
44
45 #define UNUSED 0
46
47 namespace JSC {
48
49 bool WASMFunctionParser::checkSyntax(JSWASMModule* module, const SourceCode& source, size_t functionIndex, unsigned startOffsetInSource, unsigned& endOffsetInSource, unsigned& stackHeight, String& errorMessage)
50 {
51     WASMFunctionParser parser(module, source, functionIndex);
52     WASMFunctionSyntaxChecker syntaxChecker;
53     parser.m_reader.setOffset(startOffsetInSource);
54     parser.parseFunction(syntaxChecker);
55     if (!parser.m_errorMessage.isNull()) {
56         errorMessage = parser.m_errorMessage;
57         return false;
58     }
59     endOffsetInSource = parser.m_reader.offset();
60     stackHeight = syntaxChecker.stackHeight();
61     return true;
62 }
63
64 void WASMFunctionParser::compile(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, const SourceCode& source, size_t functionIndex)
65 {
66     WASMFunctionParser parser(module, source, functionIndex);
67     WASMFunctionCompiler compiler(vm, codeBlock, module->functionStackHeights()[functionIndex]);
68     parser.m_reader.setOffset(module->functionStartOffsetsInSource()[functionIndex]);
69     parser.parseFunction(compiler);
70     ASSERT(parser.m_errorMessage.isNull());
71 }
72
73 template <class Context>
74 bool WASMFunctionParser::parseFunction(Context& context)
75 {
76     const WASMSignature& signature = m_module->signatures()[m_module->functionDeclarations()[m_functionIndex].signatureIndex];
77
78     m_returnType = signature.returnType;
79
80     parseLocalVariables();
81     PROPAGATE_ERROR();
82
83     const Vector<WASMType>& arguments = signature.arguments;
84     for (size_t i = 0; i < arguments.size(); ++i)
85         m_localTypes.append(arguments[i]);
86     for (uint32_t i = 0; i < m_numberOfI32LocalVariables; ++i)
87         m_localTypes.append(WASMType::I32);
88     for (uint32_t i = 0; i < m_numberOfF32LocalVariables; ++i)
89         m_localTypes.append(WASMType::F32);
90     for (uint32_t i = 0; i < m_numberOfF64LocalVariables; ++i)
91         m_localTypes.append(WASMType::F64);
92
93     context.startFunction(arguments, m_numberOfI32LocalVariables, m_numberOfF32LocalVariables, m_numberOfF64LocalVariables);
94
95     parseBlockStatement(context);
96     PROPAGATE_ERROR();
97
98     context.endFunction();
99     return true;
100 }
101
102 bool WASMFunctionParser::parseLocalVariables()
103 {
104     m_numberOfI32LocalVariables = 0;
105     m_numberOfF32LocalVariables = 0;
106     m_numberOfF64LocalVariables = 0;
107
108     bool hasImmediate;
109     WASMVariableTypes variableTypes;
110     WASMVariableTypesWithImmediate variableTypesWithImmediate;
111     uint8_t immediate;
112     READ_VARIABLE_TYPES_OR_FAIL(hasImmediate, variableTypes, variableTypesWithImmediate, immediate, "Cannot read the types of local variables.");
113     if (!hasImmediate) {
114         if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::I32))
115             READ_COMPACT_UINT32_OR_FAIL(m_numberOfI32LocalVariables, "Cannot read the number of int32 local variables.");
116         if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::F32))
117             READ_COMPACT_UINT32_OR_FAIL(m_numberOfF32LocalVariables, "Cannot read the number of float32 local variables.");
118         if (static_cast<uint8_t>(variableTypes) & static_cast<uint8_t>(WASMVariableTypes::F64))
119             READ_COMPACT_UINT32_OR_FAIL(m_numberOfF64LocalVariables, "Cannot read the number of float64 local variables.");
120     } else
121         m_numberOfI32LocalVariables = immediate;
122     return true;
123 }
124
125 template <class Context>
126 ContextStatement WASMFunctionParser::parseStatement(Context& context)
127 {
128     bool hasImmediate;
129     WASMOpStatement op;
130     WASMOpStatementWithImmediate opWithImmediate;
131     uint8_t immediate;
132     READ_OP_STATEMENT_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the statement opcode.");
133     if (!hasImmediate) {
134         switch (op) {
135         case WASMOpStatement::SetLocal:
136             parseSetLocalStatement(context);
137             break;
138         case WASMOpStatement::Return:
139             parseReturnStatement(context);
140             break;
141         case WASMOpStatement::Block:
142             parseBlockStatement(context);
143             break;
144         case WASMOpStatement::If:
145             parseIfStatement(context);
146             break;
147         case WASMOpStatement::IfElse:
148             parseIfElseStatement(context);
149             break;
150         case WASMOpStatement::While:
151             parseWhileStatement(context);
152             break;
153         case WASMOpStatement::Do:
154             parseDoStatement(context);
155             break;
156         case WASMOpStatement::Label:
157             parseLabelStatement(context);
158             break;
159         case WASMOpStatement::Break:
160             parseBreakStatement(context);
161             break;
162         case WASMOpStatement::BreakLabel:
163             parseBreakLabelStatement(context);
164             break;
165         case WASMOpStatement::Continue:
166             parseContinueStatement(context);
167             break;
168         case WASMOpStatement::ContinueLabel:
169             parseContinueLabelStatement(context);
170             break;
171         case WASMOpStatement::Switch:
172             parseSwitchStatement(context);
173             break;
174         case WASMOpStatement::SetGlobal:
175         case WASMOpStatement::I32Store8:
176         case WASMOpStatement::I32StoreWithOffset8:
177         case WASMOpStatement::I32Store16:
178         case WASMOpStatement::I32StoreWithOffset16:
179         case WASMOpStatement::I32Store32:
180         case WASMOpStatement::I32StoreWithOffset32:
181         case WASMOpStatement::F32Store:
182         case WASMOpStatement::F32StoreWithOffset:
183         case WASMOpStatement::F64Store:
184         case WASMOpStatement::F64StoreWithOffset:
185         case WASMOpStatement::CallInternal:
186         case WASMOpStatement::CallIndirect:
187         case WASMOpStatement::CallImport:
188             // FIXME: Implement these instructions.
189             FAIL_WITH_MESSAGE("Unsupported instruction.");
190         default:
191             ASSERT_NOT_REACHED();
192         }
193     } else {
194         switch (opWithImmediate) {
195         case WASMOpStatementWithImmediate::SetLocal:
196             parseSetLocalStatement(context, immediate);
197             break;
198         case WASMOpStatementWithImmediate::SetGlobal:
199             // FIXME: Implement this instruction.
200             FAIL_WITH_MESSAGE("Unsupported instruction.");
201         default:
202             ASSERT_NOT_REACHED();
203         }
204     }
205     return UNUSED;
206 }
207
208 template <class Context>
209 ContextStatement WASMFunctionParser::parseSetLocalStatement(Context& context, uint32_t localIndex)
210 {
211     FAIL_IF_FALSE(localIndex < m_localTypes.size(), "The local variable index is incorrect.");
212     WASMType type = m_localTypes[localIndex];
213     parseExpression(context, WASMExpressionType(type));
214     // FIXME: Implement this instruction.
215     return UNUSED;
216 }
217
218 template <class Context>
219 ContextStatement WASMFunctionParser::parseSetLocalStatement(Context& context)
220 {
221     uint32_t localIndex;
222     READ_COMPACT_UINT32_OR_FAIL(localIndex, "Cannot read the local index.");
223     return parseSetLocalStatement(context, localIndex);
224 }
225
226 template <class Context>
227 ContextStatement WASMFunctionParser::parseReturnStatement(Context& context)
228 {
229     ContextExpression expression = 0;
230     if (m_returnType != WASMExpressionType::Void) {
231         expression = parseExpression(context, m_returnType);
232         PROPAGATE_ERROR();
233     }
234     context.buildReturn(expression, m_returnType);
235     return UNUSED;
236 }
237
238 template <class Context>
239 ContextStatement WASMFunctionParser::parseBlockStatement(Context& context)
240 {
241     uint32_t numberOfStatements;
242     READ_COMPACT_UINT32_OR_FAIL(numberOfStatements, "Cannot read the number of statements.");
243     for (uint32_t i = 0; i < numberOfStatements; ++i) {
244         parseStatement(context);
245         PROPAGATE_ERROR();
246     }
247     return UNUSED;
248 }
249
250 template <class Context>
251 ContextStatement WASMFunctionParser::parseIfStatement(Context& context)
252 {
253     parseExpressionI32(context);
254     PROPAGATE_ERROR();
255     parseStatement(context);
256     // FIXME: Implement this instruction.
257     return UNUSED;
258 }
259
260 template <class Context>
261 ContextStatement WASMFunctionParser::parseIfElseStatement(Context& context)
262 {
263     parseExpressionI32(context);
264     PROPAGATE_ERROR();
265     parseStatement(context);
266     PROPAGATE_ERROR();
267     parseStatement(context);
268     // FIXME: Implement this instruction.
269     return UNUSED;
270 }
271
272 template <class Context>
273 ContextStatement WASMFunctionParser::parseWhileStatement(Context& context)
274 {
275     parseExpressionI32(context);
276     PROPAGATE_ERROR();
277
278     m_breakScopeDepth++;
279     m_continueScopeDepth++;
280     parseStatement(context);
281     PROPAGATE_ERROR();
282     m_continueScopeDepth--;
283     m_breakScopeDepth--;
284     // FIXME: Implement this instruction.
285     return UNUSED;
286 }
287
288 template <class Context>
289 ContextStatement WASMFunctionParser::parseDoStatement(Context& context)
290 {
291     m_breakScopeDepth++;
292     m_continueScopeDepth++;
293     parseStatement(context);
294     PROPAGATE_ERROR();
295     m_continueScopeDepth--;
296     m_breakScopeDepth--;
297
298     parseExpressionI32(context);
299     // FIXME: Implement this instruction.
300     return UNUSED;
301 }
302
303 template <class Context>
304 ContextStatement WASMFunctionParser::parseLabelStatement(Context& context)
305 {
306     m_labelDepth++;
307     parseStatement(context);
308     PROPAGATE_ERROR();
309     m_labelDepth--;
310     // FIXME: Implement this instruction.
311     return UNUSED;
312 }
313
314 template <class Context>
315 ContextStatement WASMFunctionParser::parseBreakStatement(Context&)
316 {
317     FAIL_IF_FALSE(m_breakScopeDepth, "'break' is only valid inside a switch or loop statement.");
318     // FIXME: Implement this instruction.
319     return UNUSED;
320 }
321
322 template <class Context>
323 ContextStatement WASMFunctionParser::parseBreakLabelStatement(Context&)
324 {
325     uint32_t labelIndex;
326     READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
327     FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
328     // FIXME: Implement this instruction.
329     return UNUSED;
330 }
331
332 template <class Context>
333 ContextStatement WASMFunctionParser::parseContinueStatement(Context&)
334 {
335     FAIL_IF_FALSE(m_continueScopeDepth, "'continue' is only valid inside a loop statement.");
336     // FIXME: Implement this instruction.
337     return UNUSED;
338 }
339
340 template <class Context>
341 ContextStatement WASMFunctionParser::parseContinueLabelStatement(Context&)
342 {
343     uint32_t labelIndex;
344     READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
345     FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
346     // FIXME: Implement this instruction.
347     return UNUSED;
348 }
349
350 template <class Context>
351 ContextStatement WASMFunctionParser::parseSwitchStatement(Context& context)
352 {
353     uint32_t numberOfCases;
354     READ_COMPACT_UINT32_OR_FAIL(numberOfCases, "Cannot read the number of cases.");
355     parseExpressionI32(context);
356     PROPAGATE_ERROR();
357
358     m_breakScopeDepth++;
359     for (uint32_t i = 0; i < numberOfCases; ++i) {
360         WASMSwitchCase switchCase;
361         READ_SWITCH_CASE_OR_FAIL(switchCase, "Cannot read the switch case.");
362         switch (switchCase) {
363         case WASMSwitchCase::CaseWithNoStatements:
364         case WASMSwitchCase::CaseWithStatement:
365         case WASMSwitchCase::CaseWithBlockStatement: {
366             uint32_t value;
367             READ_COMPACT_INT32_OR_FAIL(value, "Cannot read the value of the switch case.");
368             if (switchCase == WASMSwitchCase::CaseWithStatement) {
369                 parseStatement(context);
370                 PROPAGATE_ERROR();
371             } else if (switchCase == WASMSwitchCase::CaseWithBlockStatement) {
372                 parseBlockStatement(context);
373                 PROPAGATE_ERROR();
374             }
375             break;
376         }
377         case WASMSwitchCase::DefaultWithNoStatements:
378         case WASMSwitchCase::DefaultWithStatement:
379         case WASMSwitchCase::DefaultWithBlockStatement: {
380             FAIL_IF_FALSE(i == numberOfCases - 1, "The default case must be the last case.");
381             if (switchCase == WASMSwitchCase::DefaultWithStatement) {
382                 parseStatement(context);
383                 PROPAGATE_ERROR();
384             } else if (switchCase == WASMSwitchCase::DefaultWithBlockStatement) {
385                 parseBlockStatement(context);
386                 PROPAGATE_ERROR();
387             }
388             break;
389         }
390         default:
391             ASSERT_NOT_REACHED();
392         }
393     }
394     m_breakScopeDepth--;
395     // FIXME: Implement this instruction.
396     return UNUSED;
397 }
398
399 template <class Context>
400 ContextExpression WASMFunctionParser::parseExpression(Context& context, WASMExpressionType expressionType)
401 {
402     switch (expressionType) {
403     case WASMExpressionType::I32:
404         return parseExpressionI32(context);
405     case WASMExpressionType::F32:
406     case WASMExpressionType::F64:
407     case WASMExpressionType::Void:
408         // FIXME: Implement these instructions.
409         FAIL_WITH_MESSAGE("Unsupported instruction.");
410     default:
411         ASSERT_NOT_REACHED();
412     }
413     return 0;
414 }
415
416 template <class Context>
417 ContextExpression WASMFunctionParser::parseExpressionI32(Context& context)
418 {
419     bool hasImmediate;
420     WASMOpExpressionI32 op;
421     WASMOpExpressionI32WithImmediate opWithImmediate;
422     uint8_t immediate;
423     READ_OP_EXPRESSION_I32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the int32 expression opcode.");
424     if (!hasImmediate) {
425         switch (op) {
426         case WASMOpExpressionI32::Immediate:
427             return parseImmediateExpressionI32(context);
428         case WASMOpExpressionI32::Add:
429         case WASMOpExpressionI32::Sub:
430             return parseBinaryExpressionI32(context, op);
431         case WASMOpExpressionI32::ConstantPoolIndex:
432         case WASMOpExpressionI32::GetLocal:
433         case WASMOpExpressionI32::GetGlobal:
434         case WASMOpExpressionI32::SetLocal:
435         case WASMOpExpressionI32::SetGlobal:
436         case WASMOpExpressionI32::SLoad8:
437         case WASMOpExpressionI32::SLoadWithOffset8:
438         case WASMOpExpressionI32::ULoad8:
439         case WASMOpExpressionI32::ULoadWithOffset8:
440         case WASMOpExpressionI32::SLoad16:
441         case WASMOpExpressionI32::SLoadWithOffset16:
442         case WASMOpExpressionI32::ULoad16:
443         case WASMOpExpressionI32::ULoadWithOffset16:
444         case WASMOpExpressionI32::Load32:
445         case WASMOpExpressionI32::LoadWithOffset32:
446         case WASMOpExpressionI32::Store8:
447         case WASMOpExpressionI32::StoreWithOffset8:
448         case WASMOpExpressionI32::Store16:
449         case WASMOpExpressionI32::StoreWithOffset16:
450         case WASMOpExpressionI32::Store32:
451         case WASMOpExpressionI32::StoreWithOffset32:
452         case WASMOpExpressionI32::CallInternal:
453         case WASMOpExpressionI32::CallIndirect:
454         case WASMOpExpressionI32::CallImport:
455         case WASMOpExpressionI32::Conditional:
456         case WASMOpExpressionI32::Comma:
457         case WASMOpExpressionI32::FromF32:
458         case WASMOpExpressionI32::FromF64:
459         case WASMOpExpressionI32::Negate:
460         case WASMOpExpressionI32::Mul:
461         case WASMOpExpressionI32::SDiv:
462         case WASMOpExpressionI32::UDiv:
463         case WASMOpExpressionI32::SMod:
464         case WASMOpExpressionI32::UMod:
465         case WASMOpExpressionI32::BitNot:
466         case WASMOpExpressionI32::BitOr:
467         case WASMOpExpressionI32::BitAnd:
468         case WASMOpExpressionI32::BitXor:
469         case WASMOpExpressionI32::LeftShift:
470         case WASMOpExpressionI32::ArithmeticRightShift:
471         case WASMOpExpressionI32::LogicalRightShift:
472         case WASMOpExpressionI32::CountLeadingZeros:
473         case WASMOpExpressionI32::LogicalNot:
474         case WASMOpExpressionI32::EqualI32:
475         case WASMOpExpressionI32::EqualF32:
476         case WASMOpExpressionI32::EqualF64:
477         case WASMOpExpressionI32::NotEqualI32:
478         case WASMOpExpressionI32::NotEqualF32:
479         case WASMOpExpressionI32::NotEqualF64:
480         case WASMOpExpressionI32::SLessThanI32:
481         case WASMOpExpressionI32::ULessThanI32:
482         case WASMOpExpressionI32::LessThanF32:
483         case WASMOpExpressionI32::LessThanF64:
484         case WASMOpExpressionI32::SLessThanOrEqualI32:
485         case WASMOpExpressionI32::ULessThanOrEqualI32:
486         case WASMOpExpressionI32::LessThanOrEqualF32:
487         case WASMOpExpressionI32::LessThanOrEqualF64:
488         case WASMOpExpressionI32::SGreaterThanI32:
489         case WASMOpExpressionI32::UGreaterThanI32:
490         case WASMOpExpressionI32::GreaterThanF32:
491         case WASMOpExpressionI32::GreaterThanF64:
492         case WASMOpExpressionI32::SGreaterThanOrEqualI32:
493         case WASMOpExpressionI32::UGreaterThanOrEqualI32:
494         case WASMOpExpressionI32::GreaterThanOrEqualF32:
495         case WASMOpExpressionI32::GreaterThanOrEqualF64:
496         case WASMOpExpressionI32::SMin:
497         case WASMOpExpressionI32::UMin:
498         case WASMOpExpressionI32::SMax:
499         case WASMOpExpressionI32::UMax:
500         case WASMOpExpressionI32::Abs:
501             // FIXME: Implement these instructions.
502             FAIL_WITH_MESSAGE("Unsupported instruction.");
503         default:
504             ASSERT_NOT_REACHED();
505         }
506     } else {
507         switch (opWithImmediate) {
508         case WASMOpExpressionI32WithImmediate::Immediate:
509             return parseImmediateExpressionI32(context, immediate);
510         case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:
511         case WASMOpExpressionI32WithImmediate::GetLocal:
512             // FIXME: Implement these instructions.
513             FAIL_WITH_MESSAGE("Unsupported instruction.");
514         default:
515             ASSERT_NOT_REACHED();
516         }
517     }
518     return 0;
519 }
520
521 template <class Context>
522 ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context, uint32_t immediate)
523 {
524     return context.buildImmediateI32(immediate);
525 }
526
527 template <class Context>
528 ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context)
529 {
530     uint32_t immediate;
531     READ_COMPACT_UINT32_OR_FAIL(immediate, "Cannot read the immediate.");
532     return parseImmediateExpressionI32(context, immediate);
533 }
534
535 template <class Context>
536 ContextExpression WASMFunctionParser::parseBinaryExpressionI32(Context& context, WASMOpExpressionI32 op)
537 {
538     ContextExpression left = parseExpressionI32(context);
539     PROPAGATE_ERROR();
540     ContextExpression right = parseExpressionI32(context);
541     PROPAGATE_ERROR();
542     return context.buildBinaryI32(left, right, op);
543 }
544
545 } // namespace JSC
546
547 #endif // ENABLE(WEBASSEMBLY)