Move Wasm tests to JS
[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     typedef typename Context::ExpressionList ExpressionList;
47
48     FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature*, const Vector<FunctionInformation>& functions);
49
50     bool WARN_UNUSED_RETURN parse();
51
52     struct ControlEntry {
53         ExpressionList enclosedExpressionStack;
54         ControlType controlData;
55     };
56
57 private:
58     static const bool verbose = false;
59
60     bool WARN_UNUSED_RETURN parseBody();
61     bool WARN_UNUSED_RETURN parseExpression(OpType);
62     bool WARN_UNUSED_RETURN parseUnreachableExpression(OpType);
63     bool WARN_UNUSED_RETURN addReturn();
64     bool WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
65
66     bool WARN_UNUSED_RETURN popExpressionStack(ExpressionType& result);
67
68     void setErrorMessage(String&& message) { m_context.setErrorMessage(WTFMove(message)); }
69
70     Context& m_context;
71     ExpressionList m_expressionStack;
72     Vector<ControlEntry> m_controlStack;
73     const Signature* m_signature;
74     const Vector<FunctionInformation>& m_functions;
75     unsigned m_unreachableBlocks { 0 };
76 };
77
78 template<typename Context>
79 FunctionParser<Context>::FunctionParser(Context& context, const uint8_t* functionStart, size_t functionLength, const Signature* signature, const Vector<FunctionInformation>& functions)
80     : Parser(functionStart, functionLength)
81     , m_context(context)
82     , m_signature(signature)
83     , m_functions(functions)
84 {
85     if (verbose)
86         dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength);
87 }
88
89 template<typename Context>
90 bool FunctionParser<Context>::parse()
91 {
92     if (!m_context.addArguments(m_signature->arguments))
93         return false;
94
95     uint32_t localCount;
96     if (!parseVarUInt32(localCount))
97         return false;
98
99     for (uint32_t i = 0; i < localCount; ++i) {
100         uint32_t numberOfLocals;
101         if (!parseVarUInt32(numberOfLocals))
102             return false;
103
104         Type typeOfLocal;
105         if (!parseValueType(typeOfLocal))
106             return false;
107
108         if (!m_context.addLocal(typeOfLocal, numberOfLocals))
109             return false;
110     }
111
112     return parseBody();
113 }
114
115 template<typename Context>
116 bool FunctionParser<Context>::parseBody()
117 {
118     while (true) {
119         uint8_t op;
120         if (!parseUInt7(op) || !isValidOpType(op)) {
121             if (verbose)
122                 WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
123             return false;
124         }
125
126         if (verbose) {
127             dataLogLn("processing op (", m_unreachableBlocks, "): ",  RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
128             m_context.dump(m_controlStack, m_expressionStack);
129         }
130
131         if (op == OpType::End && !m_controlStack.size())
132             return m_unreachableBlocks ? true : addReturn();
133
134         if (m_unreachableBlocks) {
135             if (!parseUnreachableExpression(static_cast<OpType>(op))) {
136                 if (verbose)
137                     dataLogLn("failed to process unreachable op:", op);
138                 return false;
139             }
140         } else if (!parseExpression(static_cast<OpType>(op))) {
141             if (verbose)
142                 dataLogLn("failed to process op:", op);
143             return false;
144         }
145
146     }
147
148     RELEASE_ASSERT_NOT_REACHED();
149 }
150
151 template<typename Context>
152 bool FunctionParser<Context>::addReturn()
153 {
154     ExpressionList returnValues;
155     if (m_signature->returnType != Void) {
156         ExpressionType returnValue;
157         if (!popExpressionStack(returnValue))
158             return false;
159         returnValues.append(returnValue);
160     }
161
162     m_unreachableBlocks = 1;
163     return m_context.addReturn(returnValues);
164 }
165
166 #define CREATE_CASE(name, id, b3op) case name:
167
168 template<typename Context>
169 bool FunctionParser<Context>::parseExpression(OpType op)
170 {
171     switch (op) {
172     FOR_EACH_WASM_BINARY_OP(CREATE_CASE) {
173         ExpressionType right;
174         if (!popExpressionStack(right))
175             return false;
176
177         ExpressionType left;
178         if (!popExpressionStack(left))
179             return false;
180
181         ExpressionType result;
182         if (!m_context.binaryOp(static_cast<BinaryOpType>(op), left, right, result))
183             return false;
184         m_expressionStack.append(result);
185         return true;
186     }
187
188     FOR_EACH_WASM_UNARY_OP(CREATE_CASE) {
189         ExpressionType value;
190         if (!popExpressionStack(value))
191             return false;
192
193         ExpressionType result;
194         if (!m_context.unaryOp(static_cast<UnaryOpType>(op), value, result))
195             return false;
196         m_expressionStack.append(result);
197         return true;
198     }
199
200     FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
201         uint32_t alignment;
202         if (!parseVarUInt32(alignment))
203             return false;
204
205         uint32_t offset;
206         if (!parseVarUInt32(offset))
207             return false;
208
209         ExpressionType pointer;
210         if (!popExpressionStack(pointer))
211             return false;
212
213         ExpressionType result;
214         if (!m_context.load(static_cast<LoadOpType>(op), pointer, result, offset))
215             return false;
216         m_expressionStack.append(result);
217         return true;
218     }
219
220     FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
221         uint32_t alignment;
222         if (!parseVarUInt32(alignment))
223             return false;
224
225         uint32_t offset;
226         if (!parseVarUInt32(offset))
227             return false;
228
229         ExpressionType value;
230         if (!popExpressionStack(value))
231             return false;
232
233         ExpressionType pointer;
234         if (!popExpressionStack(pointer))
235             return false;
236
237         return m_context.store(static_cast<StoreOpType>(op), pointer, value, offset);
238     }
239
240     case OpType::F32Const:
241     case OpType::I32Const: {
242         uint32_t constant;
243         if (!parseVarUInt32(constant))
244             return false;
245         m_expressionStack.append(m_context.addConstant(I32, constant));
246         return true;
247     }
248
249     case OpType::F64Const:
250     case OpType::I64Const: {
251         uint64_t constant;
252         if (!parseVarUInt64(constant))
253             return false;
254         m_expressionStack.append(m_context.addConstant(I64, constant));
255         return true;
256     }
257
258     case OpType::GetLocal: {
259         uint32_t index;
260         if (!parseVarUInt32(index))
261             return false;
262         ExpressionType result;
263         if (!m_context.getLocal(index, result))
264             return false;
265
266         m_expressionStack.append(result);
267         return true;
268     }
269
270     case OpType::SetLocal: {
271         uint32_t index;
272         if (!parseVarUInt32(index))
273             return false;
274         ExpressionType value;
275         if (!popExpressionStack(value))
276             return false;
277         return m_context.setLocal(index, value);
278     }
279
280     case OpType::Call: {
281         uint32_t functionIndex;
282         if (!parseVarUInt32(functionIndex))
283             return false;
284
285         if (functionIndex >= m_functions.size())
286             return false;
287
288         const FunctionInformation& info = m_functions[functionIndex];
289
290         if (info.signature->arguments.size() > m_expressionStack.size())
291             return false;
292
293         size_t firstArgumentIndex = m_expressionStack.size() - info.signature->arguments.size();
294         Vector<ExpressionType> args;
295         args.reserveInitialCapacity(info.signature->arguments.size());
296         for (unsigned i = firstArgumentIndex; i < m_expressionStack.size(); ++i)
297             args.append(m_expressionStack[i]);
298         m_expressionStack.shrink(firstArgumentIndex);
299
300         ExpressionType result = Context::emptyExpression;
301         if (!m_context.addCall(functionIndex, info, args, result))
302             return false;
303
304         if (result != Context::emptyExpression)
305             m_expressionStack.append(result);
306
307         return true;
308     }
309
310     case OpType::Block: {
311         Type inlineSignature;
312         if (!parseValueType(inlineSignature))
313             return false;
314
315         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addBlock(inlineSignature) });
316         m_expressionStack = ExpressionList();
317         return true;
318     }
319
320     case OpType::Loop: {
321         Type inlineSignature;
322         if (!parseValueType(inlineSignature))
323             return false;
324
325         m_controlStack.append({ WTFMove(m_expressionStack), m_context.addLoop(inlineSignature) });
326         m_expressionStack = ExpressionList();
327         return true;
328     }
329
330     case OpType::If: {
331         Type inlineSignature;
332         if (!parseValueType(inlineSignature))
333             return false;
334
335         ExpressionType condition;
336         if (!popExpressionStack(condition))
337             return false;
338
339         ControlType control;
340         if (!m_context.addIf(condition, inlineSignature, control))
341             return false;
342
343         m_controlStack.append({ WTFMove(m_expressionStack), control });
344         m_expressionStack = ExpressionList();
345         return true;
346     }
347
348     case OpType::Else: {
349         if (!m_controlStack.size()) {
350             setErrorMessage("Attempted to use else block at the top-level of a function");
351             return false;
352         }
353
354         if (!m_context.addElse(m_controlStack.last().controlData, m_expressionStack))
355             return false;
356         m_expressionStack.shrink(0);
357         return true;
358     }
359
360     case OpType::Br:
361     case OpType::BrIf: {
362         uint32_t target;
363         if (!parseVarUInt32(target) || target >= m_controlStack.size())
364             return false;
365
366         ExpressionType condition = Context::emptyExpression;
367         if (op == OpType::BrIf) {
368             if (!popExpressionStack(condition))
369                 return false;
370         } else
371             m_unreachableBlocks = 1;
372
373         ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
374
375         return m_context.addBranch(data, condition, m_expressionStack);
376     }
377
378     case OpType::BrTable: {
379         uint32_t numberOfTargets;
380         if (!parseVarUInt32(numberOfTargets))
381             return false;
382
383         Vector<ControlType*> targets;
384         if (!targets.tryReserveCapacity(numberOfTargets))
385             return false;
386
387         for (uint32_t i = 0; i < numberOfTargets; ++i) {
388             uint32_t target;
389             if (!parseVarUInt32(target))
390                 return false;
391
392             if (target >= m_controlStack.size())
393                 return false;
394
395             targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
396         }
397
398         uint32_t defaultTarget;
399         if (!parseVarUInt32(defaultTarget))
400             return false;
401
402         if (defaultTarget >= m_controlStack.size())
403             return false;
404
405         ExpressionType condition;
406         if (!popExpressionStack(condition))
407             return false;
408         
409         if (!m_context.addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack))
410             return false;
411
412         m_unreachableBlocks = 1;
413         return true;
414     }
415
416     case OpType::Return: {
417         return addReturn();
418     }
419
420     case OpType::End: {
421         ControlEntry data = m_controlStack.takeLast();
422         // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
423         // That's a little too effectful for me but I don't have a better API right now.
424         // see: https://bugs.webkit.org/show_bug.cgi?id=164353
425         if (!m_context.endBlock(data, m_expressionStack))
426             return false;
427         m_expressionStack.swap(data.enclosedExpressionStack);
428         return true;
429     }
430
431     case OpType::Unreachable: {
432         m_unreachableBlocks = 1;
433         return true;
434     }
435
436     case OpType::Select:
437     case OpType::Nop:
438     case OpType::Drop:
439     case OpType::TeeLocal:
440     case OpType::GetGlobal:
441     case OpType::SetGlobal:
442     case OpType::CallIndirect:
443         // FIXME: Not yet implemented.
444         return false;
445     }
446
447     ASSERT_NOT_REACHED();
448 }
449
450 template<typename Context>
451 bool FunctionParser<Context>::parseUnreachableExpression(OpType op)
452 {
453     ASSERT(m_unreachableBlocks);
454     switch (op) {
455     case OpType::Else: {
456         if (m_unreachableBlocks > 1)
457             return true;
458
459         ControlEntry& data = m_controlStack.last();
460         m_unreachableBlocks = 0;
461         if (!m_context.addElseToUnreachable(data.controlData))
462             return false;
463         m_expressionStack.shrink(0);
464         return true;
465     }
466
467     case OpType::End: {
468         if (m_unreachableBlocks == 1) {
469             ControlEntry data = m_controlStack.takeLast();
470             if (!m_context.addEndToUnreachable(data))
471                 return false;
472             m_expressionStack.swap(data.enclosedExpressionStack);
473         }
474         m_unreachableBlocks--;
475         return true;
476     }
477
478     case OpType::Loop:
479     case OpType::If:
480     case OpType::Block: {
481         m_unreachableBlocks++;
482         return true;
483     }
484
485     // two immediate cases
486     case OpType::Br:
487     case OpType::BrIf: {
488         uint32_t unused;
489         if (!parseVarUInt32(unused))
490             return false;
491         return parseVarUInt32(unused);
492     }
493
494     // one immediate cases
495     case OpType::F32Const:
496     case OpType::I32Const:
497     case OpType::F64Const:
498     case OpType::I64Const:
499     case OpType::SetLocal:
500     case OpType::GetLocal: {
501         uint32_t unused;
502         return parseVarUInt32(unused);
503     }
504
505     default:
506         break;
507     }
508     return true;
509 }
510
511 template<typename Context>
512 bool FunctionParser<Context>::popExpressionStack(ExpressionType& result)
513 {
514     if (m_expressionStack.size()) {
515         result = m_expressionStack.takeLast();
516         return true;
517     }
518
519     setErrorMessage("Attempted to use a stack value when none existed");
520     return false;
521 }
522
523 #undef CREATE_CASE
524
525 } } // namespace JSC::Wasm
526
527 #endif // ENABLE(WEBASSEMBLY)