Changeset 179392 in webkit for trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
- Timestamp:
- Jan 29, 2015, 8:28:36 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
r179357 r179392 1 1 /* 2 * Copyright (C) 2012 -2015Apple Inc. All rights reserved.2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 48 48 } 49 49 50 m_ variants.append(CallVariant(value.asCell()));50 m_edges.append(CallEdge(CallVariant(value.asCell()), 1)); 51 51 } 52 52 … … 130 130 UNUSED_PARAM(profiledBlock); 131 131 132 if (Options::callStatusShouldUseCallEdgeProfile()) { 133 // Always trust the call edge profile over anything else since this has precise counts. 134 // It can make the best possible decision because it never "forgets" what happened for any 135 // call, with the exception of fading out the counts of old calls (for example if the 136 // counter type is 16-bit then calls that happened more than 2^16 calls ago are given half 137 // weight, and this compounds for every 2^15 [sic] calls after that). The combination of 138 // high fidelity for recent calls and fading for older calls makes this the most useful 139 // mechamism of choosing how to optimize future calls. 140 CallEdgeProfile* edgeProfile = callLinkInfo.callEdgeProfile.get(); 141 WTF::loadLoadFence(); 142 if (edgeProfile) { 143 CallLinkStatus result = computeFromCallEdgeProfile(edgeProfile); 144 if (!!result) 145 return result; 146 } 147 } 148 132 149 return computeFromCallLinkInfo(locker, callLinkInfo); 133 150 } … … 149 166 // is probably OK for now. 150 167 151 // PolymorphicCallStubRoutine is a GCAwareJITStubRoutine, so if non-null, it will stay alive152 // until next GC even if the CallLinkInfo is concurrently cleared. Also, the variants list is153 // never mutated after the PolymorphicCallStubRoutine is instantiated. We have some conservative154 // fencing in place to make sure that we see the variants list after construction.155 if (PolymorphicCallStubRoutine* stub = callLinkInfo.stub.get()) {156 WTF::loadLoadFence();157 158 CallEdgeList edges = stub->edges();159 160 // Now that we've loaded the edges list, there are no further concurrency concerns. We will161 // just manipulate and prune this list to our liking - mostly removing entries that are too162 // infrequent and ensuring that it's sorted in descending order of frequency.163 164 RELEASE_ASSERT(edges.size());165 166 std::sort(167 edges.begin(), edges.end(),168 [] (CallEdge a, CallEdge b) {169 return a.count() > b.count();170 });171 RELEASE_ASSERT(edges.first().count() >= edges.last().count());172 173 double totalCallsToKnown = 0;174 double totalCallsToUnknown = callLinkInfo.slowPathCount;175 CallVariantList variants;176 for (size_t i = 0; i < edges.size(); ++i) {177 CallEdge edge = edges[i];178 // If the call is at the tail of the distribution, then we don't optimize it and we179 // treat it as if it was a call to something unknown. We define the tail as being either180 // a call that doesn't belong to the N most frequent callees (N =181 // maxPolymorphicCallVariantsForInlining) or that has a total call count that is too182 // small.183 if (i >= Options::maxPolymorphicCallVariantsForInlining()184 || edge.count() < Options::frequentCallThreshold())185 totalCallsToUnknown += edge.count();186 else {187 totalCallsToKnown += edge.count();188 variants.append(edge.callee());189 }190 }191 192 // Bail if we didn't find any calls that qualified.193 RELEASE_ASSERT(!!totalCallsToKnown == !!variants.size());194 if (variants.isEmpty())195 return takesSlowPath();196 197 // We require that the distribution of callees is skewed towards a handful of common ones.198 if (totalCallsToKnown / totalCallsToUnknown < Options::minimumCallToKnownRate())199 return takesSlowPath();200 201 RELEASE_ASSERT(totalCallsToKnown);202 RELEASE_ASSERT(variants.size());203 204 CallLinkStatus result;205 result.m_variants = variants;206 result.m_couldTakeSlowPath = !!totalCallsToUnknown;207 return result;208 }209 210 168 if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) 211 169 return takesSlowPath(); 170 171 if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get()) 172 return CallLinkStatus(stub->executable()); 212 173 213 174 JSFunction* target = callLinkInfo.lastSeenCallee.get(); … … 219 180 220 181 return CallLinkStatus(target); 182 } 183 184 CallLinkStatus CallLinkStatus::computeFromCallEdgeProfile(CallEdgeProfile* edgeProfile) 185 { 186 // In cases where the call edge profile saw nothing, use the CallLinkInfo instead. 187 if (!edgeProfile->totalCalls()) 188 return CallLinkStatus(); 189 190 // To do anything meaningful, we require that the majority of calls are to something we 191 // know how to handle. 192 unsigned numCallsToKnown = edgeProfile->numCallsToKnownCells(); 193 unsigned numCallsToUnknown = edgeProfile->numCallsToNotCell() + edgeProfile->numCallsToUnknownCell(); 194 195 // We require that the majority of calls were to something that we could possibly inline. 196 if (numCallsToKnown <= numCallsToUnknown) 197 return takesSlowPath(); 198 199 // We require that the number of such calls is greater than some minimal threshold, so that we 200 // avoid inlining completely cold calls. 201 if (numCallsToKnown < Options::frequentCallThreshold()) 202 return takesSlowPath(); 203 204 CallLinkStatus result; 205 result.m_edges = edgeProfile->callEdges(); 206 result.m_couldTakeSlowPath = !!numCallsToUnknown; 207 result.m_canTrustCounts = true; 208 209 return result; 221 210 } 222 211 … … 294 283 bool CallLinkStatus::isClosureCall() const 295 284 { 296 for (unsigned i = m_ variants.size(); i--;) {297 if (m_ variants[i].isClosureCall())285 for (unsigned i = m_edges.size(); i--;) { 286 if (m_edges[i].callee().isClosureCall()) 298 287 return true; 299 288 } … … 303 292 void CallLinkStatus::makeClosureCall() 304 293 { 305 m_variants = despecifiedVariantList(m_variants); 294 ASSERT(!m_isProved); 295 for (unsigned i = m_edges.size(); i--;) 296 m_edges[i] = m_edges[i].despecifiedClosure(); 297 298 if (!ASSERT_DISABLED) { 299 // Doing this should not have created duplicates, because the CallEdgeProfile 300 // should despecify closures if doing so would reduce the number of known callees. 301 for (unsigned i = 0; i < m_edges.size(); ++i) { 302 for (unsigned j = i + 1; j < m_edges.size(); ++j) 303 ASSERT(m_edges[i].callee() != m_edges[j].callee()); 304 } 305 } 306 306 } 307 307 … … 321 321 out.print(comma, "Could Take Slow Path"); 322 322 323 if (!m_variants.isEmpty()) 324 out.print(comma, listDump(m_variants)); 323 out.print(listDump(m_edges)); 325 324 } 326 325
Note:
See TracChangeset
for help on using the changeset viewer.