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