diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGRepatch.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGRepatch.cpp | 172 |
1 files changed, 161 insertions, 11 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 7c15ef33e..a20eb544a 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -114,6 +114,23 @@ static void addStructureTransitionCheck( failureCases, scratchGPR); } +static void replaceWithJump(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo, const MacroAssemblerCodePtr target) +{ + if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) { + repatchBuffer.replaceWithJump( + RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress( + stubInfo.callReturnLocation.dataLabelPtrAtOffset( + -(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall)), + CodeLocationLabel(target)); + return; + } + + repatchBuffer.relink( + stubInfo.callReturnLocation.jumpAtOffset( + stubInfo.patch.dfg.deltaCallToStructCheck), + CodeLocationLabel(target)); +} + static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases) { if (needToRestoreScratch) { @@ -284,7 +301,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier stubInfo.patch.dfg.deltaCallToDone).executableAddress())); RepatchBuffer repatchBuffer(codeBlock); - repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code())); + replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code()); repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById); return true; @@ -334,7 +351,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase), stubInfo.stubRoutine); RepatchBuffer repatchBuffer(codeBlock); - repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code())); + replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code()); repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList); stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain, count, true); @@ -518,9 +535,11 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, isDirect); - CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck); RepatchBuffer repatchBuffer(codeBlock); - repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code())); + repatchBuffer.relink( + stubInfo.callReturnLocation.jumpAtOffset( + stubInfo.patch.dfg.deltaCallToStructCheck), + CodeLocationLabel(stubRoutine->code().code())); if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1)) return true; @@ -584,9 +603,8 @@ static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const I polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure, true); - CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck); RepatchBuffer repatchBuffer(codeBlock); - repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine->code().code())); + replaceWithJump(repatchBuffer, stubInfo, stubRoutine->code().code()); if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1)) return true; @@ -976,7 +994,10 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier stubInfo.stubRoutine); RepatchBuffer repatchBuffer(codeBlock); - repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.dfg.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine->code().code())); + repatchBuffer.relink( + stubInfo.callReturnLocation.jumpAtOffset( + stubInfo.patch.dfg.deltaCallToStructCheck), + CodeLocationLabel(stubInfo.stubRoutine->code().code())); repatchBuffer.relink(stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind)); stubInfo.initPutByIdTransition(*globalData, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain, putKind == Direct); @@ -1092,8 +1113,20 @@ void dfgBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& p dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind)); } +static void linkSlowFor(RepatchBuffer& repatchBuffer, JSGlobalData* globalData, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind) +{ + if (kind == CodeForCall) { + repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code()); + return; + } + ASSERT(kind == CodeForConstruct); + repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code()); +} + void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, JSFunction* callee, MacroAssemblerCodePtr codePtr, CodeSpecializationKind kind) { + ASSERT(!callLinkInfo.stub); + CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock(); JSGlobalData* globalData = callerCodeBlock->globalData(); @@ -1108,17 +1141,125 @@ void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCo calleeCodeBlock->linkIncomingCall(&callLinkInfo); if (kind == CodeForCall) { - repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code()); + repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(linkClosureCallThunkGenerator).code()); return; } + ASSERT(kind == CodeForConstruct); - repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code()); + linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForConstruct); +} + +void dfgLinkSlowFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind) +{ + CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock(); + JSGlobalData* globalData = callerCodeBlock->globalData(); + + RepatchBuffer repatchBuffer(callerCodeBlock); + + linkSlowFor(repatchBuffer, globalData, callLinkInfo, kind); +} + +void dfgLinkClosureCall(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, Structure* structure, ExecutableBase* executable, MacroAssemblerCodePtr codePtr) +{ + ASSERT(!callLinkInfo.stub); + + CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock(); + JSGlobalData* globalData = callerCodeBlock->globalData(); + + GPRReg calleeGPR = static_cast<GPRReg>(callLinkInfo.calleeGPR); + + CCallHelpers stubJit(globalData, callerCodeBlock); + + CCallHelpers::JumpList slowPath; + +#if USE(JSVALUE64) + slowPath.append( + stubJit.branchTest64( + CCallHelpers::NonZero, calleeGPR, GPRInfo::tagMaskRegister)); +#else + // We would have already checked that the callee is a cell. +#endif + + slowPath.append( + stubJit.branchPtr( + CCallHelpers::NotEqual, + CCallHelpers::Address(calleeGPR, JSCell::structureOffset()), + CCallHelpers::TrustedImmPtr(structure))); + + slowPath.append( + stubJit.branchPtr( + CCallHelpers::NotEqual, + CCallHelpers::Address(calleeGPR, JSFunction::offsetOfExecutable()), + CCallHelpers::TrustedImmPtr(executable))); + + stubJit.loadPtr( + CCallHelpers::Address(calleeGPR, JSFunction::offsetOfScopeChain()), + GPRInfo::returnValueGPR); + +#if USE(JSVALUE64) + stubJit.store64( + GPRInfo::returnValueGPR, + CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain))); +#else + stubJit.storePtr( + GPRInfo::returnValueGPR, + CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); + stubJit.store32( + CCallHelpers::TrustedImm32(JSValue::CellTag), + CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); +#endif + + JITCompiler::Call call = stubJit.nearCall(); + JITCompiler::Jump done = stubJit.jump(); + + slowPath.link(&stubJit); + stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation.executableAddress()), GPRInfo::nonArgGPR2); + stubJit.restoreReturnAddressBeforeReturn(GPRInfo::nonArgGPR2); + stubJit.move(calleeGPR, GPRInfo::nonArgGPR0); +#if USE(JSVALUE32_64) + stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::nonArgGPR1); +#endif + JITCompiler::Jump slow = stubJit.jump(); + + LinkBuffer patchBuffer(*globalData, &stubJit, callerCodeBlock); + + patchBuffer.link(call, FunctionPtr(codePtr.executableAddress())); + patchBuffer.link(done, callLinkInfo.callReturnLocation.labelAtOffset(0)); + patchBuffer.link(slow, CodeLocationLabel(globalData->getCTIStub(virtualCallThunkGenerator).code())); + + RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine( + FINALIZE_DFG_CODE( + patchBuffer, + ("DFG closure call stub for CodeBlock %p, return point %p, target %p (CodeBlock %p)", + callerCodeBlock, callLinkInfo.callReturnLocation.labelAtOffset(0).executableAddress(), + codePtr.executableAddress(), calleeCodeBlock)), + *globalData, callerCodeBlock->ownerExecutable(), structure, executable, callLinkInfo.codeOrigin)); + + RepatchBuffer repatchBuffer(callerCodeBlock); + + repatchBuffer.replaceWithJump( + RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo.hotPathBegin), + CodeLocationLabel(stubRoutine->code().code())); + linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForCall); + + callLinkInfo.stub = stubRoutine.release(); + + ASSERT(!calleeCodeBlock || calleeCodeBlock->isIncomingCallAlreadyLinked(&callLinkInfo)); } void dfgResetGetByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo) { repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdOptimize); - repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); + CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall); + if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) { + repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch( + RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress(structureLabel), + MacroAssembler::Address( + static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR), + JSCell::structureOffset()), + reinterpret_cast<void*>(-1)); + } + repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1)); #if USE(JSVALUE64) repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0); #else @@ -1143,7 +1284,16 @@ void dfgResetPutByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo) optimizedFunction = operationPutByIdDirectNonStrictOptimize; } repatchBuffer.relink(stubInfo.callReturnLocation, optimizedFunction); - repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), reinterpret_cast<void*>(-1)); + CodeLocationDataLabelPtr structureLabel = stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall); + if (MacroAssembler::canJumpReplacePatchableBranchPtrWithPatch()) { + repatchBuffer.revertJumpReplacementToPatchableBranchPtrWithPatch( + RepatchBuffer::startOfPatchableBranchPtrWithPatchOnAddress(structureLabel), + MacroAssembler::Address( + static_cast<MacroAssembler::RegisterID>(stubInfo.patch.dfg.baseGPR), + JSCell::structureOffset()), + reinterpret_cast<void*>(-1)); + } + repatchBuffer.repatch(structureLabel, reinterpret_cast<void*>(-1)); #if USE(JSVALUE64) repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), 0); #else |