8f63fceda4901f404bd2ef6b849426f45aa76297
[WebKit-https.git] / Source / JavaScriptCore / wasm / WASMFunctionParser.h
1 /*
2  * Copyright (C) 2016 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 <wtf/DataLog.h>
32
33 namespace JSC { namespace WASM {
34
35 enum class BlockType {
36     If,
37     Block,
38     Loop
39 };
40
41 template<typename Context>
42 class FunctionParser : public Parser {
43 public:
44     typedef typename Context::ExpressionType ExpressionType;
45     typedef typename Context::ControlType ControlType;
46
47     FunctionParser(Context&, const Vector<uint8_t>& sourceBuffer, const FunctionInformation&);
48
49     bool WARN_UNUSED_RETURN parse();
50
51 private:
52     static const bool verbose = false;
53
54     bool WARN_UNUSED_RETURN parseBlock();
55     bool WARN_UNUSED_RETURN parseExpression(OpType);
56     bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
57     bool WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
58
59     Context& m_context;
60     Vector<ExpressionType, 1> m_expressionStack;
61     Vector<ControlType> m_controlStack;
62     unsigned m_unreachableBlocks { 0 };
63 };
64
65 template<typename Context>
66 FunctionParser<Context>::FunctionParser(Context& context, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& info)
67     : Parser(sourceBuffer, info.start, info.end)
68     , m_context(context)
69 {
70     m_context.addArguments(info.signature->arguments);
71 }
72
73 template<typename Context>
74 bool FunctionParser<Context>::parse()
75 {
76     uint32_t localCount;
77     if (!parseVarUInt32(localCount))
78         return false;
79
80     for (uint32_t i = 0; i < localCount; ++i) {
81         uint32_t numberOfLocals;
82         if (!parseVarUInt32(numberOfLocals))
83             return false;
84
85         Type typeOfLocal;
86         if (!parseValueType(typeOfLocal))
87             return false;
88
89         m_context.addLocal(typeOfLocal, numberOfLocals);
90     }
91
92     return parseBlock();
93 }
94
95 template<typename Context>
96 bool FunctionParser<Context>::parseBlock()
97 {
98     while (true) {
99         uint8_t op;
100         if (!parseUInt7(op))
101             return false;
102
103         if (verbose) {
104             dataLogLn("processing op (", m_unreachableBlocks, "): ",  RawPointer(reinterpret_cast<void*>(op)));
105             m_context.dump(m_controlStack, m_expressionStack);
106         }
107
108         if (op == OpType::End && !m_controlStack.size())
109             break;
110
111         if (m_unreachableBlocks) {
112             if (!parseUnreachableExpression(static_cast<OpType>(op))) {
113                 if (verbose)
114                     dataLogLn("failed to process unreachable op:", op);
115                 return false;
116             }
117         } else if (!parseExpression(static_cast<OpType>(op))) {
118             if (verbose)
119                 dataLogLn("failed to process op:", op);
120             return false;
121         }
122
123     }
124
125     // I'm not sure if we should check the expression stack here...
126     return true;
127 }
128 #define CREATE_CASE(name, id, b3op) case name:
129
130 template<typename Context>
131 bool FunctionParser<Context>::parseExpression(OpType op)
132 {
133     switch (op) {
134     FOR_EACH_WASM_BINARY_OP(CREATE_CASE) {
135         ExpressionType right = m_expressionStack.takeLast();
136         ExpressionType left = m_expressionStack.takeLast();
137         ExpressionType result;
138         if (!m_context.binaryOp(static_cast<BinaryOpType>(op), left, right, result))
139             return false;
140         m_expressionStack.append(result);
141         return true;
142     }
143
144     FOR_EACH_WASM_UNARY_OP(CREATE_CASE) {
145         ExpressionType arg = m_expressionStack.takeLast();
146         ExpressionType result;
147         if (!m_context.unaryOp(static_cast<UnaryOpType>(op), arg, result))
148             return false;
149         m_expressionStack.append(result);
150         return true;
151     }
152
153     case OpType::I32Const: {
154         uint32_t constant;
155         if (!parseVarUInt32(constant))
156             return false;
157         m_expressionStack.append(m_context.addConstant(I32, constant));
158         return true;
159     }
160
161     case OpType::GetLocal: {
162         uint32_t index;
163         if (!parseVarUInt32(index))
164             return false;
165         ExpressionType result;
166         if (!m_context.getLocal(index, result))
167             return false;
168
169         m_expressionStack.append(result);
170         return true;
171     }
172
173     case OpType::SetLocal: {
174         uint32_t index;
175         if (!parseVarUInt32(index))
176             return false;
177         ExpressionType value = m_expressionStack.takeLast();
178         return m_context.setLocal(index, value);
179     }
180
181     case OpType::Block: {
182         m_controlStack.append(m_context.addBlock());
183         return true;
184     }
185
186     case OpType::Loop: {
187         m_controlStack.append(m_context.addLoop());
188         return true;
189     }
190
191     case OpType::If: {
192         ExpressionType condition = m_expressionStack.takeLast();
193         m_controlStack.append(m_context.addIf(condition));
194         return true;
195     }
196
197     case OpType::Else: {
198         return m_context.addElse(m_controlStack.last());
199     }
200
201     case OpType::Branch:
202     case OpType::BranchIf: {
203         uint32_t arity;
204         if (!parseVarUInt32(arity) || arity > m_expressionStack.size())
205             return false;
206
207         uint32_t target;
208         if (!parseVarUInt32(target))
209             return false;
210
211         ExpressionType condition = Context::emptyExpression;
212         if (op == OpType::BranchIf)
213             condition = m_expressionStack.takeLast();
214         else
215             m_unreachableBlocks = 1;
216
217         Vector<ExpressionType, 1> values(arity);
218         for (unsigned i = arity; i; i--)
219             values[i-1] = m_expressionStack.takeLast();
220
221         if (target >= m_controlStack.size())
222             return false;
223         ControlType& data = m_controlStack[m_controlStack.size() - 1 - target];
224
225         return m_context.addBranch(data, condition, values);
226     }
227
228     case OpType::Return: {
229         uint8_t returnCount;
230         if (!parseVarUInt1(returnCount))
231             return false;
232         Vector<ExpressionType, 1> returnValues;
233         if (returnCount)
234             returnValues.append(m_expressionStack.takeLast());
235
236         m_unreachableBlocks = 1;
237         return m_context.addReturn(returnValues);
238     }
239
240     case OpType::End: {
241         ControlType data = m_controlStack.takeLast();
242         return m_context.endBlock(data, m_expressionStack);
243     }
244
245     }
246
247     // Unknown opcode.
248     return false;
249 }
250
251 template<typename Context>
252 bool FunctionParser<Context>::parseUnreachableExpression(OpType op)
253 {
254     ASSERT(m_unreachableBlocks);
255     switch (op) {
256     case OpType::Else: {
257         if (m_unreachableBlocks > 1)
258             return true;
259
260         ControlType& data = m_controlStack.last();
261         ASSERT(data.type() == BlockType::If);
262         m_unreachableBlocks = 0;
263         return m_context.addElse(data);
264     }
265
266     case OpType::End: {
267         if (m_unreachableBlocks == 1) {
268             ControlType data = m_controlStack.takeLast();
269             if (!m_context.isContinuationReachable(data))
270                 return true;
271         }
272         m_unreachableBlocks--;
273         return true;
274     }
275
276     case OpType::Loop:
277     case OpType::If:
278     case OpType::Block: {
279         m_unreachableBlocks++;
280         return true;
281     }
282
283     // two immediate cases
284     case OpType::Branch:
285     case OpType::BranchIf: {
286         uint32_t unused;
287         if (!parseVarUInt32(unused))
288             return false;
289         return parseVarUInt32(unused);
290     }
291
292     // one immediate cases
293     case OpType::Return:
294     case OpType::I32Const:
295     case OpType::SetLocal:
296     case OpType::GetLocal: {
297         uint32_t unused;
298         return parseVarUInt32(unused);
299     }
300
301     default:
302         break;
303     }
304     return true;
305 }
306
307 #undef CREATE_CASE
308
309 } } // namespace JSC::WASM
310
311 #endif // ENABLE(WEBASSEMBLY)