Changeset 172940 in webkit for trunk/Source/JavaScriptCore/bytecode
- Timestamp:
- Aug 25, 2014, 3:35:40 PM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore/bytecode
- Files:
-
- 7 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
r172176 r172940 84 84 if (!!lastSeenCallee && !Heap::isMarked(lastSeenCallee.get())) 85 85 lastSeenCallee.clear(); 86 87 if (callEdgeProfile) { 88 WTF::loadLoadFence(); 89 callEdgeProfile->visitWeak(); 90 } 86 91 } 87 92 -
trunk/Source/JavaScriptCore/bytecode/CallLinkInfo.h
r166392 r172940 27 27 #define CallLinkInfo_h 28 28 29 #include "CallEdgeProfile.h" 29 30 #include "ClosureCallStubRoutine.h" 30 31 #include "CodeLocation.h" … … 34 35 #include "Opcode.h" 35 36 #include "WriteBarrier.h" 37 #include <wtf/OwnPtr.h> 36 38 #include <wtf/SentinelLinkedList.h> 37 39 … … 89 91 unsigned slowPathCount; 90 92 CodeOrigin codeOrigin; 93 OwnPtr<CallEdgeProfile> callEdgeProfile; 91 94 92 95 bool isLinked() { return stub || callee; } -
trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
r172176 r172940 33 33 #include "JSCInlines.h" 34 34 #include <wtf/CommaPrinter.h> 35 #include <wtf/ListDump.h> 35 36 36 37 namespace JSC { … … 39 40 40 41 CallLinkStatus::CallLinkStatus(JSValue value) 41 : m_callTarget(value) 42 , m_executable(0) 43 , m_couldTakeSlowPath(false) 42 : m_couldTakeSlowPath(false) 44 43 , m_isProved(false) 45 44 { 46 if (!value || !value.isCell()) 45 if (!value || !value.isCell()) { 46 m_couldTakeSlowPath = true; 47 47 return; 48 49 if (!value.asCell()->inherits(JSFunction::info())) 50 return; 51 52 m_executable = jsCast<JSFunction*>(value.asCell())->executable(); 53 } 54 55 JSFunction* CallLinkStatus::function() const 56 { 57 if (!m_callTarget || !m_callTarget.isCell()) 58 return 0; 59 60 if (!m_callTarget.asCell()->inherits(JSFunction::info())) 61 return 0; 62 63 return jsCast<JSFunction*>(m_callTarget.asCell()); 64 } 65 66 InternalFunction* CallLinkStatus::internalFunction() const 67 { 68 if (!m_callTarget || !m_callTarget.isCell()) 69 return 0; 70 71 if (!m_callTarget.asCell()->inherits(InternalFunction::info())) 72 return 0; 73 74 return jsCast<InternalFunction*>(m_callTarget.asCell()); 75 } 76 77 Intrinsic CallLinkStatus::intrinsicFor(CodeSpecializationKind kind) const 78 { 79 if (!m_executable) 80 return NoIntrinsic; 81 82 return m_executable->intrinsicFor(kind); 48 } 49 50 m_edges.append(CallEdge(CallVariant(value.asCell()), 1)); 83 51 } 84 52 … … 88 56 UNUSED_PARAM(bytecodeIndex); 89 57 #if ENABLE(DFG_JIT) 90 if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, Bad Function))) {58 if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell))) { 91 59 // We could force this to be a closure call, but instead we'll just assume that it 92 60 // takes slow path. … … 126 94 return computeFromLLInt(locker, profiledBlock, bytecodeIndex); 127 95 128 return computeFor(locker, *callLinkInfo, exitSiteData);96 return computeFor(locker, profiledBlock, *callLinkInfo, exitSiteData); 129 97 #else 130 98 return CallLinkStatus(); … … 140 108 #if ENABLE(DFG_JIT) 141 109 exitSiteData.m_takesSlowPath = 142 profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, Bad Cache, exitingJITType))110 profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType, exitingJITType)) 143 111 || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable, exitingJITType)); 144 112 exitSiteData.m_badFunction = 145 profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, Bad Function, exitingJITType));113 profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell, exitingJITType)); 146 114 #else 147 115 UNUSED_PARAM(locker); … … 155 123 156 124 #if ENABLE(JIT) 157 CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) 125 CallLinkStatus CallLinkStatus::computeFor( 126 const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo) 127 { 128 // We don't really need this, but anytime we have to debug this code, it becomes indispensable. 129 UNUSED_PARAM(profiledBlock); 130 131 if (Options::callStatusShouldUseCallEdgeProfile()) { 132 // Always trust the call edge profile over anything else since this has precise counts. 133 // It can make the best possible decision because it never "forgets" what happened for any 134 // call, with the exception of fading out the counts of old calls (for example if the 135 // counter type is 16-bit then calls that happened more than 2^16 calls ago are given half 136 // weight, and this compounds for every 2^15 [sic] calls after that). The combination of 137 // high fidelity for recent calls and fading for older calls makes this the most useful 138 // mechamism of choosing how to optimize future calls. 139 CallEdgeProfile* edgeProfile = callLinkInfo.callEdgeProfile.get(); 140 WTF::loadLoadFence(); 141 if (edgeProfile) { 142 CallLinkStatus result = computeFromCallEdgeProfile(edgeProfile); 143 if (!!result) 144 return result; 145 } 146 } 147 148 return computeFromCallLinkInfo(locker, callLinkInfo); 149 } 150 151 CallLinkStatus CallLinkStatus::computeFromCallLinkInfo( 152 const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) 158 153 { 159 154 // Note that despite requiring that the locker is held, this code is racy with respect … … 178 173 JSFunction* target = callLinkInfo.lastSeenCallee.get(); 179 174 if (!target) 180 return CallLinkStatus();175 return takesSlowPath(); 181 176 182 177 if (callLinkInfo.hasSeenClosure) … … 186 181 } 187 182 183 CallLinkStatus CallLinkStatus::computeFromCallEdgeProfile(CallEdgeProfile* edgeProfile) 184 { 185 // In cases where the call edge profile saw nothing, use the CallLinkInfo instead. 186 if (!edgeProfile->totalCalls()) 187 return CallLinkStatus(); 188 189 // To do anything meaningful, we require that the majority of calls are to something we 190 // know how to handle. 191 unsigned numCallsToKnown = edgeProfile->numCallsToKnownCells(); 192 unsigned numCallsToUnknown = edgeProfile->numCallsToNotCell() + edgeProfile->numCallsToUnknownCell(); 193 194 // We require that the majority of calls were to something that we could possibly inline. 195 if (numCallsToKnown <= numCallsToUnknown) 196 return takesSlowPath(); 197 198 // We require that the number of such calls is greater than some minimal threshold, so that we 199 // avoid inlining completely cold calls. 200 if (numCallsToKnown < Options::frequentCallThreshold()) 201 return takesSlowPath(); 202 203 CallLinkStatus result; 204 result.m_edges = edgeProfile->callEdges(); 205 result.m_couldTakeSlowPath = !!numCallsToUnknown; 206 result.m_canTrustCounts = true; 207 208 return result; 209 } 210 188 211 CallLinkStatus CallLinkStatus::computeFor( 189 const ConcurrentJITLocker& locker, CallLinkInfo& callLinkInfo, ExitSiteData exitSiteData) 190 { 191 if (exitSiteData.m_takesSlowPath) 192 return takesSlowPath(); 193 194 CallLinkStatus result = computeFor(locker, callLinkInfo); 212 const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo, 213 ExitSiteData exitSiteData) 214 { 215 CallLinkStatus result = computeFor(locker, profiledBlock, callLinkInfo); 195 216 if (exitSiteData.m_badFunction) 196 217 result.makeClosureCall(); 218 if (exitSiteData.m_takesSlowPath) 219 result.m_couldTakeSlowPath = true; 197 220 198 221 return result; … … 228 251 { 229 252 ConcurrentJITLocker locker(dfgCodeBlock->m_lock); 230 map.add(info.codeOrigin, computeFor(locker, info, exitSiteData));253 map.add(info.codeOrigin, computeFor(locker, dfgCodeBlock, info, exitSiteData)); 231 254 } 232 255 } … … 257 280 } 258 281 282 bool CallLinkStatus::isClosureCall() const 283 { 284 for (unsigned i = m_edges.size(); i--;) { 285 if (m_edges[i].callee().isClosureCall()) 286 return true; 287 } 288 return false; 289 } 290 291 void CallLinkStatus::makeClosureCall() 292 { 293 ASSERT(!m_isProved); 294 for (unsigned i = m_edges.size(); i--;) 295 m_edges[i] = m_edges[i].despecifiedClosure(); 296 297 if (!ASSERT_DISABLED) { 298 // Doing this should not have created duplicates, because the CallEdgeProfile 299 // should despecify closures if doing so would reduce the number of known callees. 300 for (unsigned i = 0; i < m_edges.size(); ++i) { 301 for (unsigned j = i + 1; j < m_edges.size(); ++j) 302 ASSERT(m_edges[i].callee() != m_edges[j].callee()); 303 } 304 } 305 } 306 259 307 void CallLinkStatus::dump(PrintStream& out) const 260 308 { … … 272 320 out.print(comma, "Could Take Slow Path"); 273 321 274 if (m_callTarget) 275 out.print(comma, "Known target: ", m_callTarget); 276 277 if (m_executable) { 278 out.print(comma, "Executable/CallHash: ", RawPointer(m_executable)); 279 if (!isCompilationThread()) 280 out.print("/", m_executable->hashFor(CodeForCall)); 281 } 322 out.print(listDump(m_edges)); 282 323 } 283 324 -
trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.h
r172176 r172940 47 47 public: 48 48 CallLinkStatus() 49 : m_executable(0) 50 , m_couldTakeSlowPath(false) 49 : m_couldTakeSlowPath(false) 51 50 , m_isProved(false) 51 , m_canTrustCounts(false) 52 52 { 53 53 } … … 62 62 explicit CallLinkStatus(JSValue); 63 63 64 CallLinkStatus( ExecutableBase* executable)65 : m_e xecutable(executable)64 CallLinkStatus(CallVariant variant) 65 : m_edges(1, CallEdge(variant, 1)) 66 66 , m_couldTakeSlowPath(false) 67 67 , m_isProved(false) 68 , m_canTrustCounts(false) 68 69 { 69 70 } … … 93 94 // Computes the status assuming that we never took slow path and never previously 94 95 // exited. 95 static CallLinkStatus computeFor(const ConcurrentJITLocker&, CallLinkInfo&); 96 static CallLinkStatus computeFor(const ConcurrentJITLocker&, CallLinkInfo&, ExitSiteData); 96 static CallLinkStatus computeFor(const ConcurrentJITLocker&, CodeBlock*, CallLinkInfo&); 97 static CallLinkStatus computeFor( 98 const ConcurrentJITLocker&, CodeBlock*, CallLinkInfo&, ExitSiteData); 97 99 #endif 98 100 … … 108 110 CodeBlock*, CodeOrigin, const CallLinkInfoMap&, const ContextMap&); 109 111 110 bool isSet() const { return m_callTarget || m_executable|| m_couldTakeSlowPath; }112 bool isSet() const { return !m_edges.isEmpty() || m_couldTakeSlowPath; } 111 113 112 114 bool operator!() const { return !isSet(); } 113 115 114 116 bool couldTakeSlowPath() const { return m_couldTakeSlowPath; } 115 bool isClosureCall() const { return m_executable && !m_callTarget; }116 117 117 JSValue callTarget() const { return m_callTarget; } 118 JSFunction* function() const; 119 InternalFunction* internalFunction() const; 120 Intrinsic intrinsicFor(CodeSpecializationKind) const; 121 ExecutableBase* executable() const { return m_executable; } 118 CallEdgeList edges() const { return m_edges; } 119 unsigned size() const { return m_edges.size(); } 120 CallEdge at(unsigned i) const { return m_edges[i]; } 121 CallEdge operator[](unsigned i) const { return at(i); } 122 122 bool isProved() const { return m_isProved; } 123 bool canOptimize() const { return (m_callTarget || m_executable) && !m_couldTakeSlowPath; } 123 bool canOptimize() const { return !m_edges.isEmpty(); } 124 bool canTrustCounts() const { return m_canTrustCounts; } 125 126 bool isClosureCall() const; // Returns true if any callee is a closure call. 124 127 125 128 void dump(PrintStream&) const; 126 129 127 130 private: 128 void makeClosureCall() 129 { 130 ASSERT(!m_isProved); 131 // Turn this into a closure call. 132 m_callTarget = JSValue(); 133 } 131 void makeClosureCall(); 134 132 135 133 static CallLinkStatus computeFromLLInt(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex); 134 #if ENABLE(JIT) 135 static CallLinkStatus computeFromCallEdgeProfile(CallEdgeProfile*); 136 static CallLinkStatus computeFromCallLinkInfo( 137 const ConcurrentJITLocker&, CallLinkInfo&); 138 #endif 136 139 137 JSValue m_callTarget; 138 ExecutableBase* m_executable; 140 CallEdgeList m_edges; 139 141 bool m_couldTakeSlowPath; 140 142 bool m_isProved; 143 bool m_canTrustCounts; 141 144 }; 142 145 -
trunk/Source/JavaScriptCore/bytecode/CodeOrigin.h
r172853 r172940 155 155 } 156 156 157 static bool isNormalCall(Kind kind) 158 { 159 switch (kind) { 160 case Call: 161 case Construct: 162 return true; 163 default: 164 return false; 165 } 166 } 167 157 168 Vector<ValueRecovery> arguments; // Includes 'this'. 158 169 WriteBarrier<ScriptExecutable> executable; -
trunk/Source/JavaScriptCore/bytecode/ExitKind.cpp
r171613 r172940 39 39 case BadType: 40 40 return "BadType"; 41 case Bad Function:42 return "Bad Function";41 case BadCell: 42 return "BadCell"; 43 43 case BadExecutable: 44 44 return "BadExecutable"; -
trunk/Source/JavaScriptCore/bytecode/ExitKind.h
r171613 r172940 32 32 ExitKindUnset, 33 33 BadType, // We exited because a type prediction was wrong. 34 Bad Function, // We exited because we made an incorrect assumption about what function we would see.34 BadCell, // We exited because we made an incorrect assumption about what cell we would see. Usually used for function checks. 35 35 BadExecutable, // We exited because we made an incorrect assumption about what executable we would see. 36 36 BadCache, // We exited because an inline cache was wrong. -
trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
r172129 r172940 188 188 list->at(listIndex).stubRoutine()); 189 189 callLinkStatus = std::make_unique<CallLinkStatus>( 190 CallLinkStatus::computeFor(locker, *stub->m_callLinkInfo, callExitSiteData)); 190 CallLinkStatus::computeFor( 191 locker, profiledBlock, *stub->m_callLinkInfo, callExitSiteData)); 191 192 break; 192 193 } -
trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
r172129 r172940 248 248 std::make_unique<CallLinkStatus>( 249 249 CallLinkStatus::computeFor( 250 locker, *stub->m_callLinkInfo, callExitSiteData));250 locker, profiledBlock, *stub->m_callLinkInfo, callExitSiteData)); 251 251 252 252 variant = PutByIdVariant::setter(
Note:
See TracChangeset
for help on using the changeset viewer.