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