Changeset 46598 in webkit for trunk/JavaScriptCore/jit/JITCall.cpp
- Timestamp:
- Jul 30, 2009, 1:57:44 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/jit/JITCall.cpp
r44889 r46598 46 46 namespace JSC { 47 47 48 #if USE(JSVALUE32_64) 49 50 void JIT::compileOpCallInitializeCallFrame() 51 { 52 // regT0 holds callee, regT1 holds argCount 53 store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)))); 54 55 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // scopeChain 56 57 emitStore(static_cast<unsigned>(RegisterFile::OptionalCalleeArguments), JSValue()); 58 storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); // callee 59 storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain 60 } 61 62 void JIT::compileOpCallSetupArgs(Instruction* instruction) 63 { 64 int argCount = instruction[3].u.operand; 65 int registerOffset = instruction[4].u.operand; 66 67 emitPutJITStubArg(regT0, 1); 68 emitPutJITStubArg(regT1, 2); 69 emitPutJITStubArgConstant(registerOffset, 3); 70 emitPutJITStubArgConstant(argCount, 5); 71 } 72 73 void JIT::compileOpConstructSetupArgs(Instruction* instruction) 74 { 75 int argCount = instruction[3].u.operand; 76 int registerOffset = instruction[4].u.operand; 77 int proto = instruction[5].u.operand; 78 int thisRegister = instruction[6].u.operand; 79 80 emitPutJITStubArg(regT0, 1); 81 emitPutJITStubArg(regT1, 2); 82 emitPutJITStubArgConstant(registerOffset, 3); 83 emitPutJITStubArgConstant(argCount, 5); 84 emitPutJITStubArgFromVirtualRegister(proto, 7, regT2, regT3); 85 emitPutJITStubArgConstant(thisRegister, 9); 86 } 87 88 void JIT::compileOpCallVarargsSetupArgs(Instruction*) 89 { 90 emitPutJITStubArg(regT0, 1); 91 emitPutJITStubArg(regT1, 2); 92 emitPutJITStubArg(regT3, 3); // registerOffset 93 emitPutJITStubArg(regT2, 5); // argCount 94 } 95 96 void JIT::compileOpCallVarargs(Instruction* instruction) 97 { 98 int dst = instruction[1].u.operand; 99 int callee = instruction[2].u.operand; 100 int argCountRegister = instruction[3].u.operand; 101 int registerOffset = instruction[4].u.operand; 102 103 emitLoad(callee, regT1, regT0); 104 emitLoadPayload(argCountRegister, regT2); // argCount 105 addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset 106 107 compileOpCallVarargsSetupArgs(instruction); 108 109 emitJumpSlowCaseIfNotJSCell(callee, regT1); 110 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr))); 111 112 // Speculatively roll the callframe, assuming argCount will match the arity. 113 mul32(Imm32(sizeof(Register)), regT3, regT3); 114 addPtr(callFrameRegister, regT3); 115 storePtr(callFrameRegister, Address(regT3, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register)))); 116 move(regT3, callFrameRegister); 117 118 move(regT2, regT1); // argCount 119 120 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall()); 121 122 emitStore(dst, regT1, regT0); 123 124 sampleCodeBlock(m_codeBlock); 125 } 126 127 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter) 128 { 129 int dst = instruction[1].u.operand; 130 int callee = instruction[2].u.operand; 131 132 linkSlowCaseIfNotJSCell(iter, callee); 133 linkSlowCase(iter); 134 135 JITStubCall stubCall(this, cti_op_call_NotJSFunction); 136 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst. 137 138 map(m_bytecodeIndex + OPCODE_LENGTH(op_call_varargs), dst, regT1, regT0); 139 sampleCodeBlock(m_codeBlock); 140 } 141 142 void JIT::emit_op_ret(Instruction* currentInstruction) 143 { 144 unsigned dst = currentInstruction[1].u.operand; 145 146 // We could JIT generate the deref, only calling out to C when the refcount hits zero. 147 if (m_codeBlock->needsFullScopeChain()) 148 JITStubCall(this, cti_op_ret_scopeChain).call(); 149 150 emitLoad(dst, regT1, regT0); 151 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2); 152 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 153 154 restoreReturnAddressBeforeReturn(regT2); 155 ret(); 156 } 157 158 void JIT::emit_op_construct_verify(Instruction* currentInstruction) 159 { 160 unsigned dst = currentInstruction[1].u.operand; 161 162 emitLoad(dst, regT1, regT0); 163 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); 164 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 165 addSlowCase(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType))); 166 } 167 168 void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 169 { 170 unsigned dst = currentInstruction[1].u.operand; 171 unsigned src = currentInstruction[2].u.operand; 172 173 linkSlowCase(iter); 174 linkSlowCase(iter); 175 emitLoad(src, regT1, regT0); 176 emitStore(dst, regT1, regT0); 177 } 178 179 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 180 { 181 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call); 182 } 183 184 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 185 { 186 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval); 187 } 188 189 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 190 { 191 compileOpCallVarargsSlowCase(currentInstruction, iter); 192 } 193 194 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 195 { 196 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct); 197 } 198 199 void JIT::emit_op_call(Instruction* currentInstruction) 200 { 201 compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++); 202 } 203 204 void JIT::emit_op_call_eval(Instruction* currentInstruction) 205 { 206 compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++); 207 } 208 209 void JIT::emit_op_load_varargs(Instruction* currentInstruction) 210 { 211 int argCountDst = currentInstruction[1].u.operand; 212 int argsOffset = currentInstruction[2].u.operand; 213 214 JITStubCall stubCall(this, cti_op_load_varargs); 215 stubCall.addArgument(Imm32(argsOffset)); 216 stubCall.call(); 217 // Stores a naked int32 in the register file. 218 store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); 219 } 220 221 void JIT::emit_op_call_varargs(Instruction* currentInstruction) 222 { 223 compileOpCallVarargs(currentInstruction); 224 } 225 226 void JIT::emit_op_construct(Instruction* currentInstruction) 227 { 228 compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++); 229 } 230 231 #if !ENABLE(JIT_OPTIMIZE_CALL) 232 233 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 234 235 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) 236 { 237 int dst = instruction[1].u.operand; 238 int callee = instruction[2].u.operand; 239 int argCount = instruction[3].u.operand; 240 int registerOffset = instruction[4].u.operand; 241 242 Jump wasEval1; 243 Jump wasEval2; 244 if (opcodeID == op_call_eval) { 245 JITStubCall stubCall(this, cti_op_call_eval); 246 stubCall.addArgument(callee); 247 stubCall.addArgument(JIT::Imm32(registerOffset)); 248 stubCall.addArgument(JIT::Imm32(argCount)); 249 stubCall.call(); 250 wasEval1 = branchTest32(NonZero, regT0); 251 wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 252 } 253 254 emitLoad(callee, regT1, regT2); 255 256 if (opcodeID == op_call) 257 compileOpCallSetupArgs(instruction); 258 else if (opcodeID == op_construct) 259 compileOpConstructSetupArgs(instruction); 260 261 emitJumpSlowCaseIfNotJSCell(callee, regT1); 262 addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr))); 263 264 // First, in the case of a construct, allocate the new object. 265 if (opcodeID == op_construct) { 266 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); 267 emitLoad(callee, regT1, regT2); 268 } 269 270 // Speculatively roll the callframe, assuming argCount will match the arity. 271 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); 272 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); 273 move(Imm32(argCount), regT1); 274 275 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall()); 276 277 if (opcodeID == op_call_eval) { 278 wasEval1.link(this); 279 wasEval2.link(this); 280 } 281 282 emitStore(dst, regT1, regT0);; 283 284 sampleCodeBlock(m_codeBlock); 285 } 286 287 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID) 288 { 289 int dst = instruction[1].u.operand; 290 int callee = instruction[2].u.operand; 291 292 linkSlowCaseIfNotJSCell(iter, callee); 293 linkSlowCase(iter); 294 295 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction); 296 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst. 297 298 sampleCodeBlock(m_codeBlock); 299 } 300 301 #else // !ENABLE(JIT_OPTIMIZE_CALL) 302 303 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 304 305 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) 306 { 307 int dst = instruction[1].u.operand; 308 int callee = instruction[2].u.operand; 309 int argCount = instruction[3].u.operand; 310 int registerOffset = instruction[4].u.operand; 311 312 Jump wasEval1; 313 Jump wasEval2; 314 if (opcodeID == op_call_eval) { 315 JITStubCall stubCall(this, cti_op_call_eval); 316 stubCall.addArgument(callee); 317 stubCall.addArgument(JIT::Imm32(registerOffset)); 318 stubCall.addArgument(JIT::Imm32(argCount)); 319 stubCall.call(); 320 wasEval1 = branchTest32(NonZero, regT0); 321 wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 322 } 323 324 emitLoad(callee, regT1, regT0); 325 326 DataLabelPtr addressOfLinkedFunctionCheck; 327 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0)); 328 addSlowCase(jumpToSlow); 329 ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump); 330 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; 331 332 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); 333 334 // The following is the fast case, only used whan a callee can be linked. 335 336 // In the case of OpConstruct, call out to a cti_ function to create the new object. 337 if (opcodeID == op_construct) { 338 int proto = instruction[5].u.operand; 339 int thisRegister = instruction[6].u.operand; 340 341 JITStubCall stubCall(this, cti_op_construct_JSConstruct); 342 stubCall.addArgument(regT1, regT0); 343 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument. 344 stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument. 345 stubCall.addArgument(proto); 346 stubCall.call(thisRegister); 347 348 emitLoad(callee, regT1, regT0); 349 } 350 351 // Fast version of stack frame initialization, directly relative to edi. 352 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee 353 emitStore(registerOffset + RegisterFile::OptionalCalleeArguments, JSValue()); 354 emitStore(registerOffset + RegisterFile::Callee, regT1, regT0); 355 356 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain 357 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)))); 358 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)))); 359 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)))); 360 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister); 361 362 // Call to the callee 363 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); 364 365 if (opcodeID == op_call_eval) { 366 wasEval1.link(this); 367 wasEval2.link(this); 368 } 369 370 // Put the return value in dst. In the interpreter, op_ret does this. 371 emitStore(dst, regT1, regT0); 372 map(m_bytecodeIndex + opcodeLengths[opcodeID], dst, regT1, regT0); 373 374 sampleCodeBlock(m_codeBlock); 375 } 376 377 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID) 378 { 379 int dst = instruction[1].u.operand; 380 int callee = instruction[2].u.operand; 381 int argCount = instruction[3].u.operand; 382 int registerOffset = instruction[4].u.operand; 383 384 linkSlowCase(iter); 385 linkSlowCase(iter); 386 387 // The arguments have been set up on the hot path for op_call_eval 388 if (opcodeID == op_call) 389 compileOpCallSetupArgs(instruction); 390 else if (opcodeID == op_construct) 391 compileOpConstructSetupArgs(instruction); 392 393 // Fast check for JS function. 394 Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 395 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)); 396 397 // First, in the case of a construct, allocate the new object. 398 if (opcodeID == op_construct) { 399 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); 400 emitLoad(callee, regT1, regT0); 401 } 402 403 // Speculatively roll the callframe, assuming argCount will match the arity. 404 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); 405 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); 406 move(Imm32(argCount), regT1); 407 408 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallPreLink()); 409 410 // Put the return value in dst. 411 emitStore(dst, regT1, regT0);; 412 sampleCodeBlock(m_codeBlock); 413 414 // If not, we need an extra case in the if below! 415 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); 416 417 // Done! - return back to the hot path. 418 if (opcodeID == op_construct) 419 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct)); 420 else 421 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call)); 422 423 // This handles host functions 424 callLinkFailNotObject.link(this); 425 callLinkFailNotJSFunction.link(this); 426 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call(); 427 428 emitStore(dst, regT1, regT0);; 429 sampleCodeBlock(m_codeBlock); 430 } 431 432 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */ 433 434 #endif // !ENABLE(JIT_OPTIMIZE_CALL) 435 436 #else // USE(JSVALUE32_64) 437 48 438 void JIT::compileOpCallInitializeCallFrame() 49 439 { … … 129 519 linkSlowCase(iter); 130 520 linkSlowCase(iter); 131 JITStubCall stubCall(this, JITStubs::cti_op_call_NotJSFunction);521 JITStubCall stubCall(this, cti_op_call_NotJSFunction); 132 522 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst. 133 523 … … 149 539 Jump wasEval; 150 540 if (opcodeID == op_call_eval) { 151 CallEvalJITStub(this, instruction).call(); 541 JITStubCall stubCall(this, cti_op_call_eval); 542 stubCall.addArgument(callee, regT2); 543 stubCall.addArgument(JIT::Imm32(registerOffset)); 544 stubCall.addArgument(JIT::Imm32(argCount)); 545 stubCall.call(); 152 546 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue()))); 153 547 } … … 166 560 // First, in the case of a construct, allocate the new object. 167 561 if (opcodeID == op_construct) { 168 JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);562 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); 169 563 emitGetVirtualRegister(callee, regT2); 170 564 } … … 192 586 linkSlowCase(iter); 193 587 linkSlowCase(iter); 194 JITStubCall stubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction);588 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction); 195 589 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst. 196 590 … … 212 606 Jump wasEval; 213 607 if (opcodeID == op_call_eval) { 214 CallEvalJITStub(this, instruction).call(); 608 JITStubCall stubCall(this, cti_op_call_eval); 609 stubCall.addArgument(callee, regT2); 610 stubCall.addArgument(JIT::Imm32(registerOffset)); 611 stubCall.addArgument(JIT::Imm32(argCount)); 612 stubCall.call(); 215 613 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue()))); 216 614 } … … 234 632 emitPutJITStubArg(regT2, 1); 235 633 emitPutJITStubArgFromVirtualRegister(proto, 4, regT0); 236 JITStubCall stubCall(this, JITStubs::cti_op_construct_JSConstruct);634 JITStubCall stubCall(this, cti_op_construct_JSConstruct); 237 635 stubCall.call(thisRegister); 238 636 emitGetVirtualRegister(callee, regT2); … … 282 680 // First, in the case of a construct, allocate the new object. 283 681 if (opcodeID == op_construct) { 284 JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);682 JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); 285 683 emitGetVirtualRegister(callee, regT2); 286 684 } … … 309 707 callLinkFailNotObject.link(this); 310 708 callLinkFailNotJSFunction.link(this); 311 JITStubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction).call();709 JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call(); 312 710 313 711 emitPutVirtualRegister(dst); … … 319 717 #endif // !ENABLE(JIT_OPTIMIZE_CALL) 320 718 719 #endif // USE(JSVALUE32_64) 720 321 721 } // namespace JSC 322 722
Note:
See TracChangeset
for help on using the changeset viewer.