1 /* 2 * Copyright (C) 2008 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 #include "config.h" 27 28 #if ENABLE(JIT) 29 #if USE(JSVALUE64) 30 #include "JIT.h" 31 32 #include "CodeBlock.h" 33 #include "JITInlineMethods.h" 34 #include "JITStubCall.h" 35 #include "JSArray.h" 36 #include "JSFunction.h" 37 #include "Interpreter.h" 38 #include "ResultType.h" 39 #include "SamplingTool.h" 40 41 #ifndef NDEBUG 42 #include <stdio.h> 43 #endif 44 45 using namespace std; 46 47 namespace JSC { 48 49 void JIT::compileOpCallInitializeCallFrame() 50 { 51 // regT0 holds callee, regT1 holds argCount 52 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT3); // scopeChain 53 emitPutIntToCallFrameHeader(regT1, RegisterFile::ArgumentCount); 54 emitPutCellToCallFrameHeader(regT0, RegisterFile::Callee); 55 emitPutCellToCallFrameHeader(regT3, RegisterFile::ScopeChain); 56 } 57 58 void JIT::emit_op_call_put_result(Instruction* instruction) 59 { 60 int dst = instruction[1].u.operand; 61 emitPutVirtualRegister(dst); 62 } 63 64 void JIT::compileOpCallVarargs(Instruction* instruction) 65 { 66 int callee = instruction[1].u.operand; 67 int argCountRegister = instruction[2].u.operand; 68 int registerOffset = instruction[3].u.operand; 69 70 emitGetVirtualRegister(argCountRegister, regT1); 71 emitFastArithImmToInt(regT1); 72 emitGetVirtualRegister(callee, regT0); 73 addPtr(Imm32(registerOffset), regT1, regT2); 74 75 // Check for JSFunctions. 76 emitJumpSlowCaseIfNotJSCell(regT0); 77 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr))); 78 79 // Speculatively roll the callframe, assuming argCount will match the arity. 80 mul32(TrustedImm32(sizeof(Register)), regT2, regT2); 81 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame; 82 addPtr(Imm32((int32_t)offset), regT2, regT3); 83 addPtr(callFrameRegister, regT3); 84 storePtr(callFrameRegister, regT3); 85 addPtr(regT2, callFrameRegister); 86 emitNakedCall(m_globalData->jitStubs->ctiVirtualCall()); 87 88 sampleCodeBlock(m_codeBlock); 89 } 90 91 void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter) 92 { 93 linkSlowCase(iter); 94 linkSlowCase(iter); 95 96 JITStubCall stubCall(this, cti_op_call_NotJSFunction); 97 stubCall.addArgument(regT0); 98 stubCall.addArgument(regT2); 99 stubCall.addArgument(regT1); 100 stubCall.call(); 101 102 sampleCodeBlock(m_codeBlock); 103 } 104 105 #if !ENABLE(JIT_OPTIMIZE_CALL) 106 107 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 108 109 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) 110 { 111 int callee = instruction[1].u.operand; 112 int argCount = instruction[2].u.operand; 113 int registerOffset = instruction[3].u.operand; 114 115 // Handle eval 116 Jump wasEval; 117 if (opcodeID == op_call_eval) { 118 JITStubCall stubCall(this, cti_op_call_eval); 119 stubCall.addArgument(callee, regT0); 120 stubCall.addArgument(JIT::Imm32(registerOffset)); 121 stubCall.addArgument(JIT::Imm32(argCount)); 122 stubCall.call(); 123 wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue()))); 124 } 125 126 emitGetVirtualRegister(callee, regT0); 127 128 // Check for JSFunctions. 129 emitJumpSlowCaseIfNotJSCell(regT0); 130 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr))); 131 132 // Speculatively roll the callframe, assuming argCount will match the arity. 133 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); 134 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); 135 move(Imm32(argCount), regT1); 136 137 emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstruct() : m_globalData->jitStubs->ctiVirtualCall()); 138 139 if (opcodeID == op_call_eval) 140 wasEval.link(this); 141 142 sampleCodeBlock(m_codeBlock); 143 } 144 145 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID) 146 { 147 int argCount = instruction[2].u.operand; 148 int registerOffset = instruction[3].u.operand; 149 150 linkSlowCase(iter); 151 linkSlowCase(iter); 152 153 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction); 154 stubCall.addArgument(regT0); 155 stubCall.addArgument(JIT::Imm32(registerOffset)); 156 stubCall.addArgument(JIT::Imm32(argCount)); 157 stubCall.call(); 158 159 sampleCodeBlock(m_codeBlock); 160 } 161 162 #else // !ENABLE(JIT_OPTIMIZE_CALL) 163 164 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 165 166 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) 167 { 168 int callee = instruction[1].u.operand; 169 int argCount = instruction[2].u.operand; 170 int registerOffset = instruction[3].u.operand; 171 172 // Handle eval 173 Jump wasEval; 174 if (opcodeID == op_call_eval) { 175 JITStubCall stubCall(this, cti_op_call_eval); 176 stubCall.addArgument(callee, regT0); 177 stubCall.addArgument(JIT::Imm32(registerOffset)); 178 stubCall.addArgument(JIT::Imm32(argCount)); 179 stubCall.call(); 180 wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue()))); 181 } 182 183 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee. 184 // This deliberately leaves the callee in ecx, used when setting up the stack frame below 185 emitGetVirtualRegister(callee, regT0); 186 DataLabelPtr addressOfLinkedFunctionCheck; 187 188 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall); 189 190 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue()))); 191 192 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall); 193 194 addSlowCase(jumpToSlow); 195 ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump); 196 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; 197 198 // The following is the fast case, only used whan a callee can be linked. 199 200 // Fast version of stack frame initialization, directly relative to edi. 201 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee 202 203 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain 204 205 store32(TrustedImm32(Int32Tag), intTagFor(registerOffset + RegisterFile::ArgumentCount)); 206 store32(Imm32(argCount), intPayloadFor(registerOffset + RegisterFile::ArgumentCount)); 207 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)))); 208 storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)))); 209 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)))); 210 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister); 211 212 // Call to the callee 213 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); 214 215 if (opcodeID == op_call_eval) 216 wasEval.link(this); 217 218 sampleCodeBlock(m_codeBlock); 219 } 220 221 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID) 222 { 223 int argCount = instruction[2].u.operand; 224 int registerOffset = instruction[3].u.operand; 225 226 linkSlowCase(iter); 227 228 // Fast check for JS function. 229 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0); 230 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)); 231 232 // Speculatively roll the callframe, assuming argCount will match the arity. 233 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); 234 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); 235 move(Imm32(argCount), regT1); 236 237 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink()); 238 239 // Done! - return back to the hot path. 240 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); 241 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); 242 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call)); 243 244 // This handles host functions 245 callLinkFailNotObject.link(this); 246 callLinkFailNotJSFunction.link(this); 247 248 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction); 249 stubCall.addArgument(regT0); 250 stubCall.addArgument(JIT::Imm32(registerOffset)); 251 stubCall.addArgument(JIT::Imm32(argCount)); 252 stubCall.call(); 253 254 sampleCodeBlock(m_codeBlock); 255 } 256 257 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 258 259 #endif // !ENABLE(JIT_OPTIMIZE_CALL) 260 261 } // namespace JSC 262 263 #endif // USE(JSVALUE64) 264 #endif // ENABLE(JIT) 265