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 <jit/JITCode.h> 35 36 namespace JSC { 37 38 class AbstractSamplingCounter; 39 class CodeBlock; 40 class JSGlobalData; 41 42 namespace DFG { 43 44 class JITCodeGenerator; 45 class NonSpeculativeJIT; 46 class SpeculativeJIT; 47 class SpeculationRecovery; 48 49 struct EntryLocation; 50 struct SpeculationCheck; 51 52 // Abstracted sequential numbering of available machine registers (as opposed to MacroAssembler::RegisterID, 53 // which are non-sequential, and not abstracted from the register numbering used by the underlying processor). 54 enum GPRReg { gpr0, gpr1, gpr2, gpr3, gpr4, gpr5, numberOfGPRs, InvalidGPRReg = 0xFFFFFFFF }; 55 enum FPRReg { fpr0, fpr1, fpr2, fpr3, fpr4, fpr5, numberOfFPRs, InvalidFPRReg = 0xFFFFFFFF }; 56 57 // GPRReg/FPRReg are enum types to provide type checking at compile time, use these method to iterate. 58 inline GPRReg next(GPRReg& reg) 59 { 60 ASSERT(reg < numberOfGPRs); 61 return reg = static_cast<GPRReg>(reg + 1); 62 } 63 inline FPRReg next(FPRReg& reg) 64 { 65 ASSERT(reg < numberOfFPRs); 66 return reg = static_cast<FPRReg>(reg + 1); 67 } 68 69 // === CallRecord === 70 // 71 // A record of a call out from JIT code to a helper function. 72 // Every CallRecord contains a reference to the call instruction & the function 73 // that it needs to be linked to. Calls that might throw an exception also record 74 // the Jump taken on exception (unset if not present), and ExceptionInfo (presently 75 // an unsigned, bytecode index) used to recover handler/source info. 76 struct CallRecord { 77 // Constructor for a call with no exception handler. 78 CallRecord(MacroAssembler::Call call, FunctionPtr function) 79 : m_call(call) 80 , m_function(function) 81 { 82 } 83 84 // Constructor for a call with an exception handler. 85 CallRecord(MacroAssembler::Call call, FunctionPtr function, MacroAssembler::Jump exceptionCheck, ExceptionInfo exceptionInfo) 86 : m_call(call) 87 , m_function(function) 88 , m_exceptionCheck(exceptionCheck) 89 , m_exceptionInfo(exceptionInfo) 90 { 91 } 92 93 MacroAssembler::Call m_call; 94 FunctionPtr m_function; 95 MacroAssembler::Jump m_exceptionCheck; 96 ExceptionInfo m_exceptionInfo; 97 }; 98 99 // === JITCompiler === 100 // 101 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph. 102 // It does so by delegating to the speculative & non-speculative JITs, which 103 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance 104 // relationship). The JITCompiler holds references to information required during 105 // compilation, and also records information used in linking (e.g. a list of all 106 // call to be linked). 107 class JITCompiler : public MacroAssembler { 108 public: 109 JITCompiler(JSGlobalData* globalData, Graph& dfg, CodeBlock* codeBlock) 110 : m_globalData(globalData) 111 , m_graph(dfg) 112 , m_codeBlock(codeBlock) 113 { 114 } 115 116 void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck); 117 118 // Accessors for properties. 119 Graph& graph() { return m_graph; } 120 CodeBlock* codeBlock() { return m_codeBlock; } 121 JSGlobalData* globalData() { return m_globalData; } 122 123 #if CPU(X86_64) 124 // These registers match the old JIT. 125 static const RegisterID timeoutCheckRegister = X86Registers::r12; 126 static const RegisterID callFrameRegister = X86Registers::r13; 127 static const RegisterID tagTypeNumberRegister = X86Registers::r14; 128 static const RegisterID tagMaskRegister = X86Registers::r15; 129 130 // Temporary registers (these correspond to the temporary GPRReg/FPRReg 131 // registers i.e. regT0 and grp0 refer to the same thing, grp0 being 132 // the abstracted, sequential name, and regT0 being the machine register 133 // number in the instruction set, as provided by the MacroAssembler). 134 static const RegisterID regT0 = X86Registers::eax; 135 static const RegisterID regT1 = X86Registers::edx; 136 static const RegisterID regT2 = X86Registers::ecx; 137 static const RegisterID regT3 = X86Registers::ebx; 138 static const RegisterID regT4 = X86Registers::edi; 139 static const RegisterID regT5 = X86Registers::esi; 140 static const FPRegisterID fpRegT0 = X86Registers::xmm0; 141 static const FPRegisterID fpRegT1 = X86Registers::xmm1; 142 static const FPRegisterID fpRegT2 = X86Registers::xmm2; 143 static const FPRegisterID fpRegT3 = X86Registers::xmm3; 144 static const FPRegisterID fpRegT4 = X86Registers::xmm4; 145 static const FPRegisterID fpRegT5 = X86Registers::xmm5; 146 147 // These constants provide both RegisterID & GPRReg style names for the 148 // general purpose argument & return value register. 149 static const GPRReg argumentGPR0 = gpr4; 150 static const GPRReg argumentGPR1 = gpr5; 151 static const GPRReg argumentGPR2 = gpr1; 152 static const GPRReg argumentGPR3 = gpr2; 153 static const RegisterID argumentRegister0 = regT4; 154 static const RegisterID argumentRegister1 = regT5; 155 static const RegisterID argumentRegister2 = regT1; 156 static const RegisterID argumentRegister3 = regT2; 157 static const GPRReg returnValueGPR = gpr0; 158 static const RegisterID returnValueRegister = regT0; 159 static const RegisterID returnValueRegister2 = regT1; 160 161 // These constants provide both FPRegisterID & FPRReg style names for the 162 // floating point argument & return value register. 163 static const FPRReg argumentFPR0 = fpr0; 164 static const FPRReg argumentFPR1 = fpr1; 165 static const FPRReg argumentFPR2 = fpr2; 166 static const FPRReg argumentFPR3 = fpr3; 167 static const FPRegisterID fpArgumentRegister0 = fpRegT0; 168 static const FPRegisterID fpArgumentRegister1 = fpRegT1; 169 static const FPRegisterID fpArgumentRegister2 = fpRegT2; 170 static const FPRegisterID fpArgumentRegister3 = fpRegT3; 171 static const FPRReg returnValueFPR = fpr0; 172 static const FPRegisterID fpReturnValueRegister = fpRegT0; 173 174 175 void preserveReturnAddressAfterCall(RegisterID reg) 176 { 177 pop(reg); 178 } 179 180 void restoreReturnAddressBeforeReturn(RegisterID reg) 181 { 182 push(reg); 183 } 184 185 void restoreReturnAddressBeforeReturn(Address address) 186 { 187 push(address); 188 } 189 190 void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, RegisterID to) 191 { 192 loadPtr(Address(callFrameRegister, entry * sizeof(Register)), to); 193 } 194 void emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry) 195 { 196 storePtr(from, Address(callFrameRegister, entry * sizeof(Register))); 197 } 198 199 void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry) 200 { 201 storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register))); 202 } 203 #endif 204 205 Address addressForArgument(int32_t argument) 206 { 207 return Address(callFrameRegister, (argument - (m_codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize)) * sizeof(Register)); 208 } 209 210 static Address addressForGlobalVar(RegisterID global, int32_t varNumber) 211 { 212 return Address(global, varNumber * sizeof(Register)); 213 } 214 215 static Address addressFor(VirtualRegister virtualRegister) 216 { 217 return Address(callFrameRegister, virtualRegister * sizeof(Register)); 218 } 219 220 // These methods provide mapping from sequential register numbering (GPRReg/FPRReg) 221 // to machine register numbering (RegisterID/FPRegisterID). 222 static RegisterID gprToRegisterID(GPRReg reg) 223 { 224 ASSERT(reg < numberOfGPRs); 225 static const RegisterID idForRegister[numberOfGPRs] = { regT0, regT1, regT2, regT3, regT4, regT5 }; 226 return idForRegister[reg]; 227 } 228 static FPRegisterID fprToRegisterID(FPRReg reg) 229 { 230 ASSERT(reg < numberOfFPRs); 231 static const FPRegisterID idForRegister[numberOfFPRs] = { fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5 }; 232 return idForRegister[reg]; 233 } 234 235 // Add a call out from JIT code, without an exception check. 236 void appendCall(const FunctionPtr& function) 237 { 238 m_calls.append(CallRecord(call(), function)); 239 // FIXME: should be able to JIT_ASSERT here that globalData->exception is null on return back to JIT code. 240 } 241 242 // Add a call out from JIT code, with an exception check. 243 void appendCallWithExceptionCheck(const FunctionPtr& function, unsigned exceptionInfo) 244 { 245 Call functionCall = call(); 246 Jump exceptionCheck = branchTestPtr(NonZero, AbsoluteAddress(&globalData()->exception)); 247 m_calls.append(CallRecord(functionCall, function, exceptionCheck, exceptionInfo)); 248 } 249 250 // Helper methods to check nodes for constants. 251 bool isConstant(NodeIndex nodeIndex) 252 { 253 return graph()[nodeIndex].isConstant(); 254 } 255 bool isInt32Constant(NodeIndex nodeIndex) 256 { 257 return graph()[nodeIndex].op == Int32Constant; 258 } 259 bool isDoubleConstant(NodeIndex nodeIndex) 260 { 261 return graph()[nodeIndex].op == DoubleConstant; 262 } 263 bool isJSConstant(NodeIndex nodeIndex) 264 { 265 return graph()[nodeIndex].op == JSConstant; 266 } 267 268 // Helper methods get constant values from nodes. 269 int32_t valueOfInt32Constant(NodeIndex nodeIndex) 270 { 271 ASSERT(isInt32Constant(nodeIndex)); 272 return graph()[nodeIndex].int32Constant(); 273 } 274 double valueOfDoubleConstant(NodeIndex nodeIndex) 275 { 276 ASSERT(isDoubleConstant(nodeIndex)); 277 return graph()[nodeIndex].numericConstant(); 278 } 279 JSValue valueOfJSConstant(NodeIndex nodeIndex) 280 { 281 ASSERT(isJSConstant(nodeIndex)); 282 unsigned constantIndex = graph()[nodeIndex].constantNumber(); 283 return codeBlock()->constantRegister(FirstConstantRegisterIndex + constantIndex).get(); 284 } 285 286 // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs. 287 #if DFG_JIT_ASSERT 288 void jitAssertIsInt32(GPRReg); 289 void jitAssertIsJSInt32(GPRReg); 290 void jitAssertIsJSNumber(GPRReg); 291 void jitAssertIsJSDouble(GPRReg); 292 #else 293 void jitAssertIsInt32(GPRReg) {} 294 void jitAssertIsJSInt32(GPRReg) {} 295 void jitAssertIsJSNumber(GPRReg) {} 296 void jitAssertIsJSDouble(GPRReg) {} 297 #endif 298 299 #if ENABLE(SAMPLING_COUNTERS) 300 // Debug profiling tool. 301 void emitCount(AbstractSamplingCounter&, uint32_t increment = 1); 302 #endif 303 304 private: 305 // These methods used in linking the speculative & non-speculative paths together. 306 void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary); 307 void fillInt32ToInteger(NodeIndex, GPRReg); 308 void fillToJS(NodeIndex, GPRReg); 309 void jumpFromSpeculativeToNonSpeculative(const SpeculationCheck&, const EntryLocation&, SpeculationRecovery*); 310 void linkSpeculationChecks(SpeculativeJIT&, NonSpeculativeJIT&); 311 312 // The globalData, used to access constants such as the vPtrs. 313 JSGlobalData* m_globalData; 314 315 // The dataflow graph currently being generated. 316 Graph& m_graph; 317 318 // The codeBlock currently being generated, used to access information such as constant values, immediates. 319 CodeBlock* m_codeBlock; 320 321 // Vector of calls out from JIT code, including exception handler information. 322 Vector<CallRecord> m_calls; 323 }; 324 325 } } // namespace JSC::DFG 326 327 #endif 328 #endif 329 330