Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Side by Side Diff: Source/core/css/RuleSet.cpp

Issue 17314010: RuleSet causes 600 kB of memory fragmentation (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All r ights reserved. 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All r ights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> 6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/) 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t orchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 } 193 }
194 } else if (!foundSiblingSelector && selector->isSiblingSelector()) 194 } else if (!foundSiblingSelector && selector->isSiblingSelector())
195 foundSiblingSelector = true; 195 foundSiblingSelector = true;
196 } 196 }
197 if (foundSiblingSelector) 197 if (foundSiblingSelector)
198 features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selec torIndex(), ruleData.hasDocumentSecurityOrigin())); 198 features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selec torIndex(), ruleData.hasDocumentSecurityOrigin()));
199 if (ruleData.containsUncommonAttributeSelector()) 199 if (ruleData.containsUncommonAttributeSelector())
200 features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), rule Data.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); 200 features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), rule Data.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
201 } 201 }
202 202
203 void RuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, const RuleDa ta& ruleData) 203 void RuleSet::addToRuleSet(AtomicStringImpl* key, PendingRuleMap& map, const Rul eData& ruleData)
204 { 204 {
205 if (!key) 205 if (!key)
206 return; 206 return;
207 OwnPtr<Vector<RuleData> >& rules = map.add(key, nullptr).iterator->value; 207 OwnPtr<LinkedStack<RuleData> >& rules = map.add(key, nullptr).iterator->valu e;
208 if (!rules) 208 if (!rules)
209 rules = adoptPtr(new Vector<RuleData>); 209 rules = adoptPtr(new LinkedStack<RuleData>);
210 rules->append(ruleData); 210 rules->push(ruleData);
211 } 211 }
212 212
213 bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& rule Data) 213 bool RuleSet::findBestRuleSetAndAdd(const CSSSelector* component, RuleData& rule Data)
ojan 2013/06/20 22:38:45 Should we ASSERT(m_pendingRules) here and in other
abarth-chromium 2013/06/20 22:52:32 The ASSERT isn't really needed because the code wi
214 { 214 {
215 if (component->m_match == CSSSelector::Id) { 215 if (component->m_match == CSSSelector::Id) {
216 addToRuleSet(component->value().impl(), m_idRules, ruleData); 216 addToRuleSet(component->value().impl(), m_pendingRules->idRules, ruleDat a);
217 return true; 217 return true;
218 } 218 }
219 if (component->m_match == CSSSelector::Class) { 219 if (component->m_match == CSSSelector::Class) {
220 addToRuleSet(component->value().impl(), m_classRules, ruleData); 220 addToRuleSet(component->value().impl(), m_pendingRules->classRules, rule Data);
221 return true; 221 return true;
222 } 222 }
223 if (component->isCustomPseudoElement()) { 223 if (component->isCustomPseudoElement()) {
224 addToRuleSet(component->value().impl(), m_shadowPseudoElementRules, rule Data); 224 addToRuleSet(component->value().impl(), m_pendingRules->shadowPseudoElem entRules, ruleData);
225 return true; 225 return true;
226 } 226 }
227 if (component->pseudoType() == CSSSelector::PseudoCue) { 227 if (component->pseudoType() == CSSSelector::PseudoCue) {
228 m_cuePseudoRules.append(ruleData); 228 m_cuePseudoRules.append(ruleData);
229 return true; 229 return true;
230 } 230 }
231 if (SelectorChecker::isCommonPseudoClassSelector(component)) { 231 if (SelectorChecker::isCommonPseudoClassSelector(component)) {
232 switch (component->pseudoType()) { 232 switch (component->pseudoType()) {
233 case CSSSelector::PseudoLink: 233 case CSSSelector::PseudoLink:
234 case CSSSelector::PseudoVisited: 234 case CSSSelector::PseudoVisited:
(...skipping 10 matching lines...) Expand all
245 } 245 }
246 246
247 if (component->m_match == CSSSelector::Tag) { 247 if (component->m_match == CSSSelector::Tag) {
248 if (component->tagQName().localName() != starAtom) { 248 if (component->tagQName().localName() != starAtom) {
249 // If this is part of a subselector chain, recurse ahead to find a n arrower set (ID/class.) 249 // If this is part of a subselector chain, recurse ahead to find a n arrower set (ID/class.)
250 if (component->relation() == CSSSelector::SubSelector 250 if (component->relation() == CSSSelector::SubSelector
251 && (component->tagHistory()->m_match == CSSSelector::Class || co mponent->tagHistory()->m_match == CSSSelector::Id || SelectorChecker::isCommonPs eudoClassSelector(component->tagHistory())) 251 && (component->tagHistory()->m_match == CSSSelector::Class || co mponent->tagHistory()->m_match == CSSSelector::Id || SelectorChecker::isCommonPs eudoClassSelector(component->tagHistory()))
252 && findBestRuleSetAndAdd(component->tagHistory(), ruleData)) 252 && findBestRuleSetAndAdd(component->tagHistory(), ruleData))
253 return true; 253 return true;
254 254
255 addToRuleSet(component->tagQName().localName().impl(), m_tagRules, r uleData); 255 addToRuleSet(component->tagQName().localName().impl(), m_pendingRule s->tagRules, ruleData);
256 return true; 256 return true;
257 } 257 }
258 } 258 }
259 return false; 259 return false;
260 } 260 }
261 261
262 void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addR uleFlags) 262 void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addR uleFlags)
263 { 263 {
264 m_hasDirtyRules = true; 264 ensurePendingRules();
265 RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags); 265 RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);
266 collectFeaturesFromRuleData(m_features, ruleData); 266 collectFeaturesFromRuleData(m_features, ruleData);
267 267
268 if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) { 268 if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) {
269 // If we didn't find a specialized map to stick it in, file under univer sal rules. 269 // If we didn't find a specialized map to stick it in, file under univer sal rules.
270 m_universalRules.append(ruleData); 270 m_universalRules.append(ruleData);
271 } 271 }
272 } 272 }
273 273
274 void RuleSet::addPageRule(StyleRulePage* rule) 274 void RuleSet::addPageRule(StyleRulePage* rule)
275 { 275 {
276 m_hasDirtyRules = true; 276 ensurePendingRules();
277 m_pageRules.append(rule); 277 m_pageRules.append(rule);
278 } 278 }
279 279
280 void RuleSet::addRegionRule(StyleRuleRegion* regionRule, bool hasDocumentSecurit yOrigin) 280 void RuleSet::addRegionRule(StyleRuleRegion* regionRule, bool hasDocumentSecurit yOrigin)
281 { 281 {
282 m_hasDirtyRules = true; 282 ensurePendingRules();
283 OwnPtr<RuleSet> regionRuleSet = RuleSet::create(); 283 OwnPtr<RuleSet> regionRuleSet = RuleSet::create();
284 // The region rule set should take into account the position inside the pare nt rule set. 284 // The region rule set should take into account the position inside the pare nt rule set.
285 // Otherwise, the rules inside region block might be incorrectly positioned before other similar rules from 285 // Otherwise, the rules inside region block might be incorrectly positioned before other similar rules from
286 // the stylesheet that contains the region block. 286 // the stylesheet that contains the region block.
287 regionRuleSet->m_ruleCount = m_ruleCount; 287 regionRuleSet->m_ruleCount = m_ruleCount;
288 288
289 // Collect the region rules into a rule set 289 // Collect the region rules into a rule set
290 // FIXME: Should this add other types of rules? (i.e. use addChildRules() di rectly?) 290 // FIXME: Should this add other types of rules? (i.e. use addChildRules() di rectly?)
291 const Vector<RefPtr<StyleRuleBase> >& childRules = regionRule->childRules(); 291 const Vector<RefPtr<StyleRuleBase> >& childRules = regionRule->childRules();
292 AddRuleFlags addRuleFlags = hasDocumentSecurityOrigin ? RuleHasDocumentSecur ityOrigin : RuleHasNoSpecialState; 292 AddRuleFlags addRuleFlags = hasDocumentSecurityOrigin ? RuleHasDocumentSecur ityOrigin : RuleHasNoSpecialState;
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 372
373 addChildRules(sheet->childRules(), medium, resolver, scope, hasDocumentSecur ityOrigin, addRuleFlags); 373 addChildRules(sheet->childRules(), medium, resolver, scope, hasDocumentSecur ityOrigin, addRuleFlags);
374 } 374 }
375 375
376 void RuleSet::addStyleRule(StyleRule* rule, AddRuleFlags addRuleFlags) 376 void RuleSet::addStyleRule(StyleRule* rule, AddRuleFlags addRuleFlags)
377 { 377 {
378 for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = ru le->selectorList().indexOfNextSelectorAfter(selectorIndex)) 378 for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = ru le->selectorList().indexOfNextSelectorAfter(selectorIndex))
379 addRule(rule, selectorIndex, addRuleFlags); 379 addRule(rule, selectorIndex, addRuleFlags);
380 } 380 }
381 381
382 void RuleSet::shrinkMapVectorsToFit(AtomRuleMap& map) 382 void RuleSet::ensurePendingRules()
383 { 383 {
384 RuleSet::AtomRuleMap::iterator end = map.end(); 384 if (m_pendingRules)
385 for (RuleSet::AtomRuleMap::iterator it = map.begin(); it != end; ++it) 385 return;
386 it->value->shrinkToFit(); 386 m_pendingRules = adoptPtr(new PendingRuleMaps);
387 } 387 }
388 388
389 void RuleSet::shrinkToFit() 389 void RuleSet::compactPendingRules(PendingRuleMap& pendingMap, CompactRuleMap& co mpactMap)
esprehn 2013/06/20 22:29:52 nit: Why isn't this just static in the file? It do
abarth-chromium 2013/06/20 22:52:32 The PendingRuleMap and CompactRuleMap types are pr
390 { 390 {
391 m_hasDirtyRules = false; 391 PendingRuleMap::iterator end = pendingMap.end();
392 shrinkMapVectorsToFit(m_idRules); 392 for (PendingRuleMap::iterator it = pendingMap.begin(); it != end; ++it) {
393 shrinkMapVectorsToFit(m_classRules); 393 OwnPtr<LinkedStack<RuleData> > pendingRules = it->value.release();
394 shrinkMapVectorsToFit(m_tagRules); 394 size_t pendingSize = pendingRules->size();
esprehn 2013/06/20 22:29:52 This is O(n), why not just keep the size of the li
abarth-chromium 2013/06/20 22:52:32 Sure, I can do that. My thinking was that we're g
395 shrinkMapVectorsToFit(m_shadowPseudoElementRules); 395 ASSERT(pendingSize);
396
397 OwnPtr<Vector<RuleData> >& compactRules = compactMap.add(it->key, nullpt r).iterator->value;
398 if (!compactRules) {
399 compactRules = adoptPtr(new Vector<RuleData>);
400 compactRules->reserveInitialCapacity(pendingSize);
401 } else {
402 compactRules->reserveCapacity(pendingRules->size() + pendingSize);
403 }
404
405 do {
406 compactRules->append(pendingRules->peek());
407 pendingRules->pop();
408 } while (!pendingRules->isEmpty());
esprehn 2013/06/20 22:29:52 I think regular while would be more clear, I don't
abarth-chromium 2013/06/20 22:52:32 Will fix. I was excited to be able to use a do...
409
410 ASSERT(compactRules->size() == compactRules->capacity());
411 }
412 }
413
414 void RuleSet::compactRules()
415 {
416 OwnPtr<PendingRuleMaps> pendingRules = m_pendingRules.release();
417 compactPendingRules(pendingRules->idRules, m_idRules);
418 compactPendingRules(pendingRules->classRules, m_classRules);
419 compactPendingRules(pendingRules->tagRules, m_tagRules);
420 compactPendingRules(pendingRules->shadowPseudoElementRules, m_shadowPseudoEl ementRules);
396 m_linkPseudoClassRules.shrinkToFit(); 421 m_linkPseudoClassRules.shrinkToFit();
397 m_cuePseudoRules.shrinkToFit(); 422 m_cuePseudoRules.shrinkToFit();
398 m_focusPseudoClassRules.shrinkToFit(); 423 m_focusPseudoClassRules.shrinkToFit();
399 m_universalRules.shrinkToFit(); 424 m_universalRules.shrinkToFit();
400 m_pageRules.shrinkToFit(); 425 m_pageRules.shrinkToFit();
401 } 426 }
402 427
403 } // namespace WebCore 428 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698