CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) { ConcurrentJITLocker locker(profiledBlock->m_lock); UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) if (!profiledBlock->hasBaselineJITProfiling()) return computeFromLLInt(profiledBlock, bytecodeIndex); if (profiledBlock->couldTakeSlowCase(bytecodeIndex)) return CallLinkStatus::takesSlowPath(); CallLinkInfo& callLinkInfo = profiledBlock->getCallLinkInfo(bytecodeIndex); if (callLinkInfo.stub) return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return computeFromLLInt(profiledBlock, bytecodeIndex); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFromLLInt(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(LLINT) #if ENABLE(DFG_JIT) if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction))) { // We could force this to be a closure call, but instead we'll just assume that it // takes slow path. return takesSlowPath(); } #else UNUSED_PARAM(locker); #endif VM& vm = *profiledBlock->vm(); Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; OpcodeID op = vm.interpreter->getOpcodeID(instruction[0].u.opcode); if (op != op_call && op != op_construct) return CallLinkStatus(); LLIntCallLinkInfo* callLinkInfo = instruction[5].u.callLinkInfo; return CallLinkStatus(callLinkInfo->lastSeenCallee.get()); #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) { // Note that despite requiring that the locker is held, this code is racy with respect // to the CallLinkInfo: it may get cleared while this code runs! This is because // CallLinkInfo::unlink() may be called from a different CodeBlock than the one that owns // the CallLinkInfo and currently we save space by not having CallLinkInfos know who owns // them. So, there is no way for either the caller of CallLinkInfo::unlock() or unlock() // itself to figure out which lock to lock. // // Fortunately, that doesn't matter. The only things we ask of CallLinkInfo - the slow // path count, the stub, and the target - can all be asked racily. Stubs and targets can // only be deleted at next GC, so if we load a non-null one, then it must contain data // that is still marginally valid (i.e. the pointers ain't stale). This kind of raciness // is probably OK for now. if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) return takesSlowPath(); if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get()) return CallLinkStatus(stub->executable(), stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return CallLinkStatus(); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); }
CallLinkStatus CallLinkStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(LLINT) Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; LLIntCallLinkInfo* callLinkInfo = instruction[5].u.callLinkInfo; return CallLinkStatus(callLinkInfo->lastSeenCallee.get()); #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFor( CodeBlock* profiledBlock, unsigned bytecodeIndex, const CallLinkInfoMap& map) { ConcurrentJITLocker locker(profiledBlock->m_lock); UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(map); #if ENABLE(DFG_JIT) if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint)) || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable))) return takesSlowPath(); CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)); if (!callLinkInfo) return computeFromLLInt(locker, profiledBlock, bytecodeIndex); CallLinkStatus result = computeFor(locker, *callLinkInfo); if (!result) return computeFromLLInt(locker, profiledBlock, bytecodeIndex); if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction))) result.makeClosureCall(); return result; #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) { if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) return takesSlowPath(); if (callLinkInfo.stub) return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure()); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return CallLinkStatus(); if (callLinkInfo.hasSeenClosure) return CallLinkStatus(target->executable(), target->structure()); return CallLinkStatus(target); }
CallLinkStatus CallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(JIT) && ENABLE(VALUE_PROFILER) if (!profiledBlock->numberOfCallLinkInfos()) return computeFromLLInt(profiledBlock, bytecodeIndex); if (profiledBlock->couldTakeSlowCase(bytecodeIndex)) return CallLinkStatus(0, true); CallLinkInfo& callLinkInfo = profiledBlock->getCallLinkInfo(bytecodeIndex); JSFunction* target = callLinkInfo.lastSeenCallee.get(); if (!target) return computeFromLLInt(profiledBlock, bytecodeIndex); return CallLinkStatus(target, false, !!callLinkInfo.stub); #else return CallLinkStatus(0, false, false); #endif }
CallLinkStatus CallLinkStatus::computeFor( CodeBlock* profiledBlock, unsigned bytecodeIndex, const CallLinkInfoMap& map) { ConcurrentJITLocker locker(profiledBlock->m_lock); UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(map); #if ENABLE(DFG_JIT) ExitSiteData exitSiteData = computeExitSiteData(locker, profiledBlock, bytecodeIndex); if (exitSiteData.m_takesSlowPath) return takesSlowPath(); CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)); if (!callLinkInfo) return computeFromLLInt(locker, profiledBlock, bytecodeIndex); return computeFor(locker, *callLinkInfo, exitSiteData); #else return CallLinkStatus(); #endif }