| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|  | 3  * Copyright (C) 2006-present eyeo GmbH | 
|  | 4  * | 
|  | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|  | 6  * it under the terms of the GNU General Public License version 3 as | 
|  | 7  * published by the Free Software Foundation. | 
|  | 8  * | 
|  | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
|  | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 12  * GNU General Public License for more details. | 
|  | 13  * | 
|  | 14  * You should have received a copy of the GNU General Public License | 
|  | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|  | 16  */ | 
|  | 17 | 
|  | 18 "use strict"; | 
|  | 19 | 
|  | 20 /** | 
|  | 21  * @fileOverview Filter text operations. | 
|  | 22  */ | 
|  | 23 | 
|  | 24 // The memory optimizations in this file work as of V8 7.1.314. | 
|  | 25 | 
|  | 26 /** | 
|  | 27  * The minimum length of a domain string for it to be considered long enough to | 
|  | 28  * be eligible for optimization. | 
|  | 29  * @type {number} | 
|  | 30  */ | 
|  | 31 const LONG_DOMAINS_THRESHOLD = 1000; | 
|  | 32 | 
|  | 33 /** | 
|  | 34  * Cached strings. | 
|  | 35  * @type {Map.<string,string>} | 
|  | 36  */ | 
|  | 37 let strings = new Map(); | 
|  | 38 | 
|  | 39 /** | 
|  | 40  * Slices a string out of its internal parent string, thus allowing the memory | 
|  | 41  * occupied by the parent string to be freed up. | 
|  | 42  * | 
|  | 43  * JavaScript engines like V8 tend to hold on to the parent of a sliced string | 
|  | 44  * even if there are no references to the parent string. While this | 
|  | 45  * optimization is enormously beneficial in general, in certain cases it has | 
|  | 46  * the opposite effect of needlessly holding on to large amounts of unused | 
|  | 47  * memory (V8 issue #2869). This operation creates an entirely new internal | 
|  | 48  * string with its own copy of the original string's memory, thus allowing the | 
|  | 49  * original string and any of its parents to be freed up. | 
|  | 50  * | 
|  | 51  * Note: This is a relatively expensive operation and should be used only when | 
|  | 52  * the benefit outweighs the cost. | 
|  | 53  * | 
|  | 54  * @param {string} string The string to slice. | 
|  | 55  * | 
|  | 56  * @returns {string} An entirely new copy of the original string. | 
|  | 57  */ | 
|  | 58 function trueSlice(string) | 
|  | 59 { | 
|  | 60   return JSON.parse(JSON.stringify(string)); | 
|  | 61 } | 
|  | 62 | 
|  | 63 /** | 
|  | 64  * Optimizes content filter text. | 
|  | 65  * | 
|  | 66  * @param {string} text The filter text. | 
|  | 67  * @param {string} domains The domains part of the filter text. | 
|  | 68  * @param {?string} [type] The type part of the filter text, either | 
|  | 69  *   <code>null</code> or <code>undefined</code>, or one of <code>@</code>, | 
|  | 70  *   <code>?</code>, and <code>$</code>. | 
|  | 71  * @param {string} body The body part of the filter text. | 
|  | 72  * | 
|  | 73  * @returns {Array.<string>} An array containing the optimized filter text and | 
|  | 74  *   its optimized parts. | 
|  | 75  */ | 
|  | 76 function optimizeContentFilterText(text, domains, type, body) | 
|  | 77 { | 
|  | 78   // In EasyList+AA there are a handful of filters with very long domain | 
|  | 79   // strings of 1,000 characters and even up to 100,000 characters. These tend | 
|  | 80   // to take up a lot of memory. We can restructure the text here to optimize | 
|  | 81   // for better memory usage on V8. | 
|  | 82   if (domains && domains.length >= LONG_DOMAINS_THRESHOLD) | 
|  | 83   { | 
|  | 84     let copy = strings.get(domains); | 
|  | 85     if (copy) | 
|  | 86     { | 
|  | 87       // Point to the cached copy. | 
|  | 88       domains = copy; | 
|  | 89 | 
|  | 90       // V8 tends to hold on to the parent of a sliced string even if there are | 
|  | 91       // no references to it. We must "slice" out these strings properly so the | 
|  | 92       // original filter text is freed up. | 
|  | 93       // https://bugs.chromium.org/p/v8/issues/detail?id=2869 | 
|  | 94       if (typeof type == "string") | 
|  | 95         type = trueSlice(type); | 
|  | 96       body = trueSlice(body); | 
|  | 97 | 
|  | 98       // Reconstruct the text with an optimized layout. | 
|  | 99       text = domains + "#" + (type || "") + "#" + body; | 
|  | 100     } | 
|  | 101     else | 
|  | 102     { | 
|  | 103       strings.set(domains, domains); | 
|  | 104     } | 
|  | 105   } | 
|  | 106 | 
|  | 107   return [text, domains, type, body]; | 
|  | 108 } | 
|  | 109 | 
|  | 110 exports.optimizeContentFilterText = optimizeContentFilterText; | 
|  | 111 | 
|  | 112 /** | 
|  | 113  * Optimizes blocking and whitelist filter text. | 
|  | 114  * | 
|  | 115  * @param {string} text The filter text. | 
|  | 116  * @param {string} pattern The pattern part of the filter text. | 
|  | 117  * @param {?string} [domains] The domains part of the filter text. | 
|  | 118  * @param {?string} [sitekeys] The sitekeys part of the filter text. | 
|  | 119  * @param {?string} [csp] The CSP part of the filter text. | 
|  | 120  * @param {?string} [rewrite] The rewrite pattern part of the filter text. | 
|  | 121  * | 
|  | 122  * @returns {Array.<string>} An array containing the optimized filter text and | 
|  | 123  *   its optimized parts. | 
|  | 124  */ | 
|  | 125 function optimizeRegExpFilterText(text, pattern, domains, sitekeys, csp, | 
|  | 126                                   rewrite) | 
|  | 127 { | 
|  | 128   if (!sitekeys && !csp && !rewrite && | 
|  | 129       domains && domains.length >= LONG_DOMAINS_THRESHOLD && | 
|  | 130       text.endsWith(domains)) | 
|  | 131   { | 
|  | 132     let copy = strings.get(domains); | 
|  | 133     if (copy) | 
|  | 134     { | 
|  | 135       domains = copy; | 
|  | 136 | 
|  | 137       text = trueSlice(text.substring(0, text.length - domains.length)); | 
|  | 138 | 
|  | 139       if (text[0] == "@" && text[1] == "@") | 
|  | 140         pattern = text.substring(2, 2 + pattern.length); | 
|  | 141       else | 
|  | 142         pattern = text.substring(0, pattern.length); | 
|  | 143 | 
|  | 144       // Note: This must be the last operation on the text in order for this | 
|  | 145       // optimization to work. Any further operations on the text may undo the | 
|  | 146       // optimization. | 
|  | 147       text += domains; | 
|  | 148     } | 
|  | 149     else | 
|  | 150     { | 
|  | 151       strings.set(domains, domains); | 
|  | 152     } | 
|  | 153   } | 
|  | 154 | 
|  | 155   return [text, pattern, domains, sitekeys, csp, rewrite]; | 
|  | 156 } | 
|  | 157 | 
|  | 158 exports.optimizeRegExpFilterText = optimizeRegExpFilterText; | 
| OLD | NEW | 
|---|