Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 cache.lastIndex = lastIndex; | 250 cache.lastIndex = lastIndex; |
| 251 if (saveAnswer) cache.answer = CloneRegExpResult(result); | 251 if (saveAnswer) cache.answer = CloneRegExpResult(result); |
| 252 cache.answerSaved = saveAnswer; | 252 cache.answerSaved = saveAnswer; |
| 253 cache.type = 'exec'; | 253 cache.type = 'exec'; |
| 254 } | 254 } |
| 255 return result; | 255 return result; |
| 256 | 256 |
| 257 } | 257 } |
| 258 | 258 |
| 259 | 259 |
| 260 // One-element cache for the simplified test regexp. | |
| 261 var regexp_key; | |
| 262 var regexp_val; | |
|
Lasse Reichstein
2010/06/04 11:30:33
How often do you hit this? (And how often will you
sandholm
2010/06/04 11:57:23
Caching negative results in the global regexp cach
| |
| 263 | |
| 260 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be | 264 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be |
| 261 // that test is defined in terms of String.prototype.exec. However, it probably | 265 // that test is defined in terms of String.prototype.exec. However, it probably |
| 262 // means the original value of String.prototype.exec, which is what everybody | 266 // means the original value of String.prototype.exec, which is what everybody |
| 263 // else implements. | 267 // else implements. |
| 264 function RegExpTest(string) { | 268 function RegExpTest(string) { |
| 265 if (!IS_REGEXP(this)) { | 269 if (!IS_REGEXP(this)) { |
| 266 throw MakeTypeError('incompatible_method_receiver', | 270 throw MakeTypeError('incompatible_method_receiver', |
| 267 ['RegExp.prototype.test', this]); | 271 ['RegExp.prototype.test', this]); |
| 268 } | 272 } |
| 269 if (%_ArgumentsLength() == 0) { | 273 if (%_ArgumentsLength() == 0) { |
| 270 var regExpInput = LAST_INPUT(lastMatchInfo); | 274 var regExpInput = LAST_INPUT(lastMatchInfo); |
| 271 if (IS_UNDEFINED(regExpInput)) { | 275 if (IS_UNDEFINED(regExpInput)) { |
| 272 throw MakeError('no_input_to_regexp', [this]); | 276 throw MakeError('no_input_to_regexp', [this]); |
| 273 } | 277 } |
| 274 string = regExpInput; | 278 string = regExpInput; |
| 275 } | 279 } |
| 276 var s; | 280 var s; |
| 277 if (IS_STRING(string)) { | 281 if (IS_STRING(string)) { |
| 278 s = string; | 282 s = string; |
| 279 } else { | 283 } else { |
| 280 s = ToString(string); | 284 s = ToString(string); |
| 281 } | 285 } |
| 282 | 286 |
| 283 var lastIndex = this.lastIndex; | 287 var lastIndex = this.lastIndex; |
| 284 | |
| 285 var cache = regExpCache; | 288 var cache = regExpCache; |
| 286 | |
| 287 if (%_ObjectEquals(cache.type, 'test') && | 289 if (%_ObjectEquals(cache.type, 'test') && |
| 288 %_ObjectEquals(cache.regExp, this) && | 290 %_ObjectEquals(cache.regExp, this) && |
| 289 %_ObjectEquals(cache.subject, string) && | 291 %_ObjectEquals(cache.subject, string) && |
| 290 %_ObjectEquals(cache.lastIndex, lastIndex)) { | 292 %_ObjectEquals(cache.lastIndex, lastIndex)) { |
| 291 return cache.answer; | 293 return cache.answer; |
| 292 } | 294 } |
| 293 | 295 |
| 296 // Remove irrelevant '.*' around a test regexp. The expression | |
| 297 // checks whether this.source starts and ends with '.*' and that the third | |
| 298 // char is not a '?' and that the third to last char is not a '\'. | |
| 299 if (%_StringCharCodeAt(this.source,0) == 46 && // '.' | |
|
Lasse Reichstein
2010/06/04 11:30:33
You may want to try moving this.source to a local
sandholm
2010/06/04 11:57:23
Tried this. Causes regressions on some benchmarks
| |
| 300 %_StringCharCodeAt(this.source,1) == 42 && // '*' | |
| 301 %_StringCharCodeAt(this.source,2) != 63 && // '?' | |
| 302 %_StringCharCodeAt(this.source,this.source.length - 3) != 28 && // '\' | |
| 303 %_StringCharCodeAt(this.source,this.source.length - 2) == 46 && // '.' | |
| 304 %_StringCharCodeAt(this.source,this.source.length - 1) == 42) { // '*' | |
| 305 if (!%_ObjectEquals(regexp_key, this)) { | |
| 306 regexp_key = this; | |
| 307 regexp_val = new $RegExp(this.source.substring(2, | |
| 308 this.source.length - 2), | |
| 309 (this.global ? 'g' : '') | |
| 310 + (this.ignoreCase ? 'i' : '') | |
| 311 + (this.multiline ? 'm' : '')); | |
| 312 } | |
| 313 if (!regexp_val.test(s)) return false; | |
|
Lasse Reichstein
2010/06/04 11:30:33
You can cache the negative result in the regexp ca
sandholm
2010/06/04 11:57:23
Often test is called with a new string so that won
| |
| 314 } | |
| 315 | |
| 294 var length = s.length; | 316 var length = s.length; |
| 295 var i = this.global ? TO_INTEGER(lastIndex) : 0; | 317 var i = this.global ? TO_INTEGER(lastIndex) : 0; |
| 296 | 318 |
| 297 cache.type = 'test'; | 319 cache.type = 'test'; |
| 298 cache.regExp = this; | 320 cache.regExp = this; |
| 299 cache.subject = s; | 321 cache.subject = s; |
| 300 cache.lastIndex = i; | 322 cache.lastIndex = i; |
| 301 | 323 |
| 302 if (i < 0 || i > s.length) { | 324 if (i < 0 || i > length) { |
| 303 this.lastIndex = 0; | 325 this.lastIndex = 0; |
| 304 cache.answer = false; | 326 cache.answer = false; |
| 305 return false; | 327 return false; |
| 306 } | 328 } |
| 307 | 329 |
| 308 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); | 330 %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); |
| 309 // matchIndices is either null or the lastMatchInfo array. | 331 // matchIndices is either null or the lastMatchInfo array. |
| 310 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); | 332 var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); |
| 311 | 333 |
| 312 if (matchIndices == null) { | 334 if (matchIndices == null) { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE); | 541 %DefineAccessor($RegExp, "$'", SETTER, NoOpSetter, DONT_ENUM | DONT_DELETE); |
| 520 | 542 |
| 521 for (var i = 1; i < 10; ++i) { | 543 for (var i = 1; i < 10; ++i) { |
| 522 %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_D ELETE); | 544 %DefineAccessor($RegExp, '$' + i, GETTER, RegExpMakeCaptureGetter(i), DONT_D ELETE); |
| 523 %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE); | 545 %DefineAccessor($RegExp, '$' + i, SETTER, NoOpSetter, DONT_DELETE); |
| 524 } | 546 } |
| 525 } | 547 } |
| 526 | 548 |
| 527 | 549 |
| 528 SetupRegExp(); | 550 SetupRegExp(); |
| OLD | NEW |