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