[Content Extensions] Cache actions with domains that match everything
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jul 2015 00:12:13 +0000 (00:12 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jul 2015 00:12:13 +0000 (00:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147050

Reviewed by Benjamin Poulain.

Source/WebCore:

If you have lots of rules with triggers like {"url-filter":".*","if-domain":["*webkit.org"]}
we will spend a lot of time adding unnecessary actions to HashSets when you are not on webkit.org.
Caching all the rules and only adding them to a collection once when the domain changes saves a lot of URL interpreting time.

We already had an optimization for the css-display-none actions with triggers that matched everything using a special bytecode operation.
This removes the need for a special bytecode operation by caching the triggers that match everything with and without domains,
then from those cached actions we compile a stylesheet, and create cached actions for every new domain we visit.

All functionality is covered by existing API tests.

* contentextensions/CompiledContentExtension.cpp:
(WebCore::ContentExtensions::CompiledContentExtension::~CompiledContentExtension):
(WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors): Deleted.
* contentextensions/CompiledContentExtension.h:
* contentextensions/ContentExtension.cpp:
(WebCore::ContentExtensions::ContentExtension::ContentExtension):
(WebCore::ContentExtensions::ContentExtension::findFirstIgnorePreviousRules):
(WebCore::ContentExtensions::ContentExtension::globalDisplayNoneStyleSheet):
(WebCore::ContentExtensions::ContentExtension::compileGlobalDisplayNoneStyleSheet):
(WebCore::ContentExtensions::ContentExtension::populateDomainCacheIfNeeded):
(WebCore::ContentExtensions::ContentExtension::cachedDomainActions):
(WebCore::ContentExtensions::ContentExtension::universalActionsWithDomains):
* contentextensions/ContentExtension.h:
(WebCore::ContentExtensions::ContentExtension::compiledExtension):
(WebCore::ContentExtensions::ContentExtension::universalActionsWithoutDomains):
* contentextensions/ContentExtensionCompiler.cpp:
(WebCore::ContentExtensions::compileRuleList):
* contentextensions/ContentExtensionRule.cpp:
(WebCore::ContentExtensions::ContentExtensionRule::ContentExtensionRule):
(WebCore::ContentExtensions::Action::deserialize):
(WebCore::ContentExtensions::Action::deserializeType):
(WebCore::ContentExtensions::Action::serializedLength):
* contentextensions/ContentExtensionRule.h:
(WebCore::ContentExtensions::Action::operator==):
(WebCore::ContentExtensions::Action::setExtensionIdentifier):
(WebCore::ContentExtensions::Action::extensionIdentifier):
* contentextensions/ContentExtensionsBackend.cpp:
(WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
* contentextensions/DFABytecode.h:
(WebCore::ContentExtensions::instructionSizeWithArguments):
* contentextensions/DFABytecodeCompiler.cpp:
(WebCore::ContentExtensions::DFABytecodeCompiler::emitAppendAction):
* contentextensions/DFABytecodeInterpreter.cpp:
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpretAppendAction):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpretTestFlagsAndAppendAction):
(WebCore::ContentExtensions::DFABytecodeInterpreter::actionsMatchingEverything):
(WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
(WebCore::ContentExtensions::DFABytecodeInterpreter::actionsForDefaultStylesheetFromDFARoot): Deleted.
* contentextensions/DFABytecodeInterpreter.h:
* loader/ResourceLoadInfo.h:

Source/WebKit2:

* UIProcess/API/APIUserContentExtensionStore.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@187049 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/contentextensions/CompiledContentExtension.cpp
Source/WebCore/contentextensions/CompiledContentExtension.h
Source/WebCore/contentextensions/ContentExtension.cpp
Source/WebCore/contentextensions/ContentExtension.h
Source/WebCore/contentextensions/ContentExtensionCompiler.cpp
Source/WebCore/contentextensions/ContentExtensionRule.cpp
Source/WebCore/contentextensions/ContentExtensionRule.h
Source/WebCore/contentextensions/ContentExtensionsBackend.cpp
Source/WebCore/contentextensions/DFABytecode.h
Source/WebCore/contentextensions/DFABytecodeCompiler.cpp
Source/WebCore/contentextensions/DFABytecodeInterpreter.cpp
Source/WebCore/contentextensions/DFABytecodeInterpreter.h
Source/WebCore/loader/ResourceLoadInfo.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/APIUserContentExtensionStore.h

index 00989c6..ab7d67f 100644 (file)
@@ -1,3 +1,61 @@
+2015-07-20  Alex Christensen  <achristensen@webkit.org>
+
+        [Content Extensions] Cache actions with domains that match everything
+        https://bugs.webkit.org/show_bug.cgi?id=147050
+
+        Reviewed by Benjamin Poulain.
+
+        If you have lots of rules with triggers like {"url-filter":".*","if-domain":["*webkit.org"]}
+        we will spend a lot of time adding unnecessary actions to HashSets when you are not on webkit.org.
+        Caching all the rules and only adding them to a collection once when the domain changes saves a lot of URL interpreting time.
+
+        We already had an optimization for the css-display-none actions with triggers that matched everything using a special bytecode operation.
+        This removes the need for a special bytecode operation by caching the triggers that match everything with and without domains,
+        then from those cached actions we compile a stylesheet, and create cached actions for every new domain we visit.
+
+        All functionality is covered by existing API tests.
+
+        * contentextensions/CompiledContentExtension.cpp:
+        (WebCore::ContentExtensions::CompiledContentExtension::~CompiledContentExtension):
+        (WebCore::ContentExtensions::CompiledContentExtension::globalDisplayNoneSelectors): Deleted.
+        * contentextensions/CompiledContentExtension.h:
+        * contentextensions/ContentExtension.cpp:
+        (WebCore::ContentExtensions::ContentExtension::ContentExtension):
+        (WebCore::ContentExtensions::ContentExtension::findFirstIgnorePreviousRules):
+        (WebCore::ContentExtensions::ContentExtension::globalDisplayNoneStyleSheet):
+        (WebCore::ContentExtensions::ContentExtension::compileGlobalDisplayNoneStyleSheet):
+        (WebCore::ContentExtensions::ContentExtension::populateDomainCacheIfNeeded):
+        (WebCore::ContentExtensions::ContentExtension::cachedDomainActions):
+        (WebCore::ContentExtensions::ContentExtension::universalActionsWithDomains):
+        * contentextensions/ContentExtension.h:
+        (WebCore::ContentExtensions::ContentExtension::compiledExtension):
+        (WebCore::ContentExtensions::ContentExtension::universalActionsWithoutDomains):
+        * contentextensions/ContentExtensionCompiler.cpp:
+        (WebCore::ContentExtensions::compileRuleList):
+        * contentextensions/ContentExtensionRule.cpp:
+        (WebCore::ContentExtensions::ContentExtensionRule::ContentExtensionRule):
+        (WebCore::ContentExtensions::Action::deserialize):
+        (WebCore::ContentExtensions::Action::deserializeType):
+        (WebCore::ContentExtensions::Action::serializedLength):
+        * contentextensions/ContentExtensionRule.h:
+        (WebCore::ContentExtensions::Action::operator==):
+        (WebCore::ContentExtensions::Action::setExtensionIdentifier):
+        (WebCore::ContentExtensions::Action::extensionIdentifier):
+        * contentextensions/ContentExtensionsBackend.cpp:
+        (WebCore::ContentExtensions::ContentExtensionsBackend::actionsForResourceLoad):
+        * contentextensions/DFABytecode.h:
+        (WebCore::ContentExtensions::instructionSizeWithArguments):
+        * contentextensions/DFABytecodeCompiler.cpp:
+        (WebCore::ContentExtensions::DFABytecodeCompiler::emitAppendAction):
+        * contentextensions/DFABytecodeInterpreter.cpp:
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpretTestFlagsAndAppendAction):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::actionsMatchingEverything):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::interpret):
+        (WebCore::ContentExtensions::DFABytecodeInterpreter::actionsForDefaultStylesheetFromDFARoot): Deleted.
+        * contentextensions/DFABytecodeInterpreter.h:
+        * loader/ResourceLoadInfo.h:
+
 2015-07-20  Jeremy Jones  <jeremyj@apple.com>
 
         Adopt AVPlayerLayerView
index cd056aa..e577a91 100644 (file)
@@ -35,24 +35,6 @@ namespace ContentExtensions {
 CompiledContentExtension::~CompiledContentExtension()
 {
 }
-
-Vector<String> CompiledContentExtension::globalDisplayNoneSelectors()
-{
-    DFABytecodeInterpreter interpreter(filtersWithoutDomainsBytecode(), filtersWithoutDomainsBytecodeLength());
-    DFABytecodeInterpreter::Actions actionLocations = interpreter.actionsForDefaultStylesheetFromDFARoot();
-    
-    Vector<Action> globalActions;
-    for (uint64_t actionLocation : actionLocations)
-        globalActions.append(Action::deserialize(actions(), actionsLength(), static_cast<unsigned>(actionLocation)));
-    
-    Vector<String> selectors;
-    for (Action& action : globalActions) {
-        if (action.type() == ActionType::CSSDisplayNoneSelector)
-            selectors.append(action.stringArgument());
-    }
-    
-    return selectors;
-}
     
 } // namespace ContentExtensions
 } // namespace WebCore
index 5140a50..1c12efd 100644 (file)
@@ -48,7 +48,6 @@ public:
     virtual unsigned domainFiltersBytecodeLength() const = 0;
     virtual const SerializedActionByte* actions() const = 0;
     virtual unsigned actionsLength() const = 0;
-    Vector<String> globalDisplayNoneSelectors();
 };
 
 } // namespace ContentExtensions
index 41bb070..4141576 100644 (file)
@@ -44,38 +44,79 @@ RefPtr<ContentExtension> ContentExtension::create(const String& identifier, Ref<
 ContentExtension::ContentExtension(const String& identifier, Ref<CompiledContentExtension>&& compiledExtension)
     : m_identifier(identifier)
     , m_compiledExtension(WTF::move(compiledExtension))
-    , m_parsedGlobalDisplayNoneStyleSheet(false)
 {
+    DFABytecodeInterpreter withoutDomains(m_compiledExtension->filtersWithoutDomainsBytecode(), m_compiledExtension->filtersWithoutDomainsBytecodeLength());
+    DFABytecodeInterpreter withDomains(m_compiledExtension->filtersWithDomainsBytecode(), m_compiledExtension->filtersWithDomainsBytecodeLength());
+    for (uint64_t action : withoutDomains.actionsMatchingEverything()) {
+        ASSERT(static_cast<uint32_t>(action) == action);
+        m_universalActionsWithoutDomains.append(static_cast<uint32_t>(action));
+    }
+    for (uint64_t action : withDomains.actionsMatchingEverything()) {
+        ASSERT((action & ~IfDomainFlag) == static_cast<uint32_t>(action));
+        m_universalActionsWithDomains.append(action);
+    }
+    
+    compileGlobalDisplayNoneStyleSheet();
+    m_universalActionsWithoutDomains.shrinkToFit();
+    m_universalActionsWithDomains.shrinkToFit();
 }
 
+uint32_t ContentExtension::findFirstIgnorePreviousRules() const
+{
+    auto* actions = m_compiledExtension->actions();
+    uint32_t actionsLength = m_compiledExtension->actionsLength();
+    uint32_t currentActionIndex = 0;
+    while (currentActionIndex < actionsLength) {
+        if (Action::deserializeType(actions, actionsLength, currentActionIndex) == ActionType::IgnorePreviousRules)
+            return currentActionIndex;
+        currentActionIndex += Action::serializedLength(actions, actionsLength, currentActionIndex);
+    }
+    return std::numeric_limits<uint32_t>::max();
+}
+    
 StyleSheetContents* ContentExtension::globalDisplayNoneStyleSheet()
 {
-    if (m_parsedGlobalDisplayNoneStyleSheet)
-        return m_globalDisplayNoneStyleSheet.get();
-
-    m_parsedGlobalDisplayNoneStyleSheet = true;
+    return m_globalDisplayNoneStyleSheet.get();
+}
 
-    Vector<String> selectors = m_compiledExtension->globalDisplayNoneSelectors();
-    if (selectors.isEmpty())
-        return nullptr;
+void ContentExtension::compileGlobalDisplayNoneStyleSheet()
+{
+    uint32_t firstIgnorePreviousRules = findFirstIgnorePreviousRules();
+    
+    auto* actions = m_compiledExtension->actions();
+    uint32_t actionsLength = m_compiledExtension->actionsLength();
 
+    auto inGlobalDisplayNoneStyleSheet = [&](const uint32_t location)
+    {
+        return location < firstIgnorePreviousRules && Action::deserializeType(actions, actionsLength, location) == ActionType::CSSDisplayNoneSelector;
+    };
+    
     StringBuilder css;
-    for (auto& selector : selectors) {
-        css.append(selector);
-        css.append("{");
-        css.append(ContentExtensionsBackend::displayNoneCSSRule());
-        css.append("}");
+    for (uint32_t universalActionLocation : m_universalActionsWithoutDomains) {
+        if (inGlobalDisplayNoneStyleSheet(universalActionLocation)) {
+            if (!css.isEmpty())
+                css.append(',');
+            Action action = Action::deserialize(actions, actionsLength, universalActionLocation);
+            ASSERT(action.type() == ActionType::CSSDisplayNoneSelector);
+            css.append(action.stringArgument());
+        }
     }
+    if (css.isEmpty())
+        return;
+    css.append("{");
+    css.append(ContentExtensionsBackend::displayNoneCSSRule());
+    css.append("}");
 
     m_globalDisplayNoneStyleSheet = StyleSheetContents::create();
     m_globalDisplayNoneStyleSheet->setIsUserStyleSheet(true);
     if (!m_globalDisplayNoneStyleSheet->parseString(css.toString()))
         m_globalDisplayNoneStyleSheet = nullptr;
 
-    return m_globalDisplayNoneStyleSheet.get();
+    // These actions don't need to be applied individually any more. They will all be applied to every page as a precompiled style sheet.
+    m_universalActionsWithoutDomains.removeAllMatching(inGlobalDisplayNoneStyleSheet);
 }
 
-const DFABytecodeInterpreter::Actions& ContentExtension::cachedDomainActions(const String& domain)
+void ContentExtension::populateDomainCacheIfNeeded(const String& domain)
 {
     if (m_cachedDomain != domain) {
         DFABytecodeInterpreter interpreter(m_compiledExtension->domainFiltersBytecode(), m_compiledExtension->domainFiltersBytecodeLength());
@@ -85,10 +126,30 @@ const DFABytecodeInterpreter::Actions& ContentExtension::cachedDomainActions(con
         m_cachedDomainActions.clear();
         for (uint64_t action : domainActions)
             m_cachedDomainActions.add(action);
+        
+        m_cachedUniversalDomainActions.clear();
+        for (uint64_t action : m_universalActionsWithDomains) {
+            ASSERT_WITH_MESSAGE((action & ~IfDomainFlag) == static_cast<uint32_t>(action), "Universal actions with domains should not have flags.");
+            if (!!(action & IfDomainFlag) == m_cachedDomainActions.contains(action))
+                m_cachedUniversalDomainActions.append(static_cast<uint32_t>(action));
+        }
+        m_cachedDomainActions.shrinkToFit();
+        m_cachedUniversalDomainActions.shrinkToFit();
         m_cachedDomain = domain;
     }
+}
+
+const DFABytecodeInterpreter::Actions& ContentExtension::cachedDomainActions(const String& domain)
+{
+    populateDomainCacheIfNeeded(domain);
     return m_cachedDomainActions;
 }
+
+const Vector<uint32_t>& ContentExtension::universalActionsWithDomains(const String& domain)
+{
+    populateDomainCacheIfNeeded(domain);
+    return m_cachedUniversalDomainActions;
+}
     
 } // namespace ContentExtensions
 } // namespace WebCore
index 8492975..0b1a1b7 100644 (file)
@@ -49,17 +49,26 @@ public:
     const CompiledContentExtension& compiledExtension() const { return m_compiledExtension.get(); }
     StyleSheetContents* globalDisplayNoneStyleSheet();
     const DFABytecodeInterpreter::Actions& cachedDomainActions(const String& domain);
+    const Vector<uint32_t>& universalActionsWithoutDomains() { return m_universalActionsWithoutDomains; }
+    const Vector<uint32_t>& universalActionsWithDomains(const String& domain);
 
 private:
     ContentExtension(const String& identifier, Ref<CompiledContentExtension>&&);
-
+    uint32_t findFirstIgnorePreviousRules() const;
+    
     String m_identifier;
     Ref<CompiledContentExtension> m_compiledExtension;
+
     RefPtr<StyleSheetContents> m_globalDisplayNoneStyleSheet;
-    bool m_parsedGlobalDisplayNoneStyleSheet;
-    
+    void compileGlobalDisplayNoneStyleSheet();
+
     String m_cachedDomain;
+    void populateDomainCacheIfNeeded(const String& domain);
     DFABytecodeInterpreter::Actions m_cachedDomainActions;
+    Vector<uint32_t> m_cachedUniversalDomainActions;
+
+    Vector<uint32_t> m_universalActionsWithoutDomains;
+    Vector<uint64_t> m_universalActionsWithDomains;
 };
 
 } // namespace ContentExtensions
index 75564ac..34cd664 100644 (file)
@@ -251,11 +251,9 @@ std::error_code compileRuleList(ContentExtensionCompilationClient& client, Strin
     URLFilterParser filtersWithoutDomainParser(filtersWithoutDomains);
     URLFilterParser filtersWithDomainParser(filtersWithDomains);
     
-    bool ignorePreviousRulesSeen = false;
     for (unsigned ruleIndex = 0; ruleIndex < parsedRuleList.size(); ++ruleIndex) {
         const ContentExtensionRule& contentExtensionRule = parsedRuleList[ruleIndex];
         const Trigger& trigger = contentExtensionRule.trigger();
-        const Action& action = contentExtensionRule.action();
         ASSERT(trigger.urlFilter.length());
 
         // High bits are used for flags. This should match how they are used in DFABytecodeCompiler::compileNode.
@@ -267,11 +265,6 @@ std::error_code compileRuleList(ContentExtensionCompilationClient& client, Strin
             ASSERT(trigger.domainCondition == Trigger::DomainCondition::None);
             status = filtersWithoutDomainParser.addPattern(trigger.urlFilter, trigger.urlFilterIsCaseSensitive, actionLocationAndFlags);
             if (status == URLFilterParser::MatchesEverything) {
-                if (!ignorePreviousRulesSeen
-                    && trigger.domainCondition == Trigger::DomainCondition::None
-                    && action.type() == ActionType::CSSDisplayNoneSelector
-                    && !trigger.flags)
-                    actionLocationAndFlags |= DisplayNoneStyleSheetFlag;
                 universalActionsWithoutDomains.add(actionLocationAndFlags);
                 status = URLFilterParser::Ok;
             }
@@ -300,9 +293,6 @@ std::error_code compileRuleList(ContentExtensionCompilationClient& client, Strin
                 domainFilters.addDomain(actionLocationAndFlags, domain);
         }
         ASSERT(status == URLFilterParser::Ok);
-        
-        if (action.type() == ActionType::IgnorePreviousRules)
-            ignorePreviousRulesSeen = true;
     }
     LOG_LARGE_STRUCTURES(parsedRuleList, parsedRuleList.capacity() * sizeof(ContentExtensionRule)); // Doesn't include strings.
     LOG_LARGE_STRUCTURES(actionLocations, actionLocations.capacity() * sizeof(unsigned));
index 10690d7..1793343 100644 (file)
@@ -39,8 +39,9 @@ ContentExtensionRule::ContentExtensionRule(const Trigger& trigger, const Action&
     ASSERT(!m_trigger.urlFilter.isEmpty());
 }
 
-Action Action::deserialize(const SerializedActionByte* actions, const unsigned actionsLength, unsigned location)
+Action Action::deserialize(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location)
 {
+    RELEASE_ASSERT(location < actionsLength);
     switch (static_cast<ActionType>(actions[location])) {
     case ActionType::BlockCookies:
         return Action(ActionType::BlockCookies, location);
@@ -49,10 +50,11 @@ Action Action::deserialize(const SerializedActionByte* actions, const unsigned a
     case ActionType::IgnorePreviousRules:
         return Action(ActionType::IgnorePreviousRules, location);
     case ActionType::CSSDisplayNoneSelector: {
-        unsigned stringStartIndex = location + sizeof(ActionType) + sizeof(unsigned) + sizeof(bool);
+        uint32_t headerLength = sizeof(ActionType) + sizeof(uint32_t) + sizeof(bool);
+        uint32_t stringStartIndex = location + headerLength;
         RELEASE_ASSERT(actionsLength >= stringStartIndex);
-        unsigned selectorLength = *reinterpret_cast<const unsigned*>(&actions[location + sizeof(ActionType)]);
-        bool wideCharacters = actions[location + sizeof(ActionType) + sizeof(unsigned)];
+        uint32_t selectorLength = *reinterpret_cast<const unsigned*>(&actions[location + sizeof(ActionType)]);
+        bool wideCharacters = actions[location + sizeof(ActionType) + sizeof(uint32_t)];
         
         if (wideCharacters) {
             RELEASE_ASSERT(actionsLength >= stringStartIndex + selectorLength * sizeof(UChar));
@@ -63,12 +65,56 @@ Action Action::deserialize(const SerializedActionByte* actions, const unsigned a
     }
     case ActionType::CSSDisplayNoneStyleSheet:
     case ActionType::InvalidAction:
+    default:
         RELEASE_ASSERT_NOT_REACHED();
     }
 }
-
+    
+ActionType Action::deserializeType(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location)
+{
+    RELEASE_ASSERT(location < actionsLength);
+    ActionType type = static_cast<ActionType>(actions[location]);
+    switch (type) {
+    case ActionType::BlockCookies:
+    case ActionType::BlockLoad:
+    case ActionType::IgnorePreviousRules:
+    case ActionType::CSSDisplayNoneSelector:
+        return type;
+    case ActionType::CSSDisplayNoneStyleSheet:
+    case ActionType::InvalidAction:
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+    
+uint32_t Action::serializedLength(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location)
+{
+    RELEASE_ASSERT(location < actionsLength);
+    switch (static_cast<ActionType>(actions[location])) {
+    case ActionType::BlockCookies:
+    case ActionType::BlockLoad:
+    case ActionType::IgnorePreviousRules:
+        return sizeof(ActionType);
+    case ActionType::CSSDisplayNoneSelector: {
+        uint32_t headerLength = sizeof(ActionType) + sizeof(uint32_t) + sizeof(bool);
+        uint32_t stringStartIndex = location + headerLength;
+        RELEASE_ASSERT(actionsLength >= stringStartIndex);
+        uint32_t selectorLength = *reinterpret_cast<const unsigned*>(&actions[location + sizeof(ActionType)]);
+        bool wideCharacters = actions[location + sizeof(ActionType) + sizeof(uint32_t)];
+        
+        if (wideCharacters)
+            return headerLength + selectorLength * sizeof(UChar);
+        return headerLength + selectorLength * sizeof(LChar);
+    }
+    case ActionType::CSSDisplayNoneStyleSheet:
+    case ActionType::InvalidAction:
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 }
 
+} // namespace ContentExtensions
+
 } // namespace WebCore
 
 #endif // ENABLE(CONTENT_EXTENSIONS)
index 26ab8b4..5588d86 100644 (file)
@@ -157,7 +157,9 @@ struct Action {
             && m_stringArgument == other.m_stringArgument;
     }
 
-    static Action deserialize(const SerializedActionByte* actions, const unsigned actionsLength, uint32_t location);
+    static Action deserialize(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
+    static ActionType deserializeType(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
+    static uint32_t serializedLength(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
 
     void setExtensionIdentifier(const String& extensionIdentifier) { m_extensionIdentifier = extensionIdentifier; }
     const String& extensionIdentifier() const { return m_extensionIdentifier; }
index 1c3894c..bbe0872 100644 (file)
@@ -92,20 +92,27 @@ Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLo
         DFABytecodeInterpreter withoutDomainsInterpreter(compiledExtension.filtersWithoutDomainsBytecode(), compiledExtension.filtersWithoutDomainsBytecodeLength());
         DFABytecodeInterpreter::Actions withoutDomainsActions = withoutDomainsInterpreter.interpret(urlCString, flags);
         
+        String domain = resourceLoadInfo.mainDocumentURL.host();
         DFABytecodeInterpreter withDomainsInterpreter(compiledExtension.filtersWithDomainsBytecode(), compiledExtension.filtersWithDomainsBytecodeLength());
-        DFABytecodeInterpreter::Actions withDomainsActions = withDomainsInterpreter.interpretWithDomains(urlCString, flags, contentExtension->cachedDomainActions(resourceLoadInfo.mainDocumentURL.host()));
+        DFABytecodeInterpreter::Actions withDomainsActions = withDomainsInterpreter.interpretWithDomains(urlCString, flags, contentExtension->cachedDomainActions(domain));
         
         const SerializedActionByte* actions = compiledExtension.actions();
         const unsigned actionsLength = compiledExtension.actionsLength();
         
         bool sawIgnorePreviousRules = false;
-        if (!withoutDomainsActions.isEmpty() || !withDomainsActions.isEmpty()) {
+        const Vector<uint32_t>& universalWithDomains = contentExtension->universalActionsWithDomains(domain);
+        const Vector<uint32_t>& universalWithoutDomains = contentExtension->universalActionsWithoutDomains();
+        if (!withoutDomainsActions.isEmpty() || !withDomainsActions.isEmpty() || !universalWithDomains.isEmpty() || !universalWithoutDomains.isEmpty()) {
             Vector<uint32_t> actionLocations;
-            actionLocations.reserveInitialCapacity(withoutDomainsActions.size() + withDomainsActions.size());
+            actionLocations.reserveInitialCapacity(withoutDomainsActions.size() + withDomainsActions.size() + universalWithoutDomains.size() + universalWithDomains.size());
             for (uint64_t actionLocation : withoutDomainsActions)
                 actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
             for (uint64_t actionLocation : withDomainsActions)
                 actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
+            for (uint32_t actionLocation : universalWithoutDomains)
+                actionLocations.uncheckedAppend(actionLocation);
+            for (uint32_t actionLocation : universalWithDomains)
+                actionLocations.uncheckedAppend(actionLocation);
             std::sort(actionLocations.begin(), actionLocations.end());
 
             // Add actions in reverse order to properly deal with IgnorePreviousRules.
@@ -126,7 +133,7 @@ Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLo
     }
 #if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
     double addedTimeEnd = monotonicallyIncreasingTime();
-    WTFLogAlways("Time added: %f microseconds %s", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
+    dataLogF("Time added: %f microseconds %s \n", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
 #endif
     return finalActions;
 }
index a44e93d..da12cce 100644 (file)
@@ -55,21 +55,20 @@ enum class DFABytecodeInstruction : uint8_t {
     // AppendAction has one argument:
     // The action to append (4 bytes).
     AppendAction = 0x4,
-    AppendActionDefaultStylesheet = 0x5,
-    AppendActionWithIfDomain = 0x6,
+    AppendActionWithIfDomain = 0x5,
     
     // TestFlagsAndAppendAction has two arguments:
     // The flags to check before appending (2 bytes).
     // The action to append (4 bytes).
-    TestFlagsAndAppendAction = 0x7,
-    TestFlagsAndAppendActionWithIfDomain = 0x8,
+    TestFlagsAndAppendAction = 0x6,
+    TestFlagsAndAppendActionWithIfDomain = 0x7,
 
     // Terminate has no arguments.
-    Terminate = 0x9,
+    Terminate = 0x8,
 
     // Jump has one argument:
     // The distance to jump (1-4 bytes, signed).
-    Jump = 0xA,
+    Jump = 0x9,
 };
 
 // The last four bits contain the instruction type.
@@ -110,7 +109,6 @@ static inline size_t instructionSizeWithArguments(DFABytecodeInstruction instruc
     case DFABytecodeInstruction::Jump:
         RELEASE_ASSERT_NOT_REACHED(); // Variable instruction size.
     case DFABytecodeInstruction::AppendAction:
-    case DFABytecodeInstruction::AppendActionDefaultStylesheet:
     case DFABytecodeInstruction::AppendActionWithIfDomain:
         return sizeof(DFABytecodeInstruction) + sizeof(uint32_t);
     case DFABytecodeInstruction::TestFlagsAndAppendAction:
index 784b4e3..b74cd52 100644 (file)
@@ -81,7 +81,6 @@ void DFABytecodeCompiler::emitAppendAction(uint64_t action)
 {
     // High bits are used to store flags. See compileRuleList.
     if (action & ActionFlagMask) {
-        ASSERT(!(action & DisplayNoneStyleSheetFlag));
         if (action & IfDomainFlag)
             append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain);
         else
@@ -89,10 +88,7 @@ void DFABytecodeCompiler::emitAppendAction(uint64_t action)
         append<uint16_t>(m_bytecode, static_cast<uint16_t>(action >> 32));
         append<uint32_t>(m_bytecode, static_cast<uint32_t>(action));
     } else {
-        if (action & DisplayNoneStyleSheetFlag) {
-            RELEASE_ASSERT(!(action & IfDomainFlag));
-            append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::AppendActionDefaultStylesheet);
-        } else if (action & IfDomainFlag)
+        if (action & IfDomainFlag)
             append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::AppendActionWithIfDomain);
         else
             append<DFABytecodeInstruction>(m_bytecode, DFABytecodeInstruction::AppendAction);
index a9a004b..5677bd3 100644 (file)
@@ -96,15 +96,13 @@ static inline bool matchesDomain(uint64_t actionAndFlags, const DFABytecodeInter
 void DFABytecodeInterpreter::interpretAppendAction(uint32_t& programCounter, Actions& actions, bool ifDomain)
 {
     ASSERT(getInstruction(m_bytecode, m_bytecodeLength, programCounter) == DFABytecodeInstruction::AppendAction
-        || getInstruction(m_bytecode, m_bytecodeLength, programCounter) == DFABytecodeInstruction::AppendActionWithIfDomain
-        || getInstruction(m_bytecode, m_bytecodeLength, programCounter) == DFABytecodeInstruction::AppendActionDefaultStylesheet);
+        || getInstruction(m_bytecode, m_bytecodeLength, programCounter) == DFABytecodeInstruction::AppendActionWithIfDomain);
     uint64_t action = (ifDomain ? IfDomainFlag : 0) | static_cast<uint64_t>(getBits<uint32_t>(m_bytecode, m_bytecodeLength, programCounter + sizeof(DFABytecodeInstruction)));
     if (!m_domainActions || matchesDomain(action, *m_domainActions))
         actions.add(action);
     
     programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
     ASSERT(instructionSizeWithArguments(DFABytecodeInstruction::AppendAction) == instructionSizeWithArguments(DFABytecodeInstruction::AppendActionWithIfDomain));
-    ASSERT(instructionSizeWithArguments(DFABytecodeInstruction::AppendAction) == instructionSizeWithArguments(DFABytecodeInstruction::AppendActionDefaultStylesheet));
 }
 
 void DFABytecodeInterpreter::interpretTestFlagsAndAppendAction(uint32_t& programCounter, uint16_t flags, Actions& actions, bool ifDomain)
@@ -128,7 +126,7 @@ void DFABytecodeInterpreter::interpretTestFlagsAndAppendAction(uint32_t& program
     ASSERT(instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendAction) == instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain));
 }
 
-DFABytecodeInterpreter::Actions DFABytecodeInterpreter::actionsForDefaultStylesheetFromDFARoot()
+DFABytecodeInterpreter::Actions DFABytecodeInterpreter::actionsMatchingEverything()
 {
     Actions actions;
 
@@ -138,19 +136,16 @@ DFABytecodeInterpreter::Actions DFABytecodeInterpreter::actionsForDefaultStylesh
 
     while (programCounter < dfaBytecodeLength) {
         DFABytecodeInstruction instruction = getInstruction(m_bytecode, m_bytecodeLength, programCounter);
-        if (instruction == DFABytecodeInstruction::AppendActionDefaultStylesheet)
+        if (instruction == DFABytecodeInstruction::AppendAction)
             interpretAppendAction(programCounter, actions, false);
-        else if (instruction == DFABytecodeInstruction::AppendAction)
-            programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
+        else if (instruction == DFABytecodeInstruction::AppendActionWithIfDomain)
+            interpretAppendAction(programCounter, actions, true);
         else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendAction)
             programCounter += instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendAction);
-        else {
-            // actionsForDefaultStylesheetFromDFARoot should only be called on the DFA without domains,
-            // which should never have any actions with if-domain.
-            ASSERT(instruction != DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain);
-            ASSERT(instruction != DFABytecodeInstruction::AppendActionWithIfDomain);
+        else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain)
+            programCounter += instructionSizeWithArguments(DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain);
+        else
             break;
-        }
     }
     return actions;
 }
@@ -179,16 +174,18 @@ DFABytecodeInterpreter::Actions DFABytecodeInterpreter::interpret(const CString&
         uint32_t dfaBytecodeLength = getBits<uint32_t>(m_bytecode, m_bytecodeLength, programCounter);
         programCounter += sizeof(uint32_t);
 
-        // Skip the default stylesheet actions on the DFA root. These are accessed via actionsForDefaultStylesheetFromDFARoot.
+        // Skip the actions without flags on the DFA root. These are accessed via actionsMatchingEverything.
         if (!dfaStart) {
             while (programCounter < dfaBytecodeLength) {
                 DFABytecodeInstruction instruction = getInstruction(m_bytecode, m_bytecodeLength, programCounter);
-                if (instruction == DFABytecodeInstruction::AppendActionDefaultStylesheet)
-                    programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendActionDefaultStylesheet);
-                else if (instruction == DFABytecodeInstruction::AppendAction)
-                    interpretAppendAction(programCounter, actions, false);
+                if (instruction == DFABytecodeInstruction::AppendAction)
+                    programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendAction);
+                else if (instruction == DFABytecodeInstruction::AppendActionWithIfDomain)
+                    programCounter += instructionSizeWithArguments(DFABytecodeInstruction::AppendActionWithIfDomain);
                 else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendAction)
                     interpretTestFlagsAndAppendAction(programCounter, flags, actions, false);
+                else if (instruction == DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain)
+                    interpretTestFlagsAndAppendAction(programCounter, flags, actions, true);
                 else
                     break;
             }
@@ -196,7 +193,9 @@ DFABytecodeInterpreter::Actions DFABytecodeInterpreter::interpret(const CString&
                 return actions;
         } else {
             ASSERT_WITH_MESSAGE(getInstruction(m_bytecode, m_bytecodeLength, programCounter) != DFABytecodeInstruction::AppendAction
-                && getInstruction(m_bytecode, m_bytecodeLength, programCounter) != DFABytecodeInstruction::TestFlagsAndAppendAction,
+                && getInstruction(m_bytecode, m_bytecodeLength, programCounter) != DFABytecodeInstruction::AppendActionWithIfDomain
+                && getInstruction(m_bytecode, m_bytecodeLength, programCounter) != DFABytecodeInstruction::TestFlagsAndAppendAction
+                && getInstruction(m_bytecode, m_bytecodeLength, programCounter) != DFABytecodeInstruction::TestFlagsAndAppendActionWithIfDomain,
                 "Triggers that match everything should only be in the first DFA.");
         }
         
index 889be59..2a25f9f 100644 (file)
@@ -51,7 +51,7 @@ public:
     
     Actions interpret(const CString&, uint16_t flags);
     Actions interpretWithDomains(const CString&, uint16_t flags, const DFABytecodeInterpreter::Actions& domainActions);
-    Actions actionsForDefaultStylesheetFromDFARoot();
+    Actions actionsMatchingEverything();
 
 private:
     void interpretAppendAction(unsigned& programCounter, Actions&, bool ifDomain);
index 9d19444..291a4dd 100644 (file)
@@ -62,7 +62,6 @@ typedef uint16_t ResourceFlags;
 // The values -1 and -2 are used for removed and empty values in HashTables.
 const uint64_t ActionFlagMask = 0x0000FFFF00000000;
 const uint64_t IfDomainFlag = 0x0001000000000000;
-const uint64_t DisplayNoneStyleSheetFlag = 0x0002000000000000;
 
 ResourceType toResourceType(CachedResource::Type);
 uint16_t readResourceType(const String&);
index 401891f..f338fc2 100644 (file)
@@ -1,3 +1,12 @@
+2015-07-20  Alex Christensen  <achristensen@webkit.org>
+
+        [Content Extensions] Cache actions with domains that match everything
+        https://bugs.webkit.org/show_bug.cgi?id=147050
+
+        Reviewed by Benjamin Poulain.
+
+        * UIProcess/API/APIUserContentExtensionStore.h:
+
 2015-07-20  Gordon Sheridan  <gordon_sheridan@apple.com>
 
         Support blocking a plug-in for non-security reasons
index bad0e71..ab8063f 100644 (file)
@@ -51,7 +51,7 @@ public:
     
     // This should be incremented every time a functional change is made to the bytecode, file format, etc.
     // to prevent crashing while loading old data.
-    const static uint32_t CurrentContentExtensionFileVersion = 5;
+    const static uint32_t CurrentContentExtensionFileVersion = 6;
 
     static UserContentExtensionStore& defaultStore();
     static Ref<UserContentExtensionStore> storeWithPath(const WTF::String& storePath);