| 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 | 54 |
| 55 namespace v8 { namespace internal { | 55 namespace v8 { namespace internal { |
| 56 | 56 |
| 57 | 57 |
| 58 String* RegExpImpl::last_ascii_string_ = NULL; | |
| 59 String* RegExpImpl::two_byte_cached_string_ = NULL; | |
| 60 | |
| 61 | |
| 62 void RegExpImpl::NewSpaceCollectionPrologue() { | |
| 63 // The two byte string is always in the old space. The Ascii string may be | |
| 64 // in either place. If it is in the old space we don't need to do anything. | |
| 65 if (Heap::InNewSpace(last_ascii_string_)) { | |
| 66 // Invalidate the cache. | |
| 67 last_ascii_string_ = NULL; | |
| 68 two_byte_cached_string_ = NULL; | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 | |
| 73 void RegExpImpl::OldSpaceCollectionPrologue() { | |
| 74 last_ascii_string_ = NULL; | |
| 75 two_byte_cached_string_ = NULL; | |
| 76 } | |
| 77 | |
| 78 | |
| 79 Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor, | 58 Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor, |
| 80 Handle<String> pattern, | 59 Handle<String> pattern, |
| 81 Handle<String> flags, | 60 Handle<String> flags, |
| 82 bool* has_pending_exception) { | 61 bool* has_pending_exception) { |
| 83 // Ensure that the constructor function has been loaded. | 62 // Ensure that the constructor function has been loaded. |
| 84 if (!constructor->IsLoaded()) { | 63 if (!constructor->IsLoaded()) { |
| 85 LoadLazy(constructor, has_pending_exception); | 64 LoadLazy(constructor, has_pending_exception); |
| 86 if (*has_pending_exception) return Handle<Object>(); | 65 if (*has_pending_exception) return Handle<Object>(); |
| 87 } | 66 } |
| 88 // Call the construct code with 2 arguments. | 67 // Call the construct code with 2 arguments. |
| 89 Object** argv[2] = { Handle<Object>::cast(pattern).location(), | 68 Object** argv[2] = { Handle<Object>::cast(pattern).location(), |
| 90 Handle<Object>::cast(flags).location() }; | 69 Handle<Object>::cast(flags).location() }; |
| 91 return Execution::New(constructor, 2, argv, has_pending_exception); | 70 return Execution::New(constructor, 2, argv, has_pending_exception); |
| 92 } | 71 } |
| 93 | 72 |
| 94 | 73 |
| 95 // Converts a source string to a 16 bit flat string or a SlicedString containing | |
| 96 // a 16 bit flat string). | |
| 97 Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) { | |
| 98 if (*subject == last_ascii_string_) { | |
| 99 ASSERT(two_byte_cached_string_ != NULL); | |
| 100 return Handle<String>(String::cast(two_byte_cached_string_)); | |
| 101 } | |
| 102 Handle<String> two_byte_string = StringToTwoByte(subject); | |
| 103 last_ascii_string_ = *subject; | |
| 104 two_byte_cached_string_ = *two_byte_string; | |
| 105 return two_byte_string; | |
| 106 } | |
| 107 | |
| 108 | |
| 109 // Converts a source string to a 16 bit flat string or a SlicedString containing | |
| 110 // a 16 bit flat string). | |
| 111 Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) { | |
| 112 StringShape shape(*pattern); | |
| 113 if (!pattern->IsFlat(shape)) { | |
| 114 FlattenString(pattern); | |
| 115 shape = StringShape(*pattern); | |
| 116 } | |
| 117 Handle<String> flat_string(shape.IsCons() ? | |
| 118 String::cast(ConsString::cast(*pattern)->first()) : | |
| 119 *pattern); | |
| 120 ASSERT(flat_string->IsString()); | |
| 121 StringShape flat_shape(*flat_string); | |
| 122 ASSERT(!flat_shape.IsCons()); | |
| 123 ASSERT(flat_shape.IsSequential() || | |
| 124 flat_shape.IsSliced() || | |
| 125 flat_shape.IsExternal()); | |
| 126 if (!flat_shape.IsAsciiRepresentation()) { | |
| 127 return flat_string; | |
| 128 } | |
| 129 | |
| 130 int len = flat_string->length(flat_shape); | |
| 131 Handle<String> two_byte_string = | |
| 132 Factory::NewRawTwoByteString(len, TENURED); | |
| 133 uc16* dest = SeqTwoByteString::cast(*two_byte_string)->GetChars(); | |
| 134 String::WriteToFlat(*flat_string, flat_shape, dest, 0, len); | |
| 135 return two_byte_string; | |
| 136 } | |
| 137 | |
| 138 | |
| 139 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) { | 74 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) { |
| 140 int flags = JSRegExp::NONE; | 75 int flags = JSRegExp::NONE; |
| 141 StringShape shape(*str); | 76 for (int i = 0; i < str->length(); i++) { |
| 142 for (int i = 0; i < str->length(shape); i++) { | 77 switch (str->Get(i)) { |
| 143 switch (str->Get(shape, i)) { | |
| 144 case 'i': | 78 case 'i': |
| 145 flags |= JSRegExp::IGNORE_CASE; | 79 flags |= JSRegExp::IGNORE_CASE; |
| 146 break; | 80 break; |
| 147 case 'g': | 81 case 'g': |
| 148 flags |= JSRegExp::GLOBAL; | 82 flags |= JSRegExp::GLOBAL; |
| 149 break; | 83 break; |
| 150 case 'm': | 84 case 'm': |
| 151 flags |= JSRegExp::MULTILINE; | 85 flags |= JSRegExp::MULTILINE; |
| 152 break; | 86 break; |
| 153 } | 87 } |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 } | 348 } |
| 415 return true; | 349 return true; |
| 416 } | 350 } |
| 417 | 351 |
| 418 // Compile the RegExp. | 352 // Compile the RegExp. |
| 419 ZoneScope zone_scope(DELETE_ON_EXIT); | 353 ZoneScope zone_scope(DELETE_ON_EXIT); |
| 420 | 354 |
| 421 JSRegExp::Flags flags = re->GetFlags(); | 355 JSRegExp::Flags flags = re->GetFlags(); |
| 422 | 356 |
| 423 Handle<String> pattern(re->Pattern()); | 357 Handle<String> pattern(re->Pattern()); |
| 424 if (!pattern->IsFlat(StringShape(*pattern))) { | 358 if (!pattern->IsFlat()) { |
| 425 FlattenString(pattern); | 359 FlattenString(pattern); |
| 426 } | 360 } |
| 427 | 361 |
| 428 RegExpCompileData compile_data; | 362 RegExpCompileData compile_data; |
| 429 FlatStringReader reader(pattern); | 363 FlatStringReader reader(pattern); |
| 430 if (!ParseRegExp(&reader, flags.is_multiline(), &compile_data)) { | 364 if (!ParseRegExp(&reader, flags.is_multiline(), &compile_data)) { |
| 431 // Throw an exception if we fail to parse the pattern. | 365 // Throw an exception if we fail to parse the pattern. |
| 432 // THIS SHOULD NOT HAPPEN. We already parsed it successfully once. | 366 // THIS SHOULD NOT HAPPEN. We already parsed it successfully once. |
| 433 ThrowRegExpException(re, | 367 ThrowRegExpException(re, |
| 434 pattern, | 368 pattern, |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 int previous_index = index; | 479 int previous_index = index; |
| 546 | 480 |
| 547 #ifdef DEBUG | 481 #ifdef DEBUG |
| 548 if (FLAG_trace_regexp_bytecodes) { | 482 if (FLAG_trace_regexp_bytecodes) { |
| 549 String* pattern = regexp->Pattern(); | 483 String* pattern = regexp->Pattern(); |
| 550 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); | 484 PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString())); |
| 551 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); | 485 PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString())); |
| 552 } | 486 } |
| 553 #endif | 487 #endif |
| 554 | 488 |
| 555 if (!subject->IsFlat(StringShape(*subject))) { | 489 if (!subject->IsFlat()) { |
| 556 FlattenString(subject); | 490 FlattenString(subject); |
| 557 } | 491 } |
| 558 | 492 |
| 559 last_match_info->EnsureSize(number_of_capture_registers + kLastMatchOverhead); | 493 last_match_info->EnsureSize(number_of_capture_registers + kLastMatchOverhead); |
| 560 | 494 |
| 561 return IrregexpExecOnce(re_data, | 495 return IrregexpExecOnce(re_data, |
| 562 number_of_capture_registers, | 496 number_of_capture_registers, |
| 563 last_match_info, | 497 last_match_info, |
| 564 subject, | 498 subject, |
| 565 previous_index, | 499 previous_index, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 583 int number_of_capture_registers = | 517 int number_of_capture_registers = |
| 584 (IrregexpNumberOfCaptures(*irregexp) + 1) * 2; | 518 (IrregexpNumberOfCaptures(*irregexp) + 1) * 2; |
| 585 OffsetsVector offsets(number_of_capture_registers); | 519 OffsetsVector offsets(number_of_capture_registers); |
| 586 | 520 |
| 587 int previous_index = 0; | 521 int previous_index = 0; |
| 588 | 522 |
| 589 Handle<JSArray> result = Factory::NewJSArray(0); | 523 Handle<JSArray> result = Factory::NewJSArray(0); |
| 590 int result_length = 0; | 524 int result_length = 0; |
| 591 Handle<Object> matches; | 525 Handle<Object> matches; |
| 592 | 526 |
| 593 if (!subject->IsFlat(StringShape(*subject))) { | 527 if (!subject->IsFlat()) { |
| 594 FlattenString(subject); | 528 FlattenString(subject); |
| 595 } | 529 } |
| 596 | 530 |
| 597 last_match_info->EnsureSize(number_of_capture_registers + kLastMatchOverhead); | 531 last_match_info->EnsureSize(number_of_capture_registers + kLastMatchOverhead); |
| 598 | 532 |
| 599 while (true) { | 533 while (true) { |
| 600 if (previous_index > subject->length() || previous_index < 0) { | 534 if (previous_index > subject->length() || previous_index < 0) { |
| 601 // Per ECMA-262 15.10.6.2, if the previous index is greater than the | 535 // Per ECMA-262 15.10.6.2, if the previous index is greater than the |
| 602 // string length, there is no match. | 536 // string length, there is no match. |
| 603 return result; | 537 return result; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 } | 586 } |
| 653 | 587 |
| 654 | 588 |
| 655 Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> regexp, | 589 Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> regexp, |
| 656 int number_of_capture_registers, | 590 int number_of_capture_registers, |
| 657 Handle<JSArray> last_match_info, | 591 Handle<JSArray> last_match_info, |
| 658 Handle<String> subject, | 592 Handle<String> subject, |
| 659 int previous_index, | 593 int previous_index, |
| 660 int* offsets_vector, | 594 int* offsets_vector, |
| 661 int offsets_vector_length) { | 595 int offsets_vector_length) { |
| 662 StringShape shape(*subject); | 596 ASSERT(subject->IsFlat()); |
| 663 ASSERT(subject->IsFlat(shape)); | 597 bool is_ascii = StringShape(*subject).IsAsciiRepresentation(); |
| 664 bool is_ascii = shape.IsAsciiRepresentation(); | |
| 665 bool rc; | 598 bool rc; |
| 666 | 599 |
| 667 Handle<String> original_subject = subject; | 600 Handle<String> original_subject = subject; |
| 668 if (UseNativeRegexp()) { | 601 if (UseNativeRegexp()) { |
| 669 #ifdef ARM | 602 #ifdef ARM |
| 670 UNREACHABLE(); | 603 UNREACHABLE(); |
| 671 #else | 604 #else |
| 672 Handle<Code> code(RegExpImpl::IrregexpNativeCode(*regexp, is_ascii)); | 605 Handle<Code> code(RegExpImpl::IrregexpNativeCode(*regexp, is_ascii)); |
| 673 RegExpMacroAssemblerIA32::Result res = | 606 RegExpMacroAssemblerIA32::Result res = |
| 674 RegExpMacroAssemblerIA32::Match(code, | 607 RegExpMacroAssemblerIA32::Match(code, |
| (...skipping 4011 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4686 EmbeddedVector<byte, 1024> codes; | 4619 EmbeddedVector<byte, 1024> codes; |
| 4687 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4620 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 4688 return compiler.Assemble(¯o_assembler, | 4621 return compiler.Assemble(¯o_assembler, |
| 4689 node, | 4622 node, |
| 4690 data->capture_count, | 4623 data->capture_count, |
| 4691 pattern); | 4624 pattern); |
| 4692 } | 4625 } |
| 4693 | 4626 |
| 4694 | 4627 |
| 4695 }} // namespace v8::internal | 4628 }} // namespace v8::internal |
| OLD | NEW |