Chromium Code Reviews

Side by Side Diff: src/regexp-delay.js

Issue 652224: Proof-of-concept RegExp-cache for exec, test, replace. (Closed)
Patch Set: Cache regexp operations. Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « src/ia32/codegen-ia32.cc ('k') | src/string.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 122 matching lines...)
133 DoConstructRegExp(this, pattern, flags, false); 133 DoConstructRegExp(this, pattern, flags, false);
134 } 134 }
135 } 135 }
136 136
137 137
138 function DoRegExpExec(regexp, string, index) { 138 function DoRegExpExec(regexp, string, index) {
139 return %_RegExpExec(regexp, string, index, lastMatchInfo); 139 return %_RegExpExec(regexp, string, index, lastMatchInfo);
140 } 140 }
141 141
142 142
143 var regExpExecCacheResult;
144 var regExpExecCacheInput;
145 var regExpExecCacheId;
146 var regExpExecCacheIndex;
147
143 function RegExpExec(string) { 148 function RegExpExec(string) {
144 if (!IS_REGEXP(this)) { 149 if (!IS_REGEXP(this)) {
145 throw MakeTypeError('method_called_on_incompatible', 150 throw MakeTypeError('method_called_on_incompatible',
146 ['RegExp.prototype.exec', this]); 151 ['RegExp.prototype.exec', this]);
147 } 152 }
148 if (%_ArgumentsLength() == 0) { 153 if (%_ArgumentsLength() == 0) {
149 var regExpInput = LAST_INPUT(lastMatchInfo); 154 string = LAST_INPUT(lastMatchInfo);
150 if (IS_UNDEFINED(regExpInput)) { 155 if (IS_UNDEFINED(string)) {
151 throw MakeError('no_input_to_regexp', [this]); 156 throw MakeError('no_input_to_regexp', [this]);
152 } 157 }
153 string = regExpInput;
154 } 158 }
159
160 var lastIndex = this.lastIndex;
161 if (%_IsIdentical(regExpExecCacheInput, string) &&
162 %_IsIdentical(regExpExecCacheId, %_RegExpId(this)) &&
163 %_IsIdentical(regExpExecCacheIndex, lastIndex)) {
164 var cachedResult = regExpExecCacheResult; // Cached result.
165 if (cachedResult) {
166 // If non-null, don't return the same array as last time.
167 var newArray = ArraySlice.call(cachedResult, 0, cachedResult.length);
168 newArray.input = cachedResult.input;
169 newArray.index = cachedResult.index;
170 cachedResult = newArray;
171 }
172 %_Log("regexp", "regexp-exec-cache-hit", []);
173 return cachedResult;
174 }
175 %_Log("regexp", "regexp-exec-cache-miss", []);
176
177 var i = this.global ? TO_INTEGER(lastIndex) : 0;
155 var s = ToString(string); 178 var s = ToString(string);
156 var length = s.length; 179 var length = s.length;
157 var lastIndex = this.lastIndex;
158 var i = this.global ? TO_INTEGER(lastIndex) : 0;
159 180
160 if (i < 0 || i > s.length) { 181 if (i < 0 || i > s.length) {
161 this.lastIndex = 0; 182 this.lastIndex = 0;
162 return null; 183 return null;
163 } 184 }
164 185
165 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); 186 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
166 // matchIndices is either null or the lastMatchInfo array. 187 // matchIndices is either null or the lastMatchInfo array.
167 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); 188 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
168 189
190 var result;
169 if (matchIndices == null) { 191 if (matchIndices == null) {
170 if (this.global) this.lastIndex = 0; 192 if (this.global) this.lastIndex = 0;
171 return matchIndices; // no match 193 result = matchIndices; // no match
194 } else {
195 var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
196 result = new $Array(numResults);
197 for (var i = 0; i < numResults; i++) {
198 var matchStart = lastMatchInfo[CAPTURE(i << 1)];
199 var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
200 if (matchStart != -1 && matchEnd != -1) {
201 result[i] = SubString(s, matchStart, matchEnd);
202 } else {
203 // Make sure the element is present. Avoid reading the undefined
204 // property from the global object since this may change.
205 result[i] = void 0;
206 }
207 }
208 if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
209 result.index = lastMatchInfo[CAPTURE0];
210 result.input = s;
172 } 211 }
173 212 regExpExecCacheResult = result;
174 var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1; 213 regExpExecCacheInput = string;
175 var result = new $Array(numResults); 214 regExpExecCacheId = %_RegExpId(this); // May have changed.
176 for (var i = 0; i < numResults; i++) { 215 regExpExecCacheIndex = lastIndex;
177 var matchStart = lastMatchInfo[CAPTURE(i << 1)];
178 var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
179 if (matchStart != -1 && matchEnd != -1) {
180 result[i] = SubString(s, matchStart, matchEnd);
181 } else {
182 // Make sure the element is present. Avoid reading the undefined
183 // property from the global object since this may change.
184 result[i] = void 0;
185 }
186 }
187
188 if (this.global)
189 this.lastIndex = lastMatchInfo[CAPTURE1];
190 result.index = lastMatchInfo[CAPTURE0];
191 result.input = s;
192 return result; 216 return result;
193 } 217 }
194 218
195 219
220 var regExpTestCacheResult;
221 var regExpTestCacheId;
222 var regExpTestCacheIndex;
223 var regExpTestCacheInput;
224
196 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be 225 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
197 // that test is defined in terms of String.prototype.exec. However, it probably 226 // that test is defined in terms of String.prototype.exec. However, it probably
198 // means the original value of String.prototype.exec, which is what everybody 227 // means the original value of String.prototype.exec, which is what everybody
199 // else implements. 228 // else implements.
200 function RegExpTest(string) { 229 function RegExpTest(string) {
201 if (!IS_REGEXP(this)) { 230 if (!IS_REGEXP(this)) {
202 throw MakeTypeError('method_called_on_incompatible', 231 throw MakeTypeError('method_called_on_incompatible',
203 ['RegExp.prototype.test', this]); 232 ['RegExp.prototype.test', this]);
204 } 233 }
205 if (%_ArgumentsLength() == 0) { 234 if (%_ArgumentsLength() == 0) {
206 var regExpInput = LAST_INPUT(lastMatchInfo); 235 string = LAST_INPUT(lastMatchInfo);
207 if (IS_UNDEFINED(regExpInput)) { 236 if (IS_UNDEFINED(string)) {
208 throw MakeError('no_input_to_regexp', [this]); 237 throw MakeError('no_input_to_regexp', [this]);
209 } 238 }
210 string = regExpInput;
211 } 239 }
240
241 var lastIndex = this.lastIndex;
242 if (%_IsIdentical(regExpTestCacheInput, string) &&
243 %_IsIdentical(regExpTestCacheId, %_RegExpId(this)) &&
244 %_IsIdentical(regExpTestCacheIndex, lastIndex)) {
245 %_Log("regexp", "regexp-test-cache-hit", []);
246 return regExpTestCacheResult; // Always true or false.
247 }
248 %_Log("regexp", "regexp-test-cache-miss", []);
249
250 var i = this.global ? TO_INTEGER(lastIndex) : 0;
212 var s = ToString(string); 251 var s = ToString(string);
213 var length = s.length; 252 var length = s.length;
214 var lastIndex = this.lastIndex;
215 var i = this.global ? TO_INTEGER(lastIndex) : 0;
216 253
254 var result;
217 if (i < 0 || i > s.length) { 255 if (i < 0 || i > s.length) {
218 this.lastIndex = 0; 256 this.lastIndex = 0;
219 return false; 257 result = false;
258 } else {
259 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
260 // matchIndices is either null or the lastMatchInfo array.
261 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
262
263 if (matchIndices == null) {
264 if (this.global) this.lastIndex = 0;
265 result = false;
266 } else {
267 if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
268 result = true;
269 }
220 } 270 }
221 271 regExpTestCacheResult = result;
222 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); 272 regExpTestCacheInput = string;
223 // matchIndices is either null or the lastMatchInfo array. 273 regExpTestCacheId = %_RegExpId(this);
224 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); 274 regExpTestCacheIndex = lastIndex;
225 275 return result;
226 if (matchIndices == null) {
227 if (this.global) this.lastIndex = 0;
228 return false;
229 }
230
231 if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1];
232 return true;
233 } 276 }
234 277
235 278
236 function RegExpToString() { 279 function RegExpToString() {
237 // If this.source is an empty string, output /(?:)/. 280 // If this.source is an empty string, output /(?:)/.
238 // http://bugzilla.mozilla.org/show_bug.cgi?id=225550 281 // http://bugzilla.mozilla.org/show_bug.cgi?id=225550
239 // ecma_2/RegExp/properties-001.js. 282 // ecma_2/RegExp/properties-001.js.
240 var src = this.source ? this.source : '(?:)'; 283 var src = this.source ? this.source : '(?:)';
241 var result = '/' + src + '/'; 284 var result = '/' + src + '/';
242 if (this.global) 285 if (this.global)
(...skipping 90 matching lines...)
333 "exec", RegExpExec, 376 "exec", RegExpExec,
334 "test", RegExpTest, 377 "test", RegExpTest,
335 "toString", RegExpToString, 378 "toString", RegExpToString,
336 "compile", CompileRegExp 379 "compile", CompileRegExp
337 )); 380 ));
338 381
339 // The length of compile is 1 in SpiderMonkey. 382 // The length of compile is 1 in SpiderMonkey.
340 %FunctionSetLength($RegExp.prototype.compile, 1); 383 %FunctionSetLength($RegExp.prototype.compile, 1);
341 384
342 // The properties input, $input, and $_ are aliases for each other. When this 385 // The properties input, $input, and $_ are aliases for each other. When this
343 // value is set the value it is set to is coerced to a string. 386 // value is set the value it is set to is coerced to a string.
344 // Getter and setter for the input. 387 // Getter and setter for the input.
345 function RegExpGetInput() { 388 function RegExpGetInput() {
346 var regExpInput = LAST_INPUT(lastMatchInfo); 389 var regExpInput = LAST_INPUT(lastMatchInfo);
347 return IS_UNDEFINED(regExpInput) ? "" : regExpInput; 390 return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
348 } 391 }
349 function RegExpSetInput(string) { 392 function RegExpSetInput(string) {
350 LAST_INPUT(lastMatchInfo) = ToString(string); 393 LAST_INPUT(lastMatchInfo) = ToString(string);
351 }; 394 };
352 395
353 %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE); 396 %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
(...skipping 43 matching lines...)
397 %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE); 440 %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE);
398 441
399 for (var i = 1; i < 10; ++i) { 442 for (var i = 1; i < 10; ++i) {
400 %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_D ELETE); 443 %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_D ELETE);
401 %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE); 444 %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE);
402 } 445 }
403 } 446 }
404 447
405 448
406 SetupRegExp(); 449 SetupRegExp();
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.cc ('k') | src/string.js » ('j') | no next file with comments »

Powered by Google App Engine