| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 | 44 |
| 45 #ifdef ARM | 45 #ifdef ARM |
| 46 #include "regexp-macro-assembler-arm.h" | 46 #include "regexp-macro-assembler-arm.h" |
| 47 #else // IA32 | 47 #else // IA32 |
| 48 #include "macro-assembler-ia32.h" | 48 #include "macro-assembler-ia32.h" |
| 49 #include "regexp-macro-assembler-ia32.h" | 49 #include "regexp-macro-assembler-ia32.h" |
| 50 #endif | 50 #endif |
| 51 | 51 |
| 52 #include "interpreter-irregexp.h" | 52 #include "interpreter-irregexp.h" |
| 53 | 53 |
| 54 // Including pcre.h undefines DEBUG to avoid getting debug output from | |
| 55 // the JSCRE implementation. Make sure to redefine it in debug mode | |
| 56 // after having included the header file. | |
| 57 #ifdef DEBUG | |
| 58 #include "third_party/jscre/pcre.h" | |
| 59 #define DEBUG | |
| 60 #else | |
| 61 #include "third_party/jscre/pcre.h" | |
| 62 #endif | |
| 63 | |
| 64 | 54 |
| 65 namespace v8 { namespace internal { | 55 namespace v8 { namespace internal { |
| 66 | 56 |
| 67 | 57 |
| 68 static Failure* malloc_failure; | |
| 69 | |
| 70 static void* JSREMalloc(size_t size) { | |
| 71 Object* obj = Heap::AllocateByteArray(size); | |
| 72 | |
| 73 // If allocation failed, return a NULL pointer to JSRE, and jsRegExpCompile | |
| 74 // will return NULL to the caller, performs GC there. | |
| 75 // Also pass failure information to the caller. | |
| 76 if (obj->IsFailure()) { | |
| 77 malloc_failure = Failure::cast(obj); | |
| 78 return NULL; | |
| 79 } | |
| 80 | |
| 81 // Note: object is unrooted, the caller of jsRegExpCompile must | |
| 82 // create a handle for the return value before doing heap allocation. | |
| 83 return reinterpret_cast<void*>(ByteArray::cast(obj)->GetDataStartAddress()); | |
| 84 } | |
| 85 | |
| 86 | |
| 87 static void JSREFree(void* p) { | |
| 88 USE(p); // Do nothing, memory is garbage collected. | |
| 89 } | |
| 90 | |
| 91 | |
| 92 String* RegExpImpl::last_ascii_string_ = NULL; | 58 String* RegExpImpl::last_ascii_string_ = NULL; |
| 93 String* RegExpImpl::two_byte_cached_string_ = NULL; | 59 String* RegExpImpl::two_byte_cached_string_ = NULL; |
| 94 | 60 |
| 95 | 61 |
| 96 void RegExpImpl::NewSpaceCollectionPrologue() { | 62 void RegExpImpl::NewSpaceCollectionPrologue() { |
| 97 // The two byte string is always in the old space. The Ascii string may be | 63 // The two byte string is always in the old space. The Ascii string may be |
| 98 // in either place. If it is in the old space we don't need to do anything. | 64 // in either place. If it is in the old space we don't need to do anything. |
| 99 if (Heap::InNewSpace(last_ascii_string_)) { | 65 if (Heap::InNewSpace(last_ascii_string_)) { |
| 100 // Invalidate the cache. | 66 // Invalidate the cache. |
| 101 last_ascii_string_ = NULL; | 67 last_ascii_string_ = NULL; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 if (parse_result.simple && !flags.is_ignore_case()) { | 231 if (parse_result.simple && !flags.is_ignore_case()) { |
| 266 // Parse-tree is a single atom that is equal to the pattern. | 232 // Parse-tree is a single atom that is equal to the pattern. |
| 267 result = AtomCompile(re, pattern, flags, pattern); | 233 result = AtomCompile(re, pattern, flags, pattern); |
| 268 } else if (parse_result.tree->IsAtom() && | 234 } else if (parse_result.tree->IsAtom() && |
| 269 !flags.is_ignore_case() && | 235 !flags.is_ignore_case() && |
| 270 parse_result.capture_count == 0) { | 236 parse_result.capture_count == 0) { |
| 271 RegExpAtom* atom = parse_result.tree->AsAtom(); | 237 RegExpAtom* atom = parse_result.tree->AsAtom(); |
| 272 Vector<const uc16> atom_pattern = atom->data(); | 238 Vector<const uc16> atom_pattern = atom->data(); |
| 273 Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern); | 239 Handle<String> atom_string = Factory::NewStringFromTwoByte(atom_pattern); |
| 274 result = AtomCompile(re, pattern, flags, atom_string); | 240 result = AtomCompile(re, pattern, flags, atom_string); |
| 275 } else if (FLAG_irregexp) { | 241 } else { |
| 276 result = IrregexpPrepare(re, pattern, flags); | 242 result = IrregexpPrepare(re, pattern, flags); |
| 277 } else { | |
| 278 result = JscrePrepare(re, pattern, flags); | |
| 279 } | 243 } |
| 280 Object* data = re->data(); | 244 Object* data = re->data(); |
| 281 if (data->IsFixedArray()) { | 245 if (data->IsFixedArray()) { |
| 282 // If compilation succeeded then the data is set on the regexp | 246 // If compilation succeeded then the data is set on the regexp |
| 283 // and we can store it in the cache. | 247 // and we can store it in the cache. |
| 284 Handle<FixedArray> data(FixedArray::cast(re->data())); | 248 Handle<FixedArray> data(FixedArray::cast(re->data())); |
| 285 CompilationCache::PutRegExp(pattern, flags, data); | 249 CompilationCache::PutRegExp(pattern, flags, data); |
| 286 } | 250 } |
| 287 } | 251 } |
| 288 | 252 |
| 289 return result; | 253 return result; |
| 290 } | 254 } |
| 291 | 255 |
| 292 | 256 |
| 293 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, | 257 Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp, |
| 294 Handle<String> subject, | 258 Handle<String> subject, |
| 295 Handle<Object> index) { | 259 Handle<Object> index) { |
| 296 switch (regexp->TypeTag()) { | 260 switch (regexp->TypeTag()) { |
| 297 case JSRegExp::ATOM: | 261 case JSRegExp::ATOM: |
| 298 return AtomExec(regexp, subject, index); | 262 return AtomExec(regexp, subject, index); |
| 299 case JSRegExp::IRREGEXP: { | 263 case JSRegExp::IRREGEXP: { |
| 300 Handle<Object> result = IrregexpExec(regexp, subject, index); | 264 Handle<Object> result = IrregexpExec(regexp, subject, index); |
| 301 ASSERT(!result.is_null() || Top::has_pending_exception()); | 265 ASSERT(!result.is_null() || Top::has_pending_exception()); |
| 302 return result; | 266 return result; |
| 303 } | 267 } |
| 304 case JSRegExp::JSCRE: | |
| 305 return JscreExec(regexp, subject, index); | |
| 306 default: | 268 default: |
| 307 UNREACHABLE(); | 269 UNREACHABLE(); |
| 308 return Handle<Object>::null(); | 270 return Handle<Object>::null(); |
| 309 } | 271 } |
| 310 } | 272 } |
| 311 | 273 |
| 312 | 274 |
| 313 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, | 275 Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp, |
| 314 Handle<String> subject) { | 276 Handle<String> subject) { |
| 315 switch (regexp->TypeTag()) { | 277 switch (regexp->TypeTag()) { |
| 316 case JSRegExp::ATOM: | 278 case JSRegExp::ATOM: |
| 317 return AtomExecGlobal(regexp, subject); | 279 return AtomExecGlobal(regexp, subject); |
| 318 case JSRegExp::IRREGEXP: { | 280 case JSRegExp::IRREGEXP: { |
| 319 Handle<Object> result = IrregexpExecGlobal(regexp, subject); | 281 Handle<Object> result = IrregexpExecGlobal(regexp, subject); |
| 320 ASSERT(!result.is_null() || Top::has_pending_exception()); | 282 ASSERT(!result.is_null() || Top::has_pending_exception()); |
| 321 return result; | 283 return result; |
| 322 } | 284 } |
| 323 case JSRegExp::JSCRE: | |
| 324 return JscreExecGlobal(regexp, subject); | |
| 325 default: | 285 default: |
| 326 UNREACHABLE(); | 286 UNREACHABLE(); |
| 327 return Handle<Object>::null(); | 287 return Handle<Object>::null(); |
| 328 } | 288 } |
| 329 } | 289 } |
| 330 | 290 |
| 331 | 291 |
| 332 // RegExp Atom implementation: Simple string search using indexOf. | 292 // RegExp Atom implementation: Simple string search using indexOf. |
| 333 | 293 |
| 334 | 294 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 Handle<JSArray> pair = Factory::NewJSArrayWithElements(array); | 344 Handle<JSArray> pair = Factory::NewJSArrayWithElements(array); |
| 385 SetElement(result, match_count, pair); | 345 SetElement(result, match_count, pair); |
| 386 match_count++; | 346 match_count++; |
| 387 index = end; | 347 index = end; |
| 388 if (needle_length == 0) index++; | 348 if (needle_length == 0) index++; |
| 389 } | 349 } |
| 390 return result; | 350 return result; |
| 391 } | 351 } |
| 392 | 352 |
| 393 | 353 |
| 394 // JSCRE implementation. | |
| 395 | |
| 396 | |
| 397 int RegExpImpl::JscreNumberOfCaptures(Handle<JSRegExp> re) { | |
| 398 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex)); | |
| 399 return Smi::cast(value->get(kJscreNumberOfCapturesIndex))->value(); | |
| 400 } | |
| 401 | |
| 402 | |
| 403 ByteArray* RegExpImpl::JscreInternal(Handle<JSRegExp> re) { | |
| 404 FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex)); | |
| 405 return ByteArray::cast(value->get(kJscreInternalIndex)); | |
| 406 } | |
| 407 | |
| 408 | |
| 409 Handle<Object>RegExpImpl::JscrePrepare(Handle<JSRegExp> re, | |
| 410 Handle<String> pattern, | |
| 411 JSRegExp::Flags flags) { | |
| 412 Handle<Object> value(Heap::undefined_value()); | |
| 413 Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value); | |
| 414 return re; | |
| 415 } | |
| 416 | |
| 417 | |
| 418 static inline Object* JscreDoCompile(String* pattern, | |
| 419 JSRegExp::Flags flags, | |
| 420 unsigned* number_of_captures, | |
| 421 const char** error_message, | |
| 422 v8::jscre::JscreRegExp** code) { | |
| 423 v8::jscre::JSRegExpIgnoreCaseOption case_option = flags.is_ignore_case() | |
| 424 ? v8::jscre::JSRegExpIgnoreCase | |
| 425 : v8::jscre::JSRegExpDoNotIgnoreCase; | |
| 426 v8::jscre::JSRegExpMultilineOption multiline_option = flags.is_multiline() | |
| 427 ? v8::jscre::JSRegExpMultiline | |
| 428 : v8::jscre::JSRegExpSingleLine; | |
| 429 *error_message = NULL; | |
| 430 malloc_failure = Failure::Exception(); | |
| 431 *code = v8::jscre::jsRegExpCompile(pattern->GetTwoByteData(), | |
| 432 pattern->length(), | |
| 433 case_option, | |
| 434 multiline_option, | |
| 435 number_of_captures, | |
| 436 error_message, | |
| 437 &JSREMalloc, | |
| 438 &JSREFree); | |
| 439 if (*code == NULL && (malloc_failure->IsRetryAfterGC() || | |
| 440 malloc_failure->IsOutOfMemoryFailure())) { | |
| 441 return malloc_failure; | |
| 442 } else { | |
| 443 // It doesn't matter which object we return here, we just need to return | |
| 444 // a non-failure to indicate to the GC-retry code that there was no | |
| 445 // allocation failure. | |
| 446 return pattern; | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 | |
| 451 static void JscreCompileWithRetryAfterGC(Handle<String> pattern, | |
| 452 JSRegExp::Flags flags, | |
| 453 unsigned* number_of_captures, | |
| 454 const char** error_message, | |
| 455 v8::jscre::JscreRegExp** code) { | |
| 456 CALL_HEAP_FUNCTION_VOID(JscreDoCompile(*pattern, | |
| 457 flags, | |
| 458 number_of_captures, | |
| 459 error_message, | |
| 460 code)); | |
| 461 } | |
| 462 | |
| 463 | |
| 464 Handle<Object> RegExpImpl::JscreCompile(Handle<JSRegExp> re) { | |
| 465 ASSERT_EQ(re->TypeTag(), JSRegExp::JSCRE); | |
| 466 ASSERT(re->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()); | |
| 467 | |
| 468 Handle<String> pattern(re->Pattern()); | |
| 469 JSRegExp::Flags flags = re->GetFlags(); | |
| 470 | |
| 471 Handle<String> two_byte_pattern = StringToTwoByte(pattern); | |
| 472 | |
| 473 unsigned number_of_captures; | |
| 474 const char* error_message = NULL; | |
| 475 | |
| 476 v8::jscre::JscreRegExp* code = NULL; | |
| 477 FlattenString(pattern); | |
| 478 | |
| 479 JscreCompileWithRetryAfterGC(two_byte_pattern, | |
| 480 flags, | |
| 481 &number_of_captures, | |
| 482 &error_message, | |
| 483 &code); | |
| 484 | |
| 485 if (code == NULL) { | |
| 486 // Throw an exception. | |
| 487 Handle<JSArray> array = Factory::NewJSArray(2); | |
| 488 SetElement(array, 0, pattern); | |
| 489 const char* message = | |
| 490 (error_message == NULL) ? "Unknown regexp error" : error_message; | |
| 491 SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(message))); | |
| 492 Handle<Object> regexp_err = | |
| 493 Factory::NewSyntaxError("malformed_regexp", array); | |
| 494 Top::Throw(*regexp_err); | |
| 495 return Handle<Object>(); | |
| 496 } | |
| 497 | |
| 498 // Convert the return address to a ByteArray pointer. | |
| 499 Handle<ByteArray> internal( | |
| 500 ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code))); | |
| 501 | |
| 502 Handle<FixedArray> value = Factory::NewFixedArray(kJscreDataLength); | |
| 503 value->set(kJscreNumberOfCapturesIndex, Smi::FromInt(number_of_captures)); | |
| 504 value->set(kJscreInternalIndex, *internal); | |
| 505 Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value); | |
| 506 | |
| 507 return re; | |
| 508 } | |
| 509 | |
| 510 | |
| 511 Handle<Object> RegExpImpl::JscreExec(Handle<JSRegExp> regexp, | |
| 512 Handle<String> subject, | |
| 513 Handle<Object> index) { | |
| 514 ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE); | |
| 515 if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) { | |
| 516 Handle<Object> compile_result = JscreCompile(regexp); | |
| 517 if (compile_result.is_null()) return compile_result; | |
| 518 } | |
| 519 ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray()); | |
| 520 | |
| 521 int num_captures = JscreNumberOfCaptures(regexp); | |
| 522 | |
| 523 OffsetsVector offsets((num_captures + 1) * 3); | |
| 524 | |
| 525 int previous_index = static_cast<int>(DoubleToInteger(index->Number())); | |
| 526 | |
| 527 Handle<String> subject16 = CachedStringToTwoByte(subject); | |
| 528 | |
| 529 return JscreExecOnce(regexp, | |
| 530 num_captures, | |
| 531 subject, | |
| 532 previous_index, | |
| 533 subject16->GetTwoByteData(), | |
| 534 offsets.vector(), | |
| 535 offsets.length()); | |
| 536 } | |
| 537 | |
| 538 | |
| 539 Handle<Object> RegExpImpl::JscreExecOnce(Handle<JSRegExp> regexp, | |
| 540 int num_captures, | |
| 541 Handle<String> subject, | |
| 542 int previous_index, | |
| 543 const uc16* two_byte_subject, | |
| 544 int* offsets_vector, | |
| 545 int offsets_vector_length) { | |
| 546 int rc; | |
| 547 { | |
| 548 AssertNoAllocation a; | |
| 549 ByteArray* internal = JscreInternal(regexp); | |
| 550 const v8::jscre::JscreRegExp* js_regexp = | |
| 551 reinterpret_cast<v8::jscre::JscreRegExp*>( | |
| 552 internal->GetDataStartAddress()); | |
| 553 | |
| 554 rc = v8::jscre::jsRegExpExecute(js_regexp, | |
| 555 two_byte_subject, | |
| 556 subject->length(), | |
| 557 previous_index, | |
| 558 offsets_vector, | |
| 559 offsets_vector_length); | |
| 560 } | |
| 561 | |
| 562 // The KJS JavaScript engine returns null (ie, a failed match) when | |
| 563 // JSRE's internal match limit is exceeded. We duplicate that behavior here. | |
| 564 if (rc == v8::jscre::JSRegExpErrorNoMatch | |
| 565 || rc == v8::jscre::JSRegExpErrorHitLimit) { | |
| 566 return Factory::null_value(); | |
| 567 } | |
| 568 | |
| 569 // Other JSRE errors: | |
| 570 if (rc < 0) { | |
| 571 // Throw an exception. | |
| 572 Handle<Object> code(Smi::FromInt(rc)); | |
| 573 Handle<Object> args[2] = { Factory::LookupAsciiSymbol("jsre_exec"), code }; | |
| 574 Handle<Object> regexp_err( | |
| 575 Factory::NewTypeError("jsre_error", HandleVector(args, 2))); | |
| 576 return Handle<Object>(Top::Throw(*regexp_err)); | |
| 577 } | |
| 578 | |
| 579 Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1)); | |
| 580 // The captures come in (start, end+1) pairs. | |
| 581 for (int i = 0; i < 2 * (num_captures+1); i += 2) { | |
| 582 array->set(i, Smi::FromInt(offsets_vector[i])); | |
| 583 array->set(i+1, Smi::FromInt(offsets_vector[i+1])); | |
| 584 } | |
| 585 return Factory::NewJSArrayWithElements(array); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 Handle<Object> RegExpImpl::JscreExecGlobal(Handle<JSRegExp> regexp, | |
| 590 Handle<String> subject) { | |
| 591 ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE); | |
| 592 if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) { | |
| 593 Handle<Object> compile_result = JscreCompile(regexp); | |
| 594 if (compile_result.is_null()) return compile_result; | |
| 595 } | |
| 596 ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray()); | |
| 597 | |
| 598 // Prepare space for the return values. | |
| 599 int num_captures = JscreNumberOfCaptures(regexp); | |
| 600 | |
| 601 OffsetsVector offsets((num_captures + 1) * 3); | |
| 602 | |
| 603 int previous_index = 0; | |
| 604 | |
| 605 Handle<JSArray> result = Factory::NewJSArray(0); | |
| 606 int i = 0; | |
| 607 Handle<Object> matches; | |
| 608 | |
| 609 Handle<String> subject16 = CachedStringToTwoByte(subject); | |
| 610 | |
| 611 do { | |
| 612 if (previous_index > subject->length() || previous_index < 0) { | |
| 613 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | |
| 614 // string length, there is no match. | |
| 615 matches = Factory::null_value(); | |
| 616 } else { | |
| 617 matches = JscreExecOnce(regexp, | |
| 618 num_captures, | |
| 619 subject, | |
| 620 previous_index, | |
| 621 subject16->GetTwoByteData(), | |
| 622 offsets.vector(), | |
| 623 offsets.length()); | |
| 624 | |
| 625 if (matches->IsJSArray()) { | |
| 626 SetElement(result, i, matches); | |
| 627 i++; | |
| 628 previous_index = offsets.vector()[1]; | |
| 629 if (offsets.vector()[0] == offsets.vector()[1]) { | |
| 630 previous_index++; | |
| 631 } | |
| 632 } | |
| 633 } | |
| 634 } while (matches->IsJSArray()); | |
| 635 | |
| 636 // If we exited the loop with an exception, throw it. | |
| 637 if (matches->IsNull()) { | |
| 638 // Exited loop normally. | |
| 639 return result; | |
| 640 } else { | |
| 641 // Exited loop with the exception in matches. | |
| 642 return matches; | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 | |
| 647 // Irregexp implementation. | 354 // Irregexp implementation. |
| 648 | 355 |
| 649 | 356 |
| 650 // Retrieves a compiled version of the regexp for either ASCII or non-ASCII | 357 // Retrieves a compiled version of the regexp for either ASCII or non-ASCII |
| 651 // strings. If the compiled version doesn't already exist, it is compiled | 358 // strings. If the compiled version doesn't already exist, it is compiled |
| 652 // from the source pattern. | 359 // from the source pattern. |
| 653 // Irregexp is not feature complete yet. If there is something in the | 360 // Irregexp is not feature complete yet. If there is something in the |
| 654 // regexp that the compiler cannot currently handle, an empty | 361 // regexp that the compiler cannot currently handle, an empty |
| 655 // handle is returned, but no exception is thrown. | 362 // handle is returned, but no exception is thrown. |
| 656 static Handle<FixedArray> GetCompiledIrregexp(Handle<JSRegExp> re, | 363 static Handle<FixedArray> GetCompiledIrregexp(Handle<JSRegExp> re, |
| (...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2063 return DONE; | 1770 return DONE; |
| 2064 } | 1771 } |
| 2065 // Generate generic version of the node and bind the label for later use. | 1772 // Generate generic version of the node and bind the label for later use. |
| 2066 macro_assembler->Bind(&label_); | 1773 macro_assembler->Bind(&label_); |
| 2067 return CONTINUE; | 1774 return CONTINUE; |
| 2068 } | 1775 } |
| 2069 | 1776 |
| 2070 // We are being asked to make a non-generic version. Keep track of how many | 1777 // We are being asked to make a non-generic version. Keep track of how many |
| 2071 // non-generic versions we generate so as not to overdo it. | 1778 // non-generic versions we generate so as not to overdo it. |
| 2072 trace_count_++; | 1779 trace_count_++; |
| 2073 if (FLAG_irregexp_optimization && | 1780 if (FLAG_regexp_optimization && |
| 2074 trace_count_ < kMaxCopiesCodeGenerated && | 1781 trace_count_ < kMaxCopiesCodeGenerated && |
| 2075 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { | 1782 compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
| 2076 return CONTINUE; | 1783 return CONTINUE; |
| 2077 } | 1784 } |
| 2078 | 1785 |
| 2079 // If we get here code has been generated for this node too many times or | 1786 // If we get here code has been generated for this node too many times or |
| 2080 // recursion is too deep. Time to switch to a generic version. The code for | 1787 // recursion is too deep. Time to switch to a generic version. The code for |
| 2081 // generic versions above can handle deep recursion properly. | 1788 // generic versions above can handle deep recursion properly. |
| 2082 trace->Flush(compiler, this); | 1789 trace->Flush(compiler, this); |
| 2083 return DONE; | 1790 return DONE; |
| (...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3230 new_trace.set_characters_preloaded(preload_is_current ? | 2937 new_trace.set_characters_preloaded(preload_is_current ? |
| 3231 preload_characters : | 2938 preload_characters : |
| 3232 0); | 2939 0); |
| 3233 if (preload_has_checked_bounds) { | 2940 if (preload_has_checked_bounds) { |
| 3234 new_trace.set_bound_checked_up_to(preload_characters); | 2941 new_trace.set_bound_checked_up_to(preload_characters); |
| 3235 } | 2942 } |
| 3236 new_trace.quick_check_performed()->Clear(); | 2943 new_trace.quick_check_performed()->Clear(); |
| 3237 if (not_at_start_) new_trace.set_at_start(Trace::FALSE); | 2944 if (not_at_start_) new_trace.set_at_start(Trace::FALSE); |
| 3238 alt_gen->expects_preload = preload_is_current; | 2945 alt_gen->expects_preload = preload_is_current; |
| 3239 bool generate_full_check_inline = false; | 2946 bool generate_full_check_inline = false; |
| 3240 if (FLAG_irregexp_optimization && | 2947 if (FLAG_regexp_optimization && |
| 3241 try_to_emit_quick_check_for_alternative(i) && | 2948 try_to_emit_quick_check_for_alternative(i) && |
| 3242 alternative.node()->EmitQuickCheck(compiler, | 2949 alternative.node()->EmitQuickCheck(compiler, |
| 3243 &new_trace, | 2950 &new_trace, |
| 3244 preload_has_checked_bounds, | 2951 preload_has_checked_bounds, |
| 3245 &alt_gen->possible_success, | 2952 &alt_gen->possible_success, |
| 3246 &alt_gen->quick_check_details, | 2953 &alt_gen->quick_check_details, |
| 3247 i < choice_count - 1)) { | 2954 i < choice_count - 1)) { |
| 3248 // Quick check was generated for this choice. | 2955 // Quick check was generated for this choice. |
| 3249 preload_is_current = true; | 2956 preload_is_current = true; |
| 3250 preload_has_checked_bounds = true; | 2957 preload_has_checked_bounds = true; |
| (...skipping 780 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4031 // this case. | 3738 // this case. |
| 4032 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} | 3739 static const int kMaxUnrolledMinMatches = 3; // Unroll (foo)+ and (foo){3,} |
| 4033 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} | 3740 static const int kMaxUnrolledMaxMatches = 3; // Unroll (foo)? and (foo){x,3} |
| 4034 if (max == 0) return on_success; // This can happen due to recursion. | 3741 if (max == 0) return on_success; // This can happen due to recursion. |
| 4035 bool body_can_be_empty = (body->min_match() == 0); | 3742 bool body_can_be_empty = (body->min_match() == 0); |
| 4036 int body_start_reg = RegExpCompiler::kNoRegister; | 3743 int body_start_reg = RegExpCompiler::kNoRegister; |
| 4037 Interval capture_registers = body->CaptureRegisters(); | 3744 Interval capture_registers = body->CaptureRegisters(); |
| 4038 bool needs_capture_clearing = !capture_registers.is_empty(); | 3745 bool needs_capture_clearing = !capture_registers.is_empty(); |
| 4039 if (body_can_be_empty) { | 3746 if (body_can_be_empty) { |
| 4040 body_start_reg = compiler->AllocateRegister(); | 3747 body_start_reg = compiler->AllocateRegister(); |
| 4041 } else if (FLAG_irregexp_optimization && !needs_capture_clearing) { | 3748 } else if (FLAG_regexp_optimization && !needs_capture_clearing) { |
| 4042 // Only unroll if there are no captures and the body can't be | 3749 // Only unroll if there are no captures and the body can't be |
| 4043 // empty. | 3750 // empty. |
| 4044 if (min > 0 && min <= kMaxUnrolledMinMatches) { | 3751 if (min > 0 && min <= kMaxUnrolledMinMatches) { |
| 4045 int new_max = (max == kInfinity) ? max : max - min; | 3752 int new_max = (max == kInfinity) ? max : max - min; |
| 4046 // Recurse once to get the loop or optional matches after the fixed ones. | 3753 // Recurse once to get the loop or optional matches after the fixed ones. |
| 4047 RegExpNode* answer = ToNode( | 3754 RegExpNode* answer = ToNode( |
| 4048 0, new_max, is_greedy, body, compiler, on_success, true); | 3755 0, new_max, is_greedy, body, compiler, on_success, true); |
| 4049 // Unroll the forced matches from 0 to min. This can cause chains of | 3756 // Unroll the forced matches from 0 to min. This can cause chains of |
| 4050 // TextNodes (which the parser does not generate). These should be | 3757 // TextNodes (which the parser does not generate). These should be |
| 4051 // combined if it turns out they hinder good code generation. | 3758 // combined if it turns out they hinder good code generation. |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4923 } else { | 4630 } else { |
| 4924 node = loop_node; | 4631 node = loop_node; |
| 4925 } | 4632 } |
| 4926 } | 4633 } |
| 4927 data->node = node; | 4634 data->node = node; |
| 4928 Analysis analysis(ignore_case); | 4635 Analysis analysis(ignore_case); |
| 4929 analysis.EnsureAnalyzed(node); | 4636 analysis.EnsureAnalyzed(node); |
| 4930 | 4637 |
| 4931 NodeInfo info = *node->info(); | 4638 NodeInfo info = *node->info(); |
| 4932 | 4639 |
| 4933 if (FLAG_irregexp_native) { | 4640 if (FLAG_regexp_native) { |
| 4934 #ifdef ARM | 4641 #ifdef ARM |
| 4935 // Unimplemented, fall-through to bytecode implementation. | 4642 // Unimplemented, fall-through to bytecode implementation. |
| 4936 #else // IA32 | 4643 #else // IA32 |
| 4937 RegExpMacroAssemblerIA32::Mode mode; | 4644 RegExpMacroAssemblerIA32::Mode mode; |
| 4938 if (is_ascii) { | 4645 if (is_ascii) { |
| 4939 mode = RegExpMacroAssemblerIA32::ASCII; | 4646 mode = RegExpMacroAssemblerIA32::ASCII; |
| 4940 } else { | 4647 } else { |
| 4941 mode = RegExpMacroAssemblerIA32::UC16; | 4648 mode = RegExpMacroAssemblerIA32::UC16; |
| 4942 } | 4649 } |
| 4943 RegExpMacroAssemblerIA32 macro_assembler(mode, | 4650 RegExpMacroAssemblerIA32 macro_assembler(mode, |
| 4944 (data->capture_count + 1) * 2); | 4651 (data->capture_count + 1) * 2); |
| 4945 return compiler.Assemble(¯o_assembler, | 4652 return compiler.Assemble(¯o_assembler, |
| 4946 node, | 4653 node, |
| 4947 data->capture_count, | 4654 data->capture_count, |
| 4948 pattern); | 4655 pattern); |
| 4949 #endif | 4656 #endif |
| 4950 } | 4657 } |
| 4951 EmbeddedVector<byte, 1024> codes; | 4658 EmbeddedVector<byte, 1024> codes; |
| 4952 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4659 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 4953 return compiler.Assemble(¯o_assembler, | 4660 return compiler.Assemble(¯o_assembler, |
| 4954 node, | 4661 node, |
| 4955 data->capture_count, | 4662 data->capture_count, |
| 4956 pattern); | 4663 pattern); |
| 4957 } | 4664 } |
| 4958 | 4665 |
| 4959 | 4666 |
| 4960 }} // namespace v8::internal | 4667 }} // namespace v8::internal |
| OLD | NEW |