Explorar o código

LibWeb: Stop allocating `Token`s and `ComponentValue`s unnecessarily

When the "Consume a component value from input, and do nothing."
step in `Parser::consume_the_remnants_of_a_bad_declaration` was
executed, it would allocate a `ComponentValue` that was then
immediately discarded.

Add explicitly `{}_and_do_nothing` functions for this case that never
allocate a `ComponentValue` in the first place.

Also remove a `(Token)` cast, which was unnecessarily copying a `Token`
as well.
Jonne Ransijn hai 8 meses
pai
achega
3f5e32ee84
Modificáronse 2 ficheiros con 132 adicións e 7 borrados
  1. 126 7
      Libraries/LibWeb/CSS/Parser/Parser.cpp
  2. 6 0
      Libraries/LibWeb/CSS/Parser/Parser.h

+ 126 - 7
Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -704,7 +704,7 @@ ComponentValue Parser::consume_a_component_value(TokenStream<T>& input)
 
     // Process input:
     for (;;) {
-        auto& token = input.next_token();
+        auto const& token = input.next_token();
 
         // <{-token>
         // <[-token>
@@ -728,6 +728,52 @@ ComponentValue Parser::consume_a_component_value(TokenStream<T>& input)
     }
 }
 
+template<>
+void Parser::consume_a_component_value_and_do_nothing<ComponentValue>(TokenStream<ComponentValue>& tokens)
+{
+    // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately.
+    // Note: This overload is called once tokens have already been converted into component values,
+    //       so we do not need to do the work in the more general overload.
+    (void)tokens.consume_a_token();
+}
+
+// 5.4.7. Consume a component value
+// https://drafts.csswg.org/css-syntax/#consume-component-value
+template<typename T>
+void Parser::consume_a_component_value_and_do_nothing(TokenStream<T>& input)
+{
+    // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately.
+    // To consume a component value from a token stream input:
+
+    // Process input:
+    for (;;) {
+        auto const& token = input.next_token();
+
+        // <{-token>
+        // <[-token>
+        // <(-token>
+        if (token.is(Token::Type::OpenCurly) || token.is(Token::Type::OpenSquare) || token.is(Token::Type::OpenParen)) {
+            // Consume a simple block from input and return the result.
+            consume_a_simple_block_and_do_nothing(input);
+            return;
+        }
+
+        // <function-token>
+        if (token.is(Token::Type::Function)) {
+            // Consume a function from input and return the result.
+            consume_a_function_and_do_nothing(input);
+            return;
+        }
+
+        // anything else
+        {
+            // Consume a token from input and return the result.
+            input.discard_a_token();
+            return;
+        }
+    }
+}
+
 template<typename T>
 Vector<ComponentValue> Parser::consume_a_list_of_component_values(TokenStream<T>& input, Optional<Token::Type> stop_token, Nested nested)
 {
@@ -778,11 +824,11 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream<T>& input)
     // To consume a simple block from a token stream input:
 
     // Assert: the next token of input is <{-token>, <[-token>, or <(-token>.
-    auto& next = input.next_token();
+    auto const& next = input.next_token();
     VERIFY(next.is(Token::Type::OpenCurly) || next.is(Token::Type::OpenSquare) || next.is(Token::Type::OpenParen));
 
     // Let ending token be the mirror variant of the next token. (E.g. if it was called with <[-token>, the ending token is <]-token>.)
-    auto ending_token = ((Token)input.next_token()).mirror_variant();
+    auto ending_token = input.next_token().mirror_variant();
 
     // Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list.
     SimpleBlock block {
@@ -795,7 +841,7 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream<T>& input)
 
     // Process input:
     for (;;) {
-        auto& token = input.next_token();
+        auto const& token = input.next_token();
 
         // <eof-token>
         // ending token
@@ -814,6 +860,45 @@ SimpleBlock Parser::consume_a_simple_block(TokenStream<T>& input)
     }
 }
 
+// https://drafts.csswg.org/css-syntax/#consume-simple-block
+template<typename T>
+void Parser::consume_a_simple_block_and_do_nothing(TokenStream<T>& input)
+{
+    // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately.
+    // To consume a simple block from a token stream input:
+
+    // Assert: the next token of input is <{-token>, <[-token>, or <(-token>.
+    auto const& next = input.next_token();
+    VERIFY(next.is(Token::Type::OpenCurly) || next.is(Token::Type::OpenSquare) || next.is(Token::Type::OpenParen));
+
+    // Let ending token be the mirror variant of the next token. (E.g. if it was called with <[-token>, the ending token is <]-token>.)
+    auto ending_token = input.next_token().mirror_variant();
+
+    // Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list.
+
+    // Discard a token from input.
+    input.discard_a_token();
+
+    // Process input:
+    for (;;) {
+        auto const& token = input.next_token();
+
+        // <eof-token>
+        // ending token
+        if (token.is(Token::Type::EndOfFile) || token.is(ending_token)) {
+            // Discard a token from input. Return block.
+            input.discard_a_token();
+            return;
+        }
+
+        // anything else
+        {
+            // Consume a component value from input and append the result to block’s value.
+            consume_a_component_value_and_do_nothing(input);
+        }
+    }
+}
+
 // https://drafts.csswg.org/css-syntax/#consume-function
 template<typename T>
 Function Parser::consume_a_function(TokenStream<T>& input)
@@ -834,7 +919,7 @@ Function Parser::consume_a_function(TokenStream<T>& input)
 
     // Process input:
     for (;;) {
-        auto& token = input.next_token();
+        auto const& token = input.next_token();
 
         // <eof-token>
         // <)-token>
@@ -853,6 +938,40 @@ Function Parser::consume_a_function(TokenStream<T>& input)
     }
 }
 
+// https://drafts.csswg.org/css-syntax/#consume-function
+template<typename T>
+void Parser::consume_a_function_and_do_nothing(TokenStream<T>& input)
+{
+    // AD-HOC: To avoid unnecessairy allocations, we explicitly define a "do nothing" variant that discards the result immediately.
+    // To consume a function from a token stream input:
+
+    // Assert: The next token is a <function-token>.
+    VERIFY(input.next_token().is(Token::Type::Function));
+
+    // Consume a token from input, and let function be a new function with its name equal the returned token’s value,
+    // and a value set to an empty list.
+    input.discard_a_token();
+
+    // Process input:
+    for (;;) {
+        auto const& token = input.next_token();
+
+        // <eof-token>
+        // <)-token>
+        if (token.is(Token::Type::EndOfFile) || token.is(Token::Type::CloseParen)) {
+            // Discard a token from input. Return function.
+            input.discard_a_token();
+            return;
+        }
+
+        // anything else
+        {
+            // Consume a component value from input and append the result to function’s value.
+            consume_a_component_value_and_do_nothing(input);
+        }
+    }
+}
+
 // https://drafts.csswg.org/css-syntax/#consume-declaration
 template<typename T>
 Optional<Declaration> Parser::consume_a_declaration(TokenStream<T>& input, Nested nested)
@@ -1001,7 +1120,7 @@ void Parser::consume_the_remnants_of_a_bad_declaration(TokenStream<T>& input, Ne
 
     // Process input:
     for (;;) {
-        auto& token = input.next_token();
+        auto const& token = input.next_token();
 
         // <eof-token>
         // <semicolon-token>
@@ -1023,7 +1142,7 @@ void Parser::consume_the_remnants_of_a_bad_declaration(TokenStream<T>& input, Ne
         // anything else
         {
             // Consume a component value from input, and do nothing.
-            (void)consume_a_component_value(input);
+            consume_a_component_value_and_do_nothing(input);
             continue;
         }
     }

+ 6 - 0
Libraries/LibWeb/CSS/Parser/Parser.h

@@ -161,9 +161,15 @@ private:
     template<typename T>
     [[nodiscard]] ComponentValue consume_a_component_value(TokenStream<T>&);
     template<typename T>
+    void consume_a_component_value_and_do_nothing(TokenStream<T>&);
+    template<typename T>
     SimpleBlock consume_a_simple_block(TokenStream<T>&);
     template<typename T>
+    void consume_a_simple_block_and_do_nothing(TokenStream<T>&);
+    template<typename T>
     Function consume_a_function(TokenStream<T>&);
+    template<typename T>
+    void consume_a_function_and_do_nothing(TokenStream<T>&);
     // TODO: consume_a_unicode_range_value()
 
     Optional<GeneralEnclosed> parse_general_enclosed(TokenStream<ComponentValue>&);