]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
1 | /* |
2 | * Copyright (C) 2011 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 DFGJITCompiler_h | |
27 | #define DFGJITCompiler_h | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include <assembler/MacroAssembler.h> | |
32 | #include <bytecode/CodeBlock.h> | |
33 | #include <dfg/DFGGraph.h> | |
34 | #include <dfg/DFGRegisterBank.h> | |
35 | #include <jit/JITCode.h> | |
36 | ||
37 | #include <dfg/DFGFPRInfo.h> | |
38 | #include <dfg/DFGGPRInfo.h> | |
39 | ||
40 | namespace JSC { | |
41 | ||
42 | class AbstractSamplingCounter; | |
43 | class CodeBlock; | |
44 | class JSGlobalData; | |
45 | ||
46 | namespace DFG { | |
47 | ||
48 | class JITCodeGenerator; | |
49 | class NonSpeculativeJIT; | |
50 | class SpeculativeJIT; | |
51 | class SpeculationRecovery; | |
52 | ||
53 | struct EntryLocation; | |
54 | struct SpeculationCheck; | |
55 | ||
56 | // === CallRecord === | |
57 | // | |
58 | // A record of a call out from JIT code to a helper function. | |
59 | // Every CallRecord contains a reference to the call instruction & the function | |
60 | // that it needs to be linked to. Calls that might throw an exception also record | |
61 | // the Jump taken on exception (unset if not present), and ExceptionInfo (presently | |
62 | // an unsigned, bytecode index) used to recover handler/source info. | |
63 | struct CallRecord { | |
64 | // Constructor for a call with no exception handler. | |
65 | CallRecord(MacroAssembler::Call call, FunctionPtr function) | |
66 | : m_call(call) | |
67 | , m_function(function) | |
68 | { | |
69 | } | |
70 | ||
71 | // Constructor for a call with an exception handler. | |
72 | CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, ExceptionInfo exceptionInfo) | |
73 | : m_call(call) | |
74 | , m_function(function) | |
75 | , m_exceptionCheck(exceptionCheck) | |
76 | , m_exceptionInfo(exceptionInfo) | |
77 | { | |
78 | } | |
79 | ||
80 | MacroAssembler::Call m_call; | |
81 | FunctionPtr m_function; | |
82 | MacroAssembler::Jump m_exceptionCheck; | |
83 | ExceptionInfo m_exceptionInfo; | |
84 | }; | |
85 | ||
86 | // === JITCompiler === | |
87 | // | |
88 | // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph. | |
89 | // It does so by delegating to the speculative & non-speculative JITs, which | |
90 | // generate to a MacroAssembler (which the JITCompiler owns through an inheritance | |
91 | // relationship). The JITCompiler holds references to information required during | |
92 | // compilation, and also records information used in linking (e.g. a list of all | |
93 | // call to be linked). | |
94 | class JITCompiler : public MacroAssembler { | |
95 | public: | |
96 | JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock) | |
97 | : m_globalData(globalData) | |
98 | , m_graph(dfg) | |
99 | , m_codeBlock(codeBlock) | |
100 | { | |
101 | } | |
102 | ||
103 | void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck); | |
104 | ||
105 | // Accessors for properties. | |
106 | Graph& graph() { return m_graph; } | |
107 | CodeBlock* codeBlock() { return m_codeBlock; } | |
108 | JSGlobalData* globalData() { return m_globalData; } | |
109 | ||
110 | #if CPU(X86_64) | |
111 | void preserveReturnAddressAfterCall(GPRReg reg) | |
112 | { | |
113 | pop(reg); | |
114 | } | |
115 | ||
116 | void restoreReturnAddressBeforeReturn(GPRReg reg) | |
117 | { | |
118 | push(reg); | |
119 | } | |
120 | ||
121 | void restoreReturnAddressBeforeReturn(Address address) | |
122 | { | |
123 | push(address); | |
124 | } | |
125 | ||
126 | void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to) | |
127 | { | |
128 | loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to); | |
129 | } | |
130 | void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry) | |
131 | { | |
132 | storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register))); | |
133 | } | |
134 | ||
135 | void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry) | |
136 | { | |
137 | storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register))); | |
138 | } | |
139 | #endif | |
140 | ||
141 | static Address addressForGlobalVar(GPRReg global, int32_t varNumber) | |
142 | { | |
143 | return Address(global, varNumber * sizeof(Register)); | |
144 | } | |
145 | ||
146 | static Address addressFor(VirtualRegister virtualRegister) | |
147 | { | |
148 | return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register)); | |
149 | } | |
150 | ||
151 | static Address tagFor(VirtualRegister virtualRegister) | |
152 | { | |
153 | return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); | |
154 | } | |
155 | ||
156 | static Address payloadFor(VirtualRegister virtualRegister) | |
157 | { | |
158 | return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); | |
159 | } | |
160 | ||
161 | // Add a call out from JIT code, without an exception check. | |
162 | void appendCall(const FunctionPtr& function) | |
163 | { | |
164 | m_calls.append(CallRecord(call(), function)); | |
165 | // FIXME: should be able to JIT_ASSERT here that globalData->exception is null on return back to JIT code. | |
166 | } | |
167 | ||
168 | // Add a call out from JIT code, with an exception check. | |
169 | void appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo) | |
170 | { | |
171 | Call functionCall = call(); | |
172 | Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception)); | |
173 | m_calls.append(CallRecord(functionCall, function, exceptionCheck, exceptionInfo)); | |
174 | } | |
175 | ||
176 | // Helper methods to check nodes for constants. | |
177 | bool isConstant(NodeIndex nodeIndex) | |
178 | { | |
179 | return graph()[nodeIndex].isConstant(); | |
180 | } | |
181 | bool isInt32Constant(NodeIndex nodeIndex) | |
182 | { | |
183 | return graph()[nodeIndex].op == Int32Constant; | |
184 | } | |
185 | bool isDoubleConstant(NodeIndex nodeIndex) | |
186 | { | |
187 | return graph()[nodeIndex].op == DoubleConstant; | |
188 | } | |
189 | bool isJSConstant(NodeIndex nodeIndex) | |
190 | { | |
191 | return graph()[nodeIndex].op == JSConstant; | |
192 | } | |
193 | ||
194 | // Helper methods get constant values from nodes. | |
195 | int32_t valueOfInt32Constant(NodeIndex nodeIndex) | |
196 | { | |
197 | ASSERT(isInt32Constant(nodeIndex)); | |
198 | return graph()[nodeIndex].int32Constant(); | |
199 | } | |
200 | double valueOfDoubleConstant(NodeIndex nodeIndex) | |
201 | { | |
202 | ASSERT(isDoubleConstant(nodeIndex)); | |
203 | return graph()[nodeIndex].numericConstant(); | |
204 | } | |
205 | JSValue valueOfJSConstant(NodeIndex nodeIndex) | |
206 | { | |
207 | ASSERT(isJSConstant(nodeIndex)); | |
208 | unsigned constantIndex = graph()[nodeIndex].constantNumber(); | |
209 | return codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex).get(); | |
210 | } | |
211 | ||
212 | // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs. | |
213 | #if DFG_JIT_ASSERT | |
214 | void jitAssertIsInt32(GPRReg); | |
215 | void jitAssertIsJSInt32(GPRReg); | |
216 | void jitAssertIsJSNumber(GPRReg); | |
217 | void jitAssertIsJSDouble(GPRReg); | |
218 | #else | |
219 | void jitAssertIsInt32(GPRReg) {} | |
220 | void jitAssertIsJSInt32(GPRReg) {} | |
221 | void jitAssertIsJSNumber(GPRReg) {} | |
222 | void jitAssertIsJSDouble(GPRReg) {} | |
223 | #endif | |
224 | ||
225 | #if ENABLE(SAMPLING_COUNTERS) | |
226 | // Debug profiling tool. | |
227 | void emitCount(AbstractSamplingCounter&, uint32_t increment = 1); | |
228 | #endif | |
229 | ||
230 | #if ENABLE(SAMPLING_FLAGS) | |
231 | void setSamplingFlag(int32_t flag); | |
232 | void clearSamplingFlag(int32_t flag); | |
233 | #endif | |
234 | ||
235 | private: | |
236 | // These methods used in linking the speculative & non-speculative paths together. | |
237 | void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary); | |
238 | void fillInt32ToInteger(NodeIndex, GPRReg); | |
239 | void fillToJS(NodeIndex, GPRReg); | |
240 | void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*); | |
241 | void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&); | |
242 | ||
243 | // The globalData, used to access constants such as the vPtrs. | |
244 | JSGlobalData* m_globalData; | |
245 | ||
246 | // The dataflow graph currently being generated. | |
247 | Graph& m_graph; | |
248 | ||
249 | // The codeBlock currently being generated, used to access information such as constant values, immediates. | |
250 | CodeBlock* m_codeBlock; | |
251 | ||
252 | // Vector of calls out from JIT code, including exception handler information. | |
253 | Vector<CallRecord> m_calls; | |
254 | }; | |
255 | ||
256 | } } // namespace JSC::DFG | |
257 | ||
258 | #endif | |
259 | #endif | |
260 |