Changeset 179357 in webkit for trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
- Timestamp:
- Jan 29, 2015, 12:33:45 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp
r179241 r179357 1 1 /* 2 * Copyright (C) 2012 , 2013, 2014Apple Inc. All rights reserved.2 * Copyright (C) 2012-2015 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_ edges.append(CallEdge(CallVariant(value.asCell()), 1));50 m_variants.append(CallVariant(value.asCell())); 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 any135 // call, with the exception of fading out the counts of old calls (for example if the136 // counter type is 16-bit then calls that happened more than 2^16 calls ago are given half137 // weight, and this compounds for every 2^15 [sic] calls after that). The combination of138 // high fidelity for recent calls and fading for older calls makes this the most useful139 // 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 149 132 return computeFromCallLinkInfo(locker, callLinkInfo); 150 133 } … … 166 149 // is probably OK for now. 167 150 151 // PolymorphicCallStubRoutine is a GCAwareJITStubRoutine, so if non-null, it will stay alive 152 // until next GC even if the CallLinkInfo is concurrently cleared. Also, the variants list is 153 // never mutated after the PolymorphicCallStubRoutine is instantiated. We have some conservative 154 // 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 will 161 // just manipulate and prune this list to our liking - mostly removing entries that are too 162 // 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 we 179 // treat it as if it was a call to something unknown. We define the tail as being either 180 // a call that doesn't belong to the N most frequent callees (N = 181 // maxPolymorphicCallVariantsForInlining) or that has a total call count that is too 182 // 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 168 210 if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) 169 211 return takesSlowPath(); 170 171 if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get())172 return CallLinkStatus(stub->executable());173 212 174 213 JSFunction* target = callLinkInfo.lastSeenCallee.get(); … … 180 219 181 220 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 we191 // 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 we200 // 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;210 221 } 211 222 … … 283 294 bool CallLinkStatus::isClosureCall() const 284 295 { 285 for (unsigned i = m_ edges.size(); i--;) {286 if (m_ edges[i].callee().isClosureCall())296 for (unsigned i = m_variants.size(); i--;) { 297 if (m_variants[i].isClosureCall()) 287 298 return true; 288 299 } … … 292 303 void CallLinkStatus::makeClosureCall() 293 304 { 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 } 305 m_variants = despecifiedVariantList(m_variants); 306 306 } 307 307 … … 321 321 out.print(comma, "Could Take Slow Path"); 322 322 323 out.print(listDump(m_edges)); 323 if (!m_variants.isEmpty()) 324 out.print(comma, listDump(m_variants)); 324 325 } 325 326
Note:
See TracChangeset
for help on using the changeset viewer.