a2565a48796a90304b7639aac7297f8127be6640
[WebKit-https.git] / Source / JavaScriptCore / wasm / WASMFunctionCompiler.h
1 /*
2  * Copyright (C) 2015 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 #ifndef WASMFunctionCompiler_h
27 #define WASMFunctionCompiler_h
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "CCallHelpers.h"
32 #include "JITOperations.h"
33 #include "LinkBuffer.h"
34 #include "MaxFrameExtentForSlowPathCall.h"
35
36 namespace JSC {
37
38 class WASMFunctionCompiler : private CCallHelpers {
39 public:
40     typedef int Expression;
41     typedef int Statement;
42
43     union StackSlot {
44         int32_t intValue;
45         float floatValue;
46         double doubleValue;
47     };
48
49     WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, unsigned stackHeight)
50         : CCallHelpers(&vm, codeBlock)
51         , m_stackHeight(stackHeight)
52     {
53     }
54
55     void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
56     {
57         emitFunctionPrologue();
58         emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
59
60         m_beginLabel = label();
61
62         addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot)), GPRInfo::callFrameRegister, GPRInfo::regT1);
63         m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
64
65         move(GPRInfo::regT1, stackPointerRegister);
66         checkStackPointerAlignment();
67
68         m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
69
70         unsigned localIndex = 0;
71         for (size_t i = 0; i < arguments.size(); ++i) {
72             Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register));
73             switch (arguments[i]) {
74             case WASMType::I32:
75                 load32(address, GPRInfo::regT0);
76                 store32(GPRInfo::regT0, localAddress(localIndex++));
77                 break;
78             case WASMType::F32:
79                 load64(address, GPRInfo::regT0);
80                 unboxDoubleWithoutAssertions(GPRInfo::regT0, FPRInfo::fpRegT0);
81                 convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
82                 storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++));
83                 break;
84             case WASMType::F64:
85                 load64(address, GPRInfo::regT0);
86                 unboxDoubleWithoutAssertions(GPRInfo::regT0, FPRInfo::fpRegT0);
87                 storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++));
88                 break;
89             default:
90                 ASSERT_NOT_REACHED();
91             }
92         }
93         for (uint32_t i = 0; i < numberOfI32LocalVariables; ++i)
94             store32(TrustedImm32(0), localAddress(localIndex++));
95         for (uint32_t i = 0; i < numberOfF32LocalVariables; ++i)
96             store32(TrustedImm32(0), localAddress(localIndex++));
97         for (uint32_t i = 0; i < numberOfF64LocalVariables; ++i)
98             store64(TrustedImm64(0), localAddress(localIndex++));
99
100         m_codeBlock->setNumParameters(1 + arguments.size());
101     }
102
103     void endFunction()
104     {
105         // FIXME: Remove these if the last statement is a return statement.
106         move(TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::returnValueGPR);
107         emitFunctionEpilogue();
108         ret();
109
110         m_stackOverflow.link(this);
111         if (maxFrameExtentForSlowPathCall)
112             addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
113         throwStackOverflowError();
114
115         // FIXME: Implement arity check.
116         Label arityCheck = label();
117         emitFunctionPrologue();
118         emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
119         jump(m_beginLabel);
120
121         LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed);
122
123         for (auto iterator : m_calls)
124             patchBuffer.link(iterator.first, FunctionPtr(iterator.second));
125
126         MacroAssemblerCodePtr withArityCheck = patchBuffer.locationOf(arityCheck);
127         CodeRef result = FINALIZE_CODE(patchBuffer, ("Baseline JIT code for WebAssembly"));
128         m_codeBlock->setJITCode(adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
129         m_codeBlock->capabilityLevel();
130     }
131
132 private:
133     Address localAddress(unsigned localIndex) const
134     {
135         ASSERT(localIndex < m_numberOfLocals);
136         return Address(GPRInfo::callFrameRegister, -(localIndex + 1) * sizeof(StackSlot));
137     }
138
139     void throwStackOverflowError()
140     {
141         setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));
142
143         m_calls.append(std::make_pair(call(), FunctionPtr(operationThrowStackOverflowError).value()));
144
145         // lookupExceptionHandlerFromCallerFrame is passed two arguments, the VM and the exec (the CallFrame*).
146         move(TrustedImmPtr(m_vm), GPRInfo::argumentGPR0);
147         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
148 #if CPU(X86)
149         // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer!
150         poke(GPRInfo::argumentGPR0);
151         poke(GPRInfo::argumentGPR1, 1);
152 #endif
153         m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value()));
154         jumpToExceptionHandler();
155     }
156
157     unsigned m_stackHeight;
158     unsigned m_numberOfLocals;
159
160     Label m_beginLabel;
161     Jump m_stackOverflow;
162
163     Vector<std::pair<Call, void*>> m_calls;
164 };
165
166 } // namespace JSC
167
168 #endif // ENABLE(WEBASSEMBLY)
169
170 #endif // WASMFunctionCompiler_h