5d404c7044b3620cc1861a6006d037ad10bd0b5a
[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     if (m_returnType != WASMExpressionType::Void)
230         parseExpression(context, m_returnType);
231     // FIXME: Implement this instruction.
232     return UNUSED;
233 }
234
235 template <class Context>
236 ContextStatement WASMFunctionParser::parseBlockStatement(Context& context)
237 {
238     uint32_t numberOfStatements;
239     READ_COMPACT_UINT32_OR_FAIL(numberOfStatements, "Cannot read the number of statements.");
240     for (uint32_t i = 0; i < numberOfStatements; ++i) {
241         parseStatement(context);
242         PROPAGATE_ERROR();
243     }
244     return UNUSED;
245 }
246
247 template <class Context>
248 ContextStatement WASMFunctionParser::parseIfStatement(Context& context)
249 {
250     parseExpressionI32(context);
251     PROPAGATE_ERROR();
252     parseStatement(context);
253     // FIXME: Implement this instruction.
254     return UNUSED;
255 }
256
257 template <class Context>
258 ContextStatement WASMFunctionParser::parseIfElseStatement(Context& context)
259 {
260     parseExpressionI32(context);
261     PROPAGATE_ERROR();
262     parseStatement(context);
263     PROPAGATE_ERROR();
264     parseStatement(context);
265     // FIXME: Implement this instruction.
266     return UNUSED;
267 }
268
269 template <class Context>
270 ContextStatement WASMFunctionParser::parseWhileStatement(Context& context)
271 {
272     parseExpressionI32(context);
273     PROPAGATE_ERROR();
274
275     m_breakScopeDepth++;
276     m_continueScopeDepth++;
277     parseStatement(context);
278     PROPAGATE_ERROR();
279     m_continueScopeDepth--;
280     m_breakScopeDepth--;
281     // FIXME: Implement this instruction.
282     return UNUSED;
283 }
284
285 template <class Context>
286 ContextStatement WASMFunctionParser::parseDoStatement(Context& context)
287 {
288     m_breakScopeDepth++;
289     m_continueScopeDepth++;
290     parseStatement(context);
291     PROPAGATE_ERROR();
292     m_continueScopeDepth--;
293     m_breakScopeDepth--;
294
295     parseExpressionI32(context);
296     // FIXME: Implement this instruction.
297     return UNUSED;
298 }
299
300 template <class Context>
301 ContextStatement WASMFunctionParser::parseLabelStatement(Context& context)
302 {
303     m_labelDepth++;
304     parseStatement(context);
305     PROPAGATE_ERROR();
306     m_labelDepth--;
307     // FIXME: Implement this instruction.
308     return UNUSED;
309 }
310
311 template <class Context>
312 ContextStatement WASMFunctionParser::parseBreakStatement(Context&)
313 {
314     FAIL_IF_FALSE(m_breakScopeDepth, "'break' is only valid inside a switch or loop statement.");
315     // FIXME: Implement this instruction.
316     return UNUSED;
317 }
318
319 template <class Context>
320 ContextStatement WASMFunctionParser::parseBreakLabelStatement(Context&)
321 {
322     uint32_t labelIndex;
323     READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
324     FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
325     // FIXME: Implement this instruction.
326     return UNUSED;
327 }
328
329 template <class Context>
330 ContextStatement WASMFunctionParser::parseContinueStatement(Context&)
331 {
332     FAIL_IF_FALSE(m_continueScopeDepth, "'continue' is only valid inside a loop statement.");
333     // FIXME: Implement this instruction.
334     return UNUSED;
335 }
336
337 template <class Context>
338 ContextStatement WASMFunctionParser::parseContinueLabelStatement(Context&)
339 {
340     uint32_t labelIndex;
341     READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index.");
342     FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect.");
343     // FIXME: Implement this instruction.
344     return UNUSED;
345 }
346
347 template <class Context>
348 ContextStatement WASMFunctionParser::parseSwitchStatement(Context& context)
349 {
350     uint32_t numberOfCases;
351     READ_COMPACT_UINT32_OR_FAIL(numberOfCases, "Cannot read the number of cases.");
352     parseExpressionI32(context);
353     PROPAGATE_ERROR();
354
355     m_breakScopeDepth++;
356     for (uint32_t i = 0; i < numberOfCases; ++i) {
357         WASMSwitchCase switchCase;
358         READ_SWITCH_CASE_OR_FAIL(switchCase, "Cannot read the switch case.");
359         switch (switchCase) {
360         case WASMSwitchCase::CaseWithNoStatements:
361         case WASMSwitchCase::CaseWithStatement:
362         case WASMSwitchCase::CaseWithBlockStatement: {
363             uint32_t value;
364             READ_COMPACT_INT32_OR_FAIL(value, "Cannot read the value of the switch case.");
365             if (switchCase == WASMSwitchCase::CaseWithStatement) {
366                 parseStatement(context);
367                 PROPAGATE_ERROR();
368             } else if (switchCase == WASMSwitchCase::CaseWithBlockStatement) {
369                 parseBlockStatement(context);
370                 PROPAGATE_ERROR();
371             }
372             break;
373         }
374         case WASMSwitchCase::DefaultWithNoStatements:
375         case WASMSwitchCase::DefaultWithStatement:
376         case WASMSwitchCase::DefaultWithBlockStatement: {
377             FAIL_IF_FALSE(i == numberOfCases - 1, "The default case must be the last case.");
378             if (switchCase == WASMSwitchCase::DefaultWithStatement) {
379                 parseStatement(context);
380                 PROPAGATE_ERROR();
381             } else if (switchCase == WASMSwitchCase::DefaultWithBlockStatement) {
382                 parseBlockStatement(context);
383                 PROPAGATE_ERROR();
384             }
385             break;
386         }
387         default:
388             ASSERT_NOT_REACHED();
389         }
390     }
391     m_breakScopeDepth--;
392     // FIXME: Implement this instruction.
393     return UNUSED;
394 }
395
396 template <class Context>
397 ContextExpression WASMFunctionParser::parseExpression(Context& context, WASMExpressionType expressionType)
398 {
399     switch (expressionType) {
400     case WASMExpressionType::I32:
401         return parseExpressionI32(context);
402     case WASMExpressionType::F32:
403     case WASMExpressionType::F64:
404     case WASMExpressionType::Void:
405         // FIXME: Implement these instructions.
406         FAIL_WITH_MESSAGE("Unsupported instruction.");
407     default:
408         ASSERT_NOT_REACHED();
409     }
410     return 0;
411 }
412
413 template <class Context>
414 ContextExpression WASMFunctionParser::parseExpressionI32(Context& context)
415 {
416     bool hasImmediate;
417     WASMOpExpressionI32 op;
418     WASMOpExpressionI32WithImmediate opWithImmediate;
419     uint8_t immediate;
420     READ_OP_EXPRESSION_I32_OR_FAIL(hasImmediate, op, opWithImmediate, immediate, "Cannot read the int32 expression opcode.");
421     if (!hasImmediate) {
422         switch (op) {
423         case WASMOpExpressionI32::Immediate:
424             return parseImmediateExpressionI32(context);
425         case WASMOpExpressionI32::ConstantPoolIndex:
426         case WASMOpExpressionI32::GetLocal:
427         case WASMOpExpressionI32::GetGlobal:
428         case WASMOpExpressionI32::SetLocal:
429         case WASMOpExpressionI32::SetGlobal:
430         case WASMOpExpressionI32::SLoad8:
431         case WASMOpExpressionI32::SLoadWithOffset8:
432         case WASMOpExpressionI32::ULoad8:
433         case WASMOpExpressionI32::ULoadWithOffset8:
434         case WASMOpExpressionI32::SLoad16:
435         case WASMOpExpressionI32::SLoadWithOffset16:
436         case WASMOpExpressionI32::ULoad16:
437         case WASMOpExpressionI32::ULoadWithOffset16:
438         case WASMOpExpressionI32::Load32:
439         case WASMOpExpressionI32::LoadWithOffset32:
440         case WASMOpExpressionI32::Store8:
441         case WASMOpExpressionI32::StoreWithOffset8:
442         case WASMOpExpressionI32::Store16:
443         case WASMOpExpressionI32::StoreWithOffset16:
444         case WASMOpExpressionI32::Store32:
445         case WASMOpExpressionI32::StoreWithOffset32:
446         case WASMOpExpressionI32::CallInternal:
447         case WASMOpExpressionI32::CallIndirect:
448         case WASMOpExpressionI32::CallImport:
449         case WASMOpExpressionI32::Conditional:
450         case WASMOpExpressionI32::Comma:
451         case WASMOpExpressionI32::FromF32:
452         case WASMOpExpressionI32::FromF64:
453         case WASMOpExpressionI32::Negate:
454         case WASMOpExpressionI32::Add:
455         case WASMOpExpressionI32::Sub:
456         case WASMOpExpressionI32::Mul:
457         case WASMOpExpressionI32::SDiv:
458         case WASMOpExpressionI32::UDiv:
459         case WASMOpExpressionI32::SMod:
460         case WASMOpExpressionI32::UMod:
461         case WASMOpExpressionI32::BitNot:
462         case WASMOpExpressionI32::BitOr:
463         case WASMOpExpressionI32::BitAnd:
464         case WASMOpExpressionI32::BitXor:
465         case WASMOpExpressionI32::LeftShift:
466         case WASMOpExpressionI32::ArithmeticRightShift:
467         case WASMOpExpressionI32::LogicalRightShift:
468         case WASMOpExpressionI32::CountLeadingZeros:
469         case WASMOpExpressionI32::LogicalNot:
470         case WASMOpExpressionI32::EqualI32:
471         case WASMOpExpressionI32::EqualF32:
472         case WASMOpExpressionI32::EqualF64:
473         case WASMOpExpressionI32::NotEqualI32:
474         case WASMOpExpressionI32::NotEqualF32:
475         case WASMOpExpressionI32::NotEqualF64:
476         case WASMOpExpressionI32::SLessThanI32:
477         case WASMOpExpressionI32::ULessThanI32:
478         case WASMOpExpressionI32::LessThanF32:
479         case WASMOpExpressionI32::LessThanF64:
480         case WASMOpExpressionI32::SLessThanOrEqualI32:
481         case WASMOpExpressionI32::ULessThanOrEqualI32:
482         case WASMOpExpressionI32::LessThanOrEqualF32:
483         case WASMOpExpressionI32::LessThanOrEqualF64:
484         case WASMOpExpressionI32::SGreaterThanI32:
485         case WASMOpExpressionI32::UGreaterThanI32:
486         case WASMOpExpressionI32::GreaterThanF32:
487         case WASMOpExpressionI32::GreaterThanF64:
488         case WASMOpExpressionI32::SGreaterThanOrEqualI32:
489         case WASMOpExpressionI32::UGreaterThanOrEqualI32:
490         case WASMOpExpressionI32::GreaterThanOrEqualF32:
491         case WASMOpExpressionI32::GreaterThanOrEqualF64:
492         case WASMOpExpressionI32::SMin:
493         case WASMOpExpressionI32::UMin:
494         case WASMOpExpressionI32::SMax:
495         case WASMOpExpressionI32::UMax:
496         case WASMOpExpressionI32::Abs:
497             // FIXME: Implement these instructions.
498             FAIL_WITH_MESSAGE("Unsupported instruction.");
499         default:
500             ASSERT_NOT_REACHED();
501         }
502     } else {
503         switch (opWithImmediate) {
504         case WASMOpExpressionI32WithImmediate::Immediate:
505             return parseImmediateExpressionI32(context, immediate);
506         case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:
507         case WASMOpExpressionI32WithImmediate::GetLocal:
508             // FIXME: Implement these instructions.
509             FAIL_WITH_MESSAGE("Unsupported instruction.");
510         default:
511             ASSERT_NOT_REACHED();
512         }
513     }
514     return 0;
515 }
516
517 template <class Context>
518 ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context&, uint32_t)
519 {
520     // FIXME: Implement this instruction.
521     return UNUSED;
522 }
523
524 template <class Context>
525 ContextExpression WASMFunctionParser::parseImmediateExpressionI32(Context& context)
526 {
527     uint32_t immediate;
528     READ_COMPACT_UINT32_OR_FAIL(immediate, "Cannot read the immediate.");
529     return parseImmediateExpressionI32(context, immediate);
530 }
531
532 } // namespace JSC
533
534 #endif // ENABLE(WEBASSEMBLY)