Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: src/runtime.cc

Issue 10825472: Revert r12258, r12300 and r12302 (global regexp). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/mips/code-stubs-mips.cc ('k') | src/x64/code-stubs-x64.cc » ('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 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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 2556 matching lines...) Expand 10 before | Expand all | Expand 10 after
2567 FixedArrayBuilder array_builder_; 2567 FixedArrayBuilder array_builder_;
2568 Handle<String> subject_; 2568 Handle<String> subject_;
2569 int character_count_; 2569 int character_count_;
2570 bool is_ascii_; 2570 bool is_ascii_;
2571 }; 2571 };
2572 2572
2573 2573
2574 class CompiledReplacement { 2574 class CompiledReplacement {
2575 public: 2575 public:
2576 explicit CompiledReplacement(Zone* zone) 2576 explicit CompiledReplacement(Zone* zone)
2577 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} 2577 : parts_(1, zone), replacement_substrings_(0, zone),
2578 simple_hint_(false),
2579 zone_(zone) {}
2578 2580
2579 // Return whether the replacement is simple. 2581 void Compile(Handle<String> replacement,
2580 bool Compile(Handle<String> replacement,
2581 int capture_count, 2582 int capture_count,
2582 int subject_length); 2583 int subject_length);
2583 2584
2584 // Use Apply only if Compile returned false.
2585 void Apply(ReplacementStringBuilder* builder, 2585 void Apply(ReplacementStringBuilder* builder,
2586 int match_from, 2586 int match_from,
2587 int match_to, 2587 int match_to,
2588 int32_t* match); 2588 Handle<JSArray> last_match_info);
2589 2589
2590 // Number of distinct parts of the replacement pattern. 2590 // Number of distinct parts of the replacement pattern.
2591 int parts() { 2591 int parts() {
2592 return parts_.length(); 2592 return parts_.length();
2593 } 2593 }
2594 2594
2595 bool simple_hint() {
2596 return simple_hint_;
2597 }
2598
2595 Zone* zone() const { return zone_; } 2599 Zone* zone() const { return zone_; }
2596 2600
2597 private: 2601 private:
2598 enum PartType { 2602 enum PartType {
2599 SUBJECT_PREFIX = 1, 2603 SUBJECT_PREFIX = 1,
2600 SUBJECT_SUFFIX, 2604 SUBJECT_SUFFIX,
2601 SUBJECT_CAPTURE, 2605 SUBJECT_CAPTURE,
2602 REPLACEMENT_SUBSTRING, 2606 REPLACEMENT_SUBSTRING,
2603 REPLACEMENT_STRING, 2607 REPLACEMENT_STRING,
2604 2608
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2645 // tag == REPLACEMENT_STRING: data is index into array of substrings 2649 // tag == REPLACEMENT_STRING: data is index into array of substrings
2646 // of the replacement string. 2650 // of the replacement string.
2647 // tag <= 0: Temporary representation of the substring of the replacement 2651 // tag <= 0: Temporary representation of the substring of the replacement
2648 // string ranging over -tag .. data. 2652 // string ranging over -tag .. data.
2649 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 2653 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2650 // substring objects. 2654 // substring objects.
2651 int data; 2655 int data;
2652 }; 2656 };
2653 2657
2654 template<typename Char> 2658 template<typename Char>
2655 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 2659 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2656 Vector<Char> characters, 2660 Vector<Char> characters,
2657 int capture_count, 2661 int capture_count,
2658 int subject_length, 2662 int subject_length,
2659 Zone* zone) { 2663 Zone* zone) {
2660 int length = characters.length(); 2664 int length = characters.length();
2661 int last = 0; 2665 int last = 0;
2662 for (int i = 0; i < length; i++) { 2666 for (int i = 0; i < length; i++) {
2663 Char c = characters[i]; 2667 Char c = characters[i];
2664 if (c == '$') { 2668 if (c == '$') {
2665 int next_index = i + 1; 2669 int next_index = i + 1;
2666 if (next_index == length) { // No next character! 2670 if (next_index == length) { // No next character!
2667 break; 2671 break;
2668 } 2672 }
2669 Char c2 = characters[next_index]; 2673 Char c2 = characters[next_index];
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
2743 break; 2747 break;
2744 } 2748 }
2745 default: 2749 default:
2746 i = next_index; 2750 i = next_index;
2747 break; 2751 break;
2748 } 2752 }
2749 } 2753 }
2750 } 2754 }
2751 if (length > last) { 2755 if (length > last) {
2752 if (last == 0) { 2756 if (last == 0) {
2753 // Replacement is simple. Do not use Apply to do the replacement. 2757 parts->Add(ReplacementPart::ReplacementString(), zone);
2754 return true; 2758 return true;
2755 } else { 2759 } else {
2756 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); 2760 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
2757 } 2761 }
2758 } 2762 }
2759 return false; 2763 return false;
2760 } 2764 }
2761 2765
2762 ZoneList<ReplacementPart> parts_; 2766 ZoneList<ReplacementPart> parts_;
2763 ZoneList<Handle<String> > replacement_substrings_; 2767 ZoneList<Handle<String> > replacement_substrings_;
2768 bool simple_hint_;
2764 Zone* zone_; 2769 Zone* zone_;
2765 }; 2770 };
2766 2771
2767 2772
2768 bool CompiledReplacement::Compile(Handle<String> replacement, 2773 void CompiledReplacement::Compile(Handle<String> replacement,
2769 int capture_count, 2774 int capture_count,
2770 int subject_length) { 2775 int subject_length) {
2771 { 2776 {
2772 AssertNoAllocation no_alloc; 2777 AssertNoAllocation no_alloc;
2773 String::FlatContent content = replacement->GetFlatContent(); 2778 String::FlatContent content = replacement->GetFlatContent();
2774 ASSERT(content.IsFlat()); 2779 ASSERT(content.IsFlat());
2775 bool simple = false;
2776 if (content.IsAscii()) { 2780 if (content.IsAscii()) {
2777 simple = ParseReplacementPattern(&parts_, 2781 simple_hint_ = ParseReplacementPattern(&parts_,
2778 content.ToAsciiVector(), 2782 content.ToAsciiVector(),
2779 capture_count, 2783 capture_count,
2780 subject_length, 2784 subject_length,
2781 zone()); 2785 zone());
2782 } else { 2786 } else {
2783 ASSERT(content.IsTwoByte()); 2787 ASSERT(content.IsTwoByte());
2784 simple = ParseReplacementPattern(&parts_, 2788 simple_hint_ = ParseReplacementPattern(&parts_,
2785 content.ToUC16Vector(), 2789 content.ToUC16Vector(),
2786 capture_count, 2790 capture_count,
2787 subject_length, 2791 subject_length,
2788 zone()); 2792 zone());
2789 } 2793 }
2790 if (simple) return true;
2791 } 2794 }
2792
2793 Isolate* isolate = replacement->GetIsolate(); 2795 Isolate* isolate = replacement->GetIsolate();
2794 // Find substrings of replacement string and create them as String objects. 2796 // Find substrings of replacement string and create them as String objects.
2795 int substring_index = 0; 2797 int substring_index = 0;
2796 for (int i = 0, n = parts_.length(); i < n; i++) { 2798 for (int i = 0, n = parts_.length(); i < n; i++) {
2797 int tag = parts_[i].tag; 2799 int tag = parts_[i].tag;
2798 if (tag <= 0) { // A replacement string slice. 2800 if (tag <= 0) { // A replacement string slice.
2799 int from = -tag; 2801 int from = -tag;
2800 int to = parts_[i].data; 2802 int to = parts_[i].data;
2801 replacement_substrings_.Add( 2803 replacement_substrings_.Add(
2802 isolate->factory()->NewSubString(replacement, from, to), zone()); 2804 isolate->factory()->NewSubString(replacement, from, to), zone());
2803 parts_[i].tag = REPLACEMENT_SUBSTRING; 2805 parts_[i].tag = REPLACEMENT_SUBSTRING;
2804 parts_[i].data = substring_index; 2806 parts_[i].data = substring_index;
2805 substring_index++; 2807 substring_index++;
2806 } else if (tag == REPLACEMENT_STRING) { 2808 } else if (tag == REPLACEMENT_STRING) {
2807 replacement_substrings_.Add(replacement, zone()); 2809 replacement_substrings_.Add(replacement, zone());
2808 parts_[i].data = substring_index; 2810 parts_[i].data = substring_index;
2809 substring_index++; 2811 substring_index++;
2810 } 2812 }
2811 } 2813 }
2812 return false;
2813 } 2814 }
2814 2815
2815 2816
2816 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 2817 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2817 int match_from, 2818 int match_from,
2818 int match_to, 2819 int match_to,
2819 int32_t* match) { 2820 Handle<JSArray> last_match_info) {
2820 ASSERT_LT(0, parts_.length());
2821 for (int i = 0, n = parts_.length(); i < n; i++) { 2821 for (int i = 0, n = parts_.length(); i < n; i++) {
2822 ReplacementPart part = parts_[i]; 2822 ReplacementPart part = parts_[i];
2823 switch (part.tag) { 2823 switch (part.tag) {
2824 case SUBJECT_PREFIX: 2824 case SUBJECT_PREFIX:
2825 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 2825 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2826 break; 2826 break;
2827 case SUBJECT_SUFFIX: { 2827 case SUBJECT_SUFFIX: {
2828 int subject_length = part.data; 2828 int subject_length = part.data;
2829 if (match_to < subject_length) { 2829 if (match_to < subject_length) {
2830 builder->AddSubjectSlice(match_to, subject_length); 2830 builder->AddSubjectSlice(match_to, subject_length);
2831 } 2831 }
2832 break; 2832 break;
2833 } 2833 }
2834 case SUBJECT_CAPTURE: { 2834 case SUBJECT_CAPTURE: {
2835 int capture = part.data; 2835 int capture = part.data;
2836 int from = match[capture * 2]; 2836 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2837 int to = match[capture * 2 + 1]; 2837 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2838 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2838 if (from >= 0 && to > from) { 2839 if (from >= 0 && to > from) {
2839 builder->AddSubjectSlice(from, to); 2840 builder->AddSubjectSlice(from, to);
2840 } 2841 }
2841 break; 2842 break;
2842 } 2843 }
2843 case REPLACEMENT_SUBSTRING: 2844 case REPLACEMENT_SUBSTRING:
2844 case REPLACEMENT_STRING: 2845 case REPLACEMENT_STRING:
2845 builder->AddString(replacement_substrings_[part.data]); 2846 builder->AddString(replacement_substrings_[part.data]);
2846 break; 2847 break;
2847 default: 2848 default:
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
2949 pattern_content.ToUC16Vector(), 2950 pattern_content.ToUC16Vector(),
2950 indices, 2951 indices,
2951 limit, 2952 limit,
2952 zone); 2953 zone);
2953 } 2954 }
2954 } 2955 }
2955 } 2956 }
2956 } 2957 }
2957 2958
2958 2959
2960 // Two smis before and after the match, for very long strings.
2961 const int kMaxBuilderEntriesPerRegExpMatch = 5;
2962
2963
2964 static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2965 Handle<JSArray> last_match_info,
2966 int match_start,
2967 int match_end) {
2968 // Fill last_match_info with a single capture.
2969 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2970 AssertNoAllocation no_gc;
2971 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2972 RegExpImpl::SetLastCaptureCount(elements, 2);
2973 RegExpImpl::SetLastInput(elements, *subject);
2974 RegExpImpl::SetLastSubject(elements, *subject);
2975 RegExpImpl::SetCapture(elements, 0, match_start);
2976 RegExpImpl::SetCapture(elements, 1, match_end);
2977 }
2978
2979
2980 template <typename SubjectChar, typename PatternChar>
2981 static bool SearchStringMultiple(Isolate* isolate,
2982 Vector<const SubjectChar> subject,
2983 Vector<const PatternChar> pattern,
2984 String* pattern_string,
2985 FixedArrayBuilder* builder,
2986 int* match_pos) {
2987 int pos = *match_pos;
2988 int subject_length = subject.length();
2989 int pattern_length = pattern.length();
2990 int max_search_start = subject_length - pattern_length;
2991 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2992 while (pos <= max_search_start) {
2993 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2994 *match_pos = pos;
2995 return false;
2996 }
2997 // Position of end of previous match.
2998 int match_end = pos + pattern_length;
2999 int new_pos = search.Search(subject, match_end);
3000 if (new_pos >= 0) {
3001 // A match.
3002 if (new_pos > match_end) {
3003 ReplacementStringBuilder::AddSubjectSlice(builder,
3004 match_end,
3005 new_pos);
3006 }
3007 pos = new_pos;
3008 builder->Add(pattern_string);
3009 } else {
3010 break;
3011 }
3012 }
3013
3014 if (pos < max_search_start) {
3015 ReplacementStringBuilder::AddSubjectSlice(builder,
3016 pos + pattern_length,
3017 subject_length);
3018 }
3019 *match_pos = pos;
3020 return true;
3021 }
3022
3023
3024
3025
2959 template<typename ResultSeqString> 3026 template<typename ResultSeqString>
2960 MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( 3027 MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString(
2961 Isolate* isolate, 3028 Isolate* isolate,
2962 Handle<String> subject, 3029 Handle<String> subject,
2963 Handle<JSRegExp> pattern_regexp, 3030 Handle<JSRegExp> pattern_regexp,
2964 Handle<String> replacement, 3031 Handle<String> replacement,
2965 Handle<JSArray> last_match_info) { 3032 Handle<JSArray> last_match_info,
3033 Zone* zone) {
2966 ASSERT(subject->IsFlat()); 3034 ASSERT(subject->IsFlat());
2967 ASSERT(replacement->IsFlat()); 3035 ASSERT(replacement->IsFlat());
2968 3036
2969 Zone* zone = isolate->runtime_zone(); 3037 ZoneScope zone_space(isolate->runtime_zone(), DELETE_ON_EXIT);
2970 ZoneScope zone_space(zone, DELETE_ON_EXIT); 3038 ZoneList<int> indices(8, isolate->runtime_zone());
2971 ZoneList<int> indices(8, zone);
2972 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 3039 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2973 String* pattern = 3040 String* pattern =
2974 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 3041 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2975 int subject_len = subject->length(); 3042 int subject_len = subject->length();
2976 int pattern_len = pattern->length(); 3043 int pattern_len = pattern->length();
2977 int replacement_len = replacement->length(); 3044 int replacement_len = replacement->length();
2978 3045
2979 FindStringIndicesDispatch( 3046 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff,
2980 isolate, *subject, pattern, &indices, 0xffffffff, zone); 3047 zone);
2981 3048
2982 int matches = indices.length(); 3049 int matches = indices.length();
2983 if (matches == 0) return *subject; 3050 if (matches == 0) return *subject;
2984 3051
2985 // Detect integer overflow. 3052 // Detect integer overflow.
2986 int64_t result_len_64 = 3053 int64_t result_len_64 =
2987 (static_cast<int64_t>(replacement_len) - 3054 (static_cast<int64_t>(replacement_len) -
2988 static_cast<int64_t>(pattern_len)) * 3055 static_cast<int64_t>(pattern_len)) *
2989 static_cast<int64_t>(matches) + 3056 static_cast<int64_t>(matches) +
2990 static_cast<int64_t>(subject_len); 3057 static_cast<int64_t>(subject_len);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
3025 subject_pos = indices.at(i) + pattern_len; 3092 subject_pos = indices.at(i) + pattern_len;
3026 } 3093 }
3027 // Add remaining subject content at the end. 3094 // Add remaining subject content at the end.
3028 if (subject_pos < subject_len) { 3095 if (subject_pos < subject_len) {
3029 String::WriteToFlat(*subject, 3096 String::WriteToFlat(*subject,
3030 result->GetChars() + result_pos, 3097 result->GetChars() + result_pos,
3031 subject_pos, 3098 subject_pos,
3032 subject_len); 3099 subject_len);
3033 } 3100 }
3034 3101
3035 int32_t match_indices[] = { indices.at(matches - 1), 3102 SetLastMatchInfoNoCaptures(subject,
3036 indices.at(matches - 1) + pattern_len }; 3103 last_match_info,
3037 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); 3104 indices.at(matches - 1),
3105 indices.at(matches - 1) + pattern_len);
3038 3106
3039 return *result; 3107 return *result;
3040 } 3108 }
3041 3109
3042 3110
3043 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( 3111 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
3044 Isolate* isolate, 3112 Isolate* isolate,
3045 Handle<String> subject, 3113 String* subject,
3046 Handle<JSRegExp> regexp, 3114 JSRegExp* regexp,
3047 Handle<String> replacement, 3115 String* replacement,
3048 Handle<JSArray> last_match_info) { 3116 JSArray* last_match_info,
3117 Zone* zone) {
3049 ASSERT(subject->IsFlat()); 3118 ASSERT(subject->IsFlat());
3050 ASSERT(replacement->IsFlat()); 3119 ASSERT(replacement->IsFlat());
3051 3120
3052 bool is_global = regexp->GetFlags().is_global(); 3121 HandleScope handles(isolate);
ulan 2012/08/21 09:43:40 Empty line is missing here.
Yang 2012/08/21 09:46:10 Done.
3053 int capture_count = regexp->CaptureCount(); 3122 int length = subject->length();
3054 int subject_length = subject->length(); 3123 Handle<String> subject_handle(subject);
3124 Handle<JSRegExp> regexp_handle(regexp);
3125 Handle<String> replacement_handle(replacement);
3126 Handle<JSArray> last_match_info_handle(last_match_info);
3127 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3128 subject_handle,
3129 0,
3130 last_match_info_handle);
3131 if (match.is_null()) {
3132 return Failure::Exception();
3133 }
3134 if (match->IsNull()) {
3135 return *subject_handle;
3136 }
3137
3138 int capture_count = regexp_handle->CaptureCount();
3055 3139
3056 // CompiledReplacement uses zone allocation. 3140 // CompiledReplacement uses zone allocation.
3057 Zone* zone = isolate->runtime_zone();
3058 ZoneScope zonescope(zone, DELETE_ON_EXIT); 3141 ZoneScope zonescope(zone, DELETE_ON_EXIT);
3059 CompiledReplacement compiled_replacement(zone); 3142 CompiledReplacement compiled_replacement(zone);
3060 bool simple_replace = compiled_replacement.Compile(replacement, 3143
3061 capture_count, 3144 compiled_replacement.Compile(replacement_handle,
3062 subject_length); 3145 capture_count,
3146 length);
3147
3148 bool is_global = regexp_handle->GetFlags().is_global();
3063 3149
3064 // Shortcut for simple non-regexp global replacements 3150 // Shortcut for simple non-regexp global replacements
3065 if (is_global && 3151 if (is_global &&
3066 regexp->TypeTag() == JSRegExp::ATOM && 3152 regexp_handle->TypeTag() == JSRegExp::ATOM &&
3067 simple_replace) { 3153 compiled_replacement.simple_hint()) {
3068 if (subject->HasOnlyAsciiChars()) { 3154 if (subject_handle->HasOnlyAsciiChars() &&
3155 replacement_handle->HasOnlyAsciiChars()) {
3069 return StringReplaceAtomRegExpWithString<SeqAsciiString>( 3156 return StringReplaceAtomRegExpWithString<SeqAsciiString>(
3070 isolate, subject, regexp, replacement, last_match_info); 3157 isolate,
3071 } else { 3158 subject_handle,
3159 regexp_handle,
3160 replacement_handle,
3161 last_match_info_handle,
3162 zone);
3163 } else {
3072 return StringReplaceAtomRegExpWithString<SeqTwoByteString>( 3164 return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
3073 isolate, subject, regexp, replacement, last_match_info); 3165 isolate,
3166 subject_handle,
3167 regexp_handle,
3168 replacement_handle,
3169 last_match_info_handle,
3170 zone);
3074 } 3171 }
3075 } 3172 }
3076 3173
3077 RegExpImpl::GlobalCache global_cache(regexp, subject, is_global, isolate);
3078 if (global_cache.HasException()) return Failure::Exception();
3079
3080 int32_t* current_match = global_cache.FetchNext();
3081 if (current_match == NULL) {
3082 if (global_cache.HasException()) return Failure::Exception();
3083 return *subject;
3084 }
3085
3086 // Guessing the number of parts that the final result string is built 3174 // Guessing the number of parts that the final result string is built
3087 // from. Global regexps can match any number of times, so we guess 3175 // from. Global regexps can match any number of times, so we guess
3088 // conservatively. 3176 // conservatively.
3089 int expected_parts = 3177 int expected_parts =
3090 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1; 3178 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
3091 ReplacementStringBuilder builder(isolate->heap(), 3179 ReplacementStringBuilder builder(isolate->heap(),
3092 subject, 3180 subject_handle,
3093 expected_parts); 3181 expected_parts);
3094 3182
3183 // Index of end of last match.
3184 int prev = 0;
3185
3186
3095 // Number of parts added by compiled replacement plus preceeding 3187 // Number of parts added by compiled replacement plus preceeding
3096 // string and possibly suffix after last match. It is possible for 3188 // string and possibly suffix after last match. It is possible for
3097 // all components to use two elements when encoded as two smis. 3189 // all components to use two elements when encoded as two smis.
3098 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 3190 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
3099 3191 bool matched = true;
3100 int prev = 0;
3101
3102 do { 3192 do {
3193 ASSERT(last_match_info_handle->HasFastObjectElements());
3194 // Increase the capacity of the builder before entering local handle-scope,
3195 // so its internal buffer can safely allocate a new handle if it grows.
3103 builder.EnsureCapacity(parts_added_per_loop); 3196 builder.EnsureCapacity(parts_added_per_loop);
3104 3197
3105 int start = current_match[0]; 3198 HandleScope loop_scope(isolate);
3106 int end = current_match[1]; 3199 int start, end;
3200 {
3201 AssertNoAllocation match_info_array_is_not_in_a_handle;
3202 FixedArray* match_info_array =
3203 FixedArray::cast(last_match_info_handle->elements());
3204
3205 ASSERT_EQ(capture_count * 2 + 2,
3206 RegExpImpl::GetLastCaptureCount(match_info_array));
3207 start = RegExpImpl::GetCapture(match_info_array, 0);
3208 end = RegExpImpl::GetCapture(match_info_array, 1);
3209 }
3107 3210
3108 if (prev < start) { 3211 if (prev < start) {
3109 builder.AddSubjectSlice(prev, start); 3212 builder.AddSubjectSlice(prev, start);
3110 } 3213 }
3214 compiled_replacement.Apply(&builder,
3215 start,
3216 end,
3217 last_match_info_handle);
3111 3218
3112 if (simple_replace) {
3113 builder.AddString(replacement);
3114 } else {
3115 compiled_replacement.Apply(&builder,
3116 start,
3117 end,
3118 current_match);
3119 }
3120 prev = end; 3219 prev = end;
3121 3220
3122 // Only continue checking for global regexps. 3221 // Only continue checking for global regexps.
3123 if (!is_global) break; 3222 if (!is_global) break;
3124 3223
3125 current_match = global_cache.FetchNext(); 3224 // Continue from where the match ended, unless it was an empty match.
3126 } while (current_match != NULL); 3225 int next = end;
3226 if (start == end) {
3227 next = end + 1;
3228 if (next > length) break;
3229 }
3127 3230
3128 if (global_cache.HasException()) return Failure::Exception(); 3231 match = RegExpImpl::Exec(regexp_handle,
3232 subject_handle,
3233 next,
3234 last_match_info_handle);
3235 if (match.is_null()) {
3236 return Failure::Exception();
3237 }
3238 matched = !match->IsNull();
3239 } while (matched);
3129 3240
3130 if (prev < subject_length) { 3241 if (prev < length) {
3131 builder.EnsureCapacity(2); 3242 builder.AddSubjectSlice(prev, length);
3132 builder.AddSubjectSlice(prev, subject_length);
3133 } 3243 }
3134 3244
3135 RegExpImpl::SetLastMatchInfo(last_match_info,
3136 subject,
3137 capture_count,
3138 global_cache.LastSuccessfulMatch());
3139
3140 return *(builder.ToString()); 3245 return *(builder.ToString());
3141 } 3246 }
3142 3247
3143 3248
3144 template <typename ResultSeqString> 3249 template <typename ResultSeqString>
3145 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( 3250 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
3146 Isolate* isolate, 3251 Isolate* isolate,
3147 Handle<String> subject, 3252 String* subject,
3148 Handle<JSRegExp> regexp, 3253 JSRegExp* regexp,
3149 Handle<JSArray> last_match_info) { 3254 JSArray* last_match_info,
3255 Zone* zone) {
3150 ASSERT(subject->IsFlat()); 3256 ASSERT(subject->IsFlat());
3151 3257
3152 bool is_global = regexp->GetFlags().is_global(); 3258 HandleScope handles(isolate);
3259
3260 Handle<String> subject_handle(subject);
3261 Handle<JSRegExp> regexp_handle(regexp);
3262 Handle<JSArray> last_match_info_handle(last_match_info);
3153 3263
3154 // Shortcut for simple non-regexp global replacements 3264 // Shortcut for simple non-regexp global replacements
3155 if (is_global && 3265 if (regexp_handle->GetFlags().is_global() &&
3156 regexp->TypeTag() == JSRegExp::ATOM) { 3266 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3157 Handle<String> empty_string(HEAP->empty_string()); 3267 Handle<String> empty_string_handle(HEAP->empty_string());
3158 if (subject->HasOnlyAsciiChars()) { 3268 if (subject_handle->HasOnlyAsciiChars()) {
3159 return StringReplaceAtomRegExpWithString<SeqAsciiString>( 3269 return StringReplaceAtomRegExpWithString<SeqAsciiString>(
3160 isolate, 3270 isolate,
3161 subject, 3271 subject_handle,
3162 regexp, 3272 regexp_handle,
3163 empty_string, 3273 empty_string_handle,
3164 last_match_info); 3274 last_match_info_handle,
3275 zone);
3165 } else { 3276 } else {
3166 return StringReplaceAtomRegExpWithString<SeqTwoByteString>( 3277 return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
3167 isolate, 3278 isolate,
3168 subject, 3279 subject_handle,
3169 regexp, 3280 regexp_handle,
3170 empty_string, 3281 empty_string_handle,
3171 last_match_info); 3282 last_match_info_handle,
3283 zone);
3172 } 3284 }
3173 } 3285 }
3174 3286
3175 RegExpImpl::GlobalCache global_cache(regexp, subject, is_global, isolate); 3287 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3176 if (global_cache.HasException()) return Failure::Exception(); 3288 subject_handle,
3289 0,
3290 last_match_info_handle);
3291 if (match.is_null()) return Failure::Exception();
3292 if (match->IsNull()) return *subject_handle;
3177 3293
3178 int32_t* current_match = global_cache.FetchNext(); 3294 ASSERT(last_match_info_handle->HasFastObjectElements());
3179 if (current_match == NULL) { 3295
3180 if (global_cache.HasException()) return Failure::Exception(); 3296 int start, end;
3181 return *subject; 3297 {
3298 AssertNoAllocation match_info_array_is_not_in_a_handle;
3299 FixedArray* match_info_array =
3300 FixedArray::cast(last_match_info_handle->elements());
3301
3302 start = RegExpImpl::GetCapture(match_info_array, 0);
3303 end = RegExpImpl::GetCapture(match_info_array, 1);
3182 } 3304 }
3183 3305
3184 int start = current_match[0]; 3306 bool global = regexp_handle->GetFlags().is_global();
3185 int end = current_match[1];
3186 int capture_count = regexp->CaptureCount();
3187 int subject_length = subject->length();
3188 3307
3189 int new_length = subject_length - (end - start); 3308 if (start == end && !global) return *subject_handle;
3190 if (new_length == 0) return isolate->heap()->empty_string();
3191 3309
3310 int length = subject_handle->length();
3311 int new_length = length - (end - start);
3312 if (new_length == 0) {
3313 return isolate->heap()->empty_string();
3314 }
3192 Handle<ResultSeqString> answer; 3315 Handle<ResultSeqString> answer;
3193 if (ResultSeqString::kHasAsciiEncoding) { 3316 if (ResultSeqString::kHasAsciiEncoding) {
3194 answer = Handle<ResultSeqString>::cast( 3317 answer = Handle<ResultSeqString>::cast(
3195 isolate->factory()->NewRawAsciiString(new_length)); 3318 isolate->factory()->NewRawAsciiString(new_length));
3196 } else { 3319 } else {
3197 answer = Handle<ResultSeqString>::cast( 3320 answer = Handle<ResultSeqString>::cast(
3198 isolate->factory()->NewRawTwoByteString(new_length)); 3321 isolate->factory()->NewRawTwoByteString(new_length));
3199 } 3322 }
3200 3323
3201 if (!is_global) { 3324 // If the regexp isn't global, only match once.
3202 RegExpImpl::SetLastMatchInfo( 3325 if (!global) {
3203 last_match_info, subject, capture_count, current_match); 3326 if (start > 0) {
3204 if (start == end) { 3327 String::WriteToFlat(*subject_handle,
3205 return *subject; 3328 answer->GetChars(),
3206 } else { 3329 0,
3207 if (start > 0) { 3330 start);
3208 String::WriteToFlat(*subject, answer->GetChars(), 0, start);
3209 }
3210 if (end < subject_length) {
3211 String::WriteToFlat(
3212 *subject, answer->GetChars() + start, end, subject_length);
3213 }
3214 return *answer;
3215 } 3331 }
3332 if (end < length) {
3333 String::WriteToFlat(*subject_handle,
3334 answer->GetChars() + start,
3335 end,
3336 length);
3337 }
3338 return *answer;
3216 } 3339 }
3217 3340
3218 int prev = 0; 3341 int prev = 0; // Index of end of last match.
3342 int next = 0; // Start of next search (prev unless last match was empty).
3219 int position = 0; 3343 int position = 0;
3220 3344
3221 do { 3345 do {
3222 start = current_match[0];
3223 end = current_match[1];
3224 if (prev < start) { 3346 if (prev < start) {
3225 // Add substring subject[prev;start] to answer string. 3347 // Add substring subject[prev;start] to answer string.
3226 String::WriteToFlat( 3348 String::WriteToFlat(*subject_handle,
3227 *subject, answer->GetChars() + position, prev, start); 3349 answer->GetChars() + position,
3350 prev,
3351 start);
3228 position += start - prev; 3352 position += start - prev;
3229 } 3353 }
3230 prev = end; 3354 prev = end;
3355 next = end;
3356 // Continue from where the match ended, unless it was an empty match.
3357 if (start == end) {
3358 next++;
3359 if (next > length) break;
3360 }
3361 match = RegExpImpl::Exec(regexp_handle,
3362 subject_handle,
3363 next,
3364 last_match_info_handle);
3365 if (match.is_null()) return Failure::Exception();
3366 if (match->IsNull()) break;
3231 3367
3232 current_match = global_cache.FetchNext(); 3368 ASSERT(last_match_info_handle->HasFastObjectElements());
3233 } while (current_match != NULL); 3369 HandleScope loop_scope(isolate);
3370 {
3371 AssertNoAllocation match_info_array_is_not_in_a_handle;
3372 FixedArray* match_info_array =
3373 FixedArray::cast(last_match_info_handle->elements());
3374 start = RegExpImpl::GetCapture(match_info_array, 0);
3375 end = RegExpImpl::GetCapture(match_info_array, 1);
3376 }
3377 } while (true);
3234 3378
3235 if (global_cache.HasException()) return Failure::Exception(); 3379 if (prev < length) {
3236
3237 RegExpImpl::SetLastMatchInfo(last_match_info,
3238 subject,
3239 capture_count,
3240 global_cache.LastSuccessfulMatch());
3241
3242 if (prev < subject_length) {
3243 // Add substring subject[prev;length] to answer string. 3380 // Add substring subject[prev;length] to answer string.
3244 String::WriteToFlat( 3381 String::WriteToFlat(*subject_handle,
3245 *subject, answer->GetChars() + position, prev, subject_length); 3382 answer->GetChars() + position,
3246 position += subject_length - prev; 3383 prev,
3384 length);
3385 position += length - prev;
3247 } 3386 }
3248 3387
3249 if (position == 0) return isolate->heap()->empty_string(); 3388 if (position == 0) {
3389 return isolate->heap()->empty_string();
3390 }
3250 3391
3251 // Shorten string and fill 3392 // Shorten string and fill
3252 int string_size = ResultSeqString::SizeFor(position); 3393 int string_size = ResultSeqString::SizeFor(position);
3253 int allocated_string_size = ResultSeqString::SizeFor(new_length); 3394 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3254 int delta = allocated_string_size - string_size; 3395 int delta = allocated_string_size - string_size;
3255 3396
3256 answer->set_length(position); 3397 answer->set_length(position);
3257 if (delta == 0) return *answer; 3398 if (delta == 0) return *answer;
3258 3399
3259 Address end_of_string = answer->address() + string_size; 3400 Address end_of_string = answer->address() + string_size;
3260 isolate->heap()->CreateFillerObjectAt(end_of_string, delta); 3401 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
3261 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { 3402 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3262 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); 3403 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
3263 } 3404 }
3264 3405
3265 return *answer; 3406 return *answer;
3266 } 3407 }
3267 3408
3268 3409
3269 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { 3410 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
3270 ASSERT(args.length() == 4); 3411 ASSERT(args.length() == 4);
3271 3412
3272 HandleScope scope(isolate); 3413 CONVERT_ARG_CHECKED(String, subject, 0);
3414 if (!subject->IsFlat()) {
3415 Object* flat_subject;
3416 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3417 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3418 return maybe_flat_subject;
3419 }
3420 }
3421 subject = String::cast(flat_subject);
3422 }
3273 3423
3274 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3424 CONVERT_ARG_CHECKED(String, replacement, 2);
3275 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); 3425 if (!replacement->IsFlat()) {
3276 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 3426 Object* flat_replacement;
3277 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 3427 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3428 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3429 return maybe_flat_replacement;
3430 }
3431 }
3432 replacement = String::cast(flat_replacement);
3433 }
3278 3434
3279 if (!subject->IsFlat()) subject = FlattenGetString(subject); 3435 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3280 3436 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
3281 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
3282 3437
3283 ASSERT(last_match_info->HasFastObjectElements()); 3438 ASSERT(last_match_info->HasFastObjectElements());
3284 3439
3440 Zone* zone = isolate->runtime_zone();
3285 if (replacement->length() == 0) { 3441 if (replacement->length() == 0) {
3286 if (subject->HasOnlyAsciiChars()) { 3442 if (subject->HasOnlyAsciiChars()) {
3287 return StringReplaceRegExpWithEmptyString<SeqAsciiString>( 3443 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
3288 isolate, subject, regexp, last_match_info); 3444 isolate, subject, regexp, last_match_info, zone);
3289 } else { 3445 } else {
3290 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( 3446 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
3291 isolate, subject, regexp, last_match_info); 3447 isolate, subject, regexp, last_match_info, zone);
3292 } 3448 }
3293 } 3449 }
3294 3450
3295 return StringReplaceRegExpWithString( 3451 return StringReplaceRegExpWithString(isolate,
3296 isolate, subject, regexp, replacement, last_match_info); 3452 subject,
3453 regexp,
3454 replacement,
3455 last_match_info,
3456 zone);
3297 } 3457 }
3298 3458
3299 3459
3300 Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate, 3460 Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3301 Handle<String> subject, 3461 Handle<String> subject,
3302 Handle<String> search, 3462 Handle<String> search,
3303 Handle<String> replace, 3463 Handle<String> replace,
3304 bool* found, 3464 bool* found,
3305 int recursion_limit) { 3465 int recursion_limit) {
3306 if (recursion_limit == 0) return Handle<String>::null(); 3466 if (recursion_limit == 0) return Handle<String>::null();
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
3609 3769
3610 3770
3611 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { 3771 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
3612 ASSERT_EQ(3, args.length()); 3772 ASSERT_EQ(3, args.length());
3613 3773
3614 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3774 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3615 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 3775 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3616 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); 3776 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
3617 HandleScope handles; 3777 HandleScope handles;
3618 3778
3619 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 3779 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3620 if (global_cache.HasException()) return Failure::Exception();
3621 3780
3622 int capture_count = regexp->CaptureCount(); 3781 if (match.is_null()) {
3782 return Failure::Exception();
3783 }
3784 if (match->IsNull()) {
3785 return isolate->heap()->null_value();
3786 }
3787 int length = subject->length();
3623 3788
3624 Zone* zone = isolate->runtime_zone(); 3789 Zone* zone = isolate->runtime_zone();
3625 ZoneScope zone_space(zone, DELETE_ON_EXIT); 3790 ZoneScope zone_space(zone, DELETE_ON_EXIT);
3626 ZoneList<int> offsets(8, zone); 3791 ZoneList<int> offsets(8, zone);
3627 3792 int start;
3628 while (true) { 3793 int end;
3629 int32_t* match = global_cache.FetchNext(); 3794 do {
3630 if (match == NULL) break; 3795 {
3631 offsets.Add(match[0], zone); // start 3796 AssertNoAllocation no_alloc;
3632 offsets.Add(match[1], zone); // end 3797 FixedArray* elements = FixedArray::cast(regexp_info->elements());
3633 } 3798 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3634 3799 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3635 if (global_cache.HasException()) return Failure::Exception(); 3800 }
3636 3801 offsets.Add(start, zone);
3637 if (offsets.length() == 0) { 3802 offsets.Add(end, zone);
3638 // Not a single match. 3803 if (start == end) if (++end > length) break;
3639 return isolate->heap()->null_value(); 3804 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
3640 } 3805 if (match.is_null()) {
3641 3806 return Failure::Exception();
3642 RegExpImpl::SetLastMatchInfo(regexp_info, 3807 }
3643 subject, 3808 } while (!match->IsNull());
3644 capture_count,
3645 global_cache.LastSuccessfulMatch());
3646
3647 int matches = offsets.length() / 2; 3809 int matches = offsets.length() / 2;
3648 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); 3810 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
3649 Handle<String> substring = 3811 Handle<String> substring = isolate->factory()->
3650 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); 3812 NewSubString(subject, offsets.at(0), offsets.at(1));
3651 elements->set(0, *substring); 3813 elements->set(0, *substring);
3652 for (int i = 1; i < matches; i++) { 3814 for (int i = 1; i < matches ; i++) {
3653 HandleScope temp_scope(isolate);
3654 int from = offsets.at(i * 2); 3815 int from = offsets.at(i * 2);
3655 int to = offsets.at(i * 2 + 1); 3816 int to = offsets.at(i * 2 + 1);
3656 Handle<String> substring = 3817 Handle<String> substring = isolate->factory()->
3657 isolate->factory()->NewProperSubString(subject, from, to); 3818 NewProperSubString(subject, from, to);
3658 elements->set(i, *substring); 3819 elements->set(i, *substring);
3659 } 3820 }
3660 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); 3821 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
3661 result->set_length(Smi::FromInt(matches)); 3822 result->set_length(Smi::FromInt(matches));
3662 return *result; 3823 return *result;
3663 } 3824 }
3664 3825
3665 3826
3666 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain 3827 static bool SearchStringMultiple(Isolate* isolate,
3667 // separate last match info. See comment on that function. 3828 Handle<String> subject,
3668 template<bool has_capture> 3829 Handle<String> pattern,
3669 static int SearchRegExpMultiple( 3830 Handle<JSArray> last_match_info,
3831 FixedArrayBuilder* builder) {
3832 ASSERT(subject->IsFlat());
3833 ASSERT(pattern->IsFlat());
3834
3835 // Treating as if a previous match was before first character.
3836 int match_pos = -pattern->length();
3837
3838 for (;;) { // Break when search complete.
3839 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3840 AssertNoAllocation no_gc;
3841 String::FlatContent subject_content = subject->GetFlatContent();
3842 String::FlatContent pattern_content = pattern->GetFlatContent();
3843 if (subject_content.IsAscii()) {
3844 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3845 if (pattern_content.IsAscii()) {
3846 if (SearchStringMultiple(isolate,
3847 subject_vector,
3848 pattern_content.ToAsciiVector(),
3849 *pattern,
3850 builder,
3851 &match_pos)) break;
3852 } else {
3853 if (SearchStringMultiple(isolate,
3854 subject_vector,
3855 pattern_content.ToUC16Vector(),
3856 *pattern,
3857 builder,
3858 &match_pos)) break;
3859 }
3860 } else {
3861 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3862 if (pattern_content.IsAscii()) {
3863 if (SearchStringMultiple(isolate,
3864 subject_vector,
3865 pattern_content.ToAsciiVector(),
3866 *pattern,
3867 builder,
3868 &match_pos)) break;
3869 } else {
3870 if (SearchStringMultiple(isolate,
3871 subject_vector,
3872 pattern_content.ToUC16Vector(),
3873 *pattern,
3874 builder,
3875 &match_pos)) break;
3876 }
3877 }
3878 }
3879
3880 if (match_pos >= 0) {
3881 SetLastMatchInfoNoCaptures(subject,
3882 last_match_info,
3883 match_pos,
3884 match_pos + pattern->length());
3885 return true;
3886 }
3887 return false; // No matches at all.
3888 }
3889
3890
3891 static int SearchRegExpNoCaptureMultiple(
3670 Isolate* isolate, 3892 Isolate* isolate,
3671 Handle<String> subject, 3893 Handle<String> subject,
3672 Handle<JSRegExp> regexp, 3894 Handle<JSRegExp> regexp,
3673 Handle<JSArray> last_match_array, 3895 Handle<JSArray> last_match_array,
3674 FixedArrayBuilder* builder) { 3896 FixedArrayBuilder* builder) {
3675 ASSERT(subject->IsFlat()); 3897 ASSERT(subject->IsFlat());
3676 ASSERT_NE(has_capture, regexp->CaptureCount() == 0); 3898 ASSERT(regexp->CaptureCount() == 0);
3677
3678 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3679 if (global_cache.HasException()) return RegExpImpl::RE_EXCEPTION;
3680
3681 int capture_count = regexp->CaptureCount();
3682 int subject_length = subject->length();
3683
3684 // Position to search from.
3685 int match_start = -1; 3899 int match_start = -1;
3686 int match_end = 0; 3900 int match_end = 0;
3901 int pos = 0;
3902 int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject);
3903 if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION;
3904
3905 int max_matches;
3906 int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp,
3907 registers_per_match,
3908 &max_matches);
3909 OffsetsVector registers(num_registers, isolate);
3910 Vector<int32_t> register_vector(registers.vector(), registers.length());
3911 int subject_length = subject->length();
3687 bool first = true; 3912 bool first = true;
3688 3913 for (;;) { // Break on failure, return on exception.
3689 // Two smis before and after the match, for very long strings. 3914 int num_matches = RegExpImpl::IrregexpExecRaw(regexp,
3690 static const int kMaxBuilderEntriesPerRegExpMatch = 5; 3915 subject,
3691 3916 pos,
3692 while (true) { 3917 register_vector);
3693 int32_t* current_match = global_cache.FetchNext(); 3918 if (num_matches > 0) {
3694 if (current_match == NULL) break; 3919 for (int match_index = 0; match_index < num_matches; match_index++) {
3695 match_start = current_match[0]; 3920 int32_t* current_match = &register_vector[match_index * 2];
3696 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3921 match_start = current_match[0];
3697 if (match_end < match_start) { 3922 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3698 ReplacementStringBuilder::AddSubjectSlice(builder, 3923 if (match_end < match_start) {
3699 match_end, 3924 ReplacementStringBuilder::AddSubjectSlice(builder,
3700 match_start); 3925 match_end,
3701 } 3926 match_start);
3702 match_end = current_match[1]; 3927 }
3703 { 3928 match_end = current_match[1];
3704 // Avoid accumulating new handles inside loop. 3929 HandleScope loop_scope(isolate);
3705 HandleScope temp_scope(isolate); 3930 if (!first) {
3706 Handle<String> match; 3931 builder->Add(*isolate->factory()->NewProperSubString(subject,
3707 if (!first) { 3932 match_start,
3708 match = isolate->factory()->NewProperSubString(subject, 3933 match_end));
3709 match_start, 3934 } else {
3710 match_end); 3935 builder->Add(*isolate->factory()->NewSubString(subject,
3711 } else { 3936 match_start,
3712 match = isolate->factory()->NewSubString(subject, 3937 match_end));
3713 match_start, 3938 first = false;
3714 match_end); 3939 }
3715 first = false;
3716 } 3940 }
3717 3941
3718 if (has_capture) { 3942 // If we did not get the maximum number of matches, we can stop here
3719 // Arguments array to replace function is match, captures, index and 3943 // since there are no matches left.
3720 // subject, i.e., 3 + capture count in total. 3944 if (num_matches < max_matches) break;
3721 Handle<FixedArray> elements =
3722 isolate->factory()->NewFixedArray(3 + capture_count);
3723 3945
3724 elements->set(0, *match); 3946 if (match_start != match_end) {
3725 for (int i = 1; i <= capture_count; i++) { 3947 pos = match_end;
3726 int start = current_match[i * 2];
3727 if (start >= 0) {
3728 int end = current_match[i * 2 + 1];
3729 ASSERT(start <= end);
3730 Handle<String> substring =
3731 isolate->factory()->NewSubString(subject, start, end);
3732 elements->set(i, *substring);
3733 } else {
3734 ASSERT(current_match[i * 2 + 1] < 0);
3735 elements->set(i, isolate->heap()->undefined_value());
3736 }
3737 }
3738 elements->set(capture_count + 1, Smi::FromInt(match_start));
3739 elements->set(capture_count + 2, *subject);
3740 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
3741 } else { 3948 } else {
3742 builder->Add(*match); 3949 pos = match_end + 1;
3950 if (pos > subject_length) break;
3743 } 3951 }
3952 } else if (num_matches == 0) {
3953 break;
3954 } else {
3955 ASSERT_EQ(num_matches, RegExpImpl::RE_EXCEPTION);
3956 return RegExpImpl::RE_EXCEPTION;
3744 } 3957 }
3745 } 3958 }
3746 3959
3747 if (global_cache.HasException()) return RegExpImpl::RE_EXCEPTION;
3748
3749 if (match_start >= 0) { 3960 if (match_start >= 0) {
3750 // Finished matching, with at least one match.
3751 if (match_end < subject_length) { 3961 if (match_end < subject_length) {
3752 ReplacementStringBuilder::AddSubjectSlice(builder, 3962 ReplacementStringBuilder::AddSubjectSlice(builder,
3753 match_end, 3963 match_end,
3754 subject_length); 3964 subject_length);
3755 } 3965 }
3756 3966 SetLastMatchInfoNoCaptures(subject,
3757 RegExpImpl::SetLastMatchInfo( 3967 last_match_array,
3758 last_match_array, subject, capture_count, NULL); 3968 match_start,
3759 3969 match_end);
3760 return RegExpImpl::RE_SUCCESS; 3970 return RegExpImpl::RE_SUCCESS;
3761 } else { 3971 } else {
3762 return RegExpImpl::RE_FAILURE; // No matches at all. 3972 return RegExpImpl::RE_FAILURE; // No matches at all.
3763 } 3973 }
3764 } 3974 }
3765 3975
3766 3976
3977 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
3978 // separate last match info. See comment on that function.
3979 static int SearchRegExpMultiple(
3980 Isolate* isolate,
3981 Handle<String> subject,
3982 Handle<JSRegExp> regexp,
3983 Handle<JSArray> last_match_array,
3984 FixedArrayBuilder* builder,
3985 Zone* zone) {
3986
3987 ASSERT(subject->IsFlat());
3988 int registers_per_match = RegExpImpl::IrregexpPrepare(regexp, subject);
3989 if (registers_per_match < 0) return RegExpImpl::RE_EXCEPTION;
3990
3991 int max_matches;
3992 int num_registers = RegExpImpl::GlobalOffsetsVectorSize(regexp,
3993 registers_per_match,
3994 &max_matches);
3995 OffsetsVector registers(num_registers, isolate);
3996 Vector<int32_t> register_vector(registers.vector(), registers.length());
3997
3998 int num_matches = RegExpImpl::IrregexpExecRaw(regexp,
3999 subject,
4000 0,
4001 register_vector);
4002
4003 int capture_count = regexp->CaptureCount();
4004 int subject_length = subject->length();
4005
4006 // Position to search from.
4007 int pos = 0;
4008 // End of previous match. Differs from pos if match was empty.
4009 int match_end = 0;
4010 bool first = true;
4011
4012 if (num_matches > 0) {
4013 do {
4014 int match_start = 0;
4015 for (int match_index = 0; match_index < num_matches; match_index++) {
4016 int32_t* current_match =
4017 &register_vector[match_index * registers_per_match];
4018 match_start = current_match[0];
4019 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
4020 if (match_end < match_start) {
4021 ReplacementStringBuilder::AddSubjectSlice(builder,
4022 match_end,
4023 match_start);
4024 }
4025 match_end = current_match[1];
4026
4027 {
4028 // Avoid accumulating new handles inside loop.
4029 HandleScope temp_scope(isolate);
4030 // Arguments array to replace function is match, captures, index and
4031 // subject, i.e., 3 + capture count in total.
4032 Handle<FixedArray> elements =
4033 isolate->factory()->NewFixedArray(3 + capture_count);
4034 Handle<String> match;
4035 if (!first) {
4036 match = isolate->factory()->NewProperSubString(subject,
4037 match_start,
4038 match_end);
4039 } else {
4040 match = isolate->factory()->NewSubString(subject,
4041 match_start,
4042 match_end);
4043 }
4044 elements->set(0, *match);
4045 for (int i = 1; i <= capture_count; i++) {
4046 int start = current_match[i * 2];
4047 if (start >= 0) {
4048 int end = current_match[i * 2 + 1];
4049 ASSERT(start <= end);
4050 Handle<String> substring;
4051 if (!first) {
4052 substring =
4053 isolate->factory()->NewProperSubString(subject, start, end);
4054 } else {
4055 substring =
4056 isolate->factory()->NewSubString(subject, start, end);
4057 }
4058 elements->set(i, *substring);
4059 } else {
4060 ASSERT(current_match[i * 2 + 1] < 0);
4061 elements->set(i, isolate->heap()->undefined_value());
4062 }
4063 }
4064 elements->set(capture_count + 1, Smi::FromInt(match_start));
4065 elements->set(capture_count + 2, *subject);
4066 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
4067 }
4068 first = false;
4069 }
4070
4071 // If we did not get the maximum number of matches, we can stop here
4072 // since there are no matches left.
4073 if (num_matches < max_matches) break;
4074
4075 if (match_end > match_start) {
4076 pos = match_end;
4077 } else {
4078 pos = match_end + 1;
4079 if (pos > subject_length) {
4080 break;
4081 }
4082 }
4083
4084 num_matches = RegExpImpl::IrregexpExecRaw(regexp,
4085 subject,
4086 pos,
4087 register_vector);
4088 } while (num_matches > 0);
4089
4090 if (num_matches != RegExpImpl::RE_EXCEPTION) {
4091 // Finished matching, with at least one match.
4092 if (match_end < subject_length) {
4093 ReplacementStringBuilder::AddSubjectSlice(builder,
4094 match_end,
4095 subject_length);
4096 }
4097
4098 int last_match_capture_count = (capture_count + 1) * 2;
4099 int last_match_array_size =
4100 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
4101 last_match_array->EnsureSize(last_match_array_size);
4102 AssertNoAllocation no_gc;
4103 FixedArray* elements = FixedArray::cast(last_match_array->elements());
4104 // We have to set this even though the rest of the last match array is
4105 // ignored.
4106 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
4107 // These are also read without consulting the override.
4108 RegExpImpl::SetLastSubject(elements, *subject);
4109 RegExpImpl::SetLastInput(elements, *subject);
4110 return RegExpImpl::RE_SUCCESS;
4111 }
4112 }
4113 // No matches at all, return failure or exception result directly.
4114 return num_matches;
4115 }
4116
4117
3767 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets 4118 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
3768 // lastMatchInfoOverride to maintain the last match info, so we don't need to 4119 // lastMatchInfoOverride to maintain the last match info, so we don't need to
3769 // set any other last match array info. 4120 // set any other last match array info.
3770 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { 4121 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
3771 ASSERT(args.length() == 4); 4122 ASSERT(args.length() == 4);
3772 HandleScope handles(isolate); 4123 HandleScope handles(isolate);
3773 4124
3774 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 4125 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
3775 if (!subject->IsFlat()) FlattenString(subject); 4126 if (!subject->IsFlat()) FlattenString(subject);
3776 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 4127 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3777 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); 4128 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3778 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); 4129 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
3779 4130
3780 ASSERT(last_match_info->HasFastObjectElements()); 4131 ASSERT(last_match_info->HasFastObjectElements());
3781 ASSERT(regexp->GetFlags().is_global()); 4132 ASSERT(regexp->GetFlags().is_global());
3782 Handle<FixedArray> result_elements; 4133 Handle<FixedArray> result_elements;
3783 if (result_array->HasFastObjectElements()) { 4134 if (result_array->HasFastObjectElements()) {
3784 result_elements = 4135 result_elements =
3785 Handle<FixedArray>(FixedArray::cast(result_array->elements())); 4136 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3786 } 4137 }
3787 if (result_elements.is_null() || result_elements->length() < 16) { 4138 if (result_elements.is_null() || result_elements->length() < 16) {
3788 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 4139 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
3789 } 4140 }
3790 FixedArrayBuilder builder(result_elements); 4141 FixedArrayBuilder builder(result_elements);
3791 4142
4143 if (regexp->TypeTag() == JSRegExp::ATOM) {
4144 Handle<String> pattern(
4145 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
4146 ASSERT(pattern->IsFlat());
4147 if (SearchStringMultiple(isolate, subject, pattern,
4148 last_match_info, &builder)) {
4149 return *builder.ToJSArray(result_array);
4150 }
4151 return isolate->heap()->null_value();
4152 }
4153
4154 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4155
3792 int result; 4156 int result;
3793 if (regexp->CaptureCount() == 0) { 4157 if (regexp->CaptureCount() == 0) {
3794 result = SearchRegExpMultiple<false>( 4158 result = SearchRegExpNoCaptureMultiple(isolate,
3795 isolate, subject, regexp, last_match_info, &builder); 4159 subject,
4160 regexp,
4161 last_match_info,
4162 &builder);
3796 } else { 4163 } else {
3797 result = SearchRegExpMultiple<true>( 4164 result = SearchRegExpMultiple(isolate,
3798 isolate, subject, regexp, last_match_info, &builder); 4165 subject,
4166 regexp,
4167 last_match_info,
4168 &builder,
4169 isolate->runtime_zone());
3799 } 4170 }
3800
3801 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); 4171 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3802 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value(); 4172 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
3803 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 4173 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3804 return Failure::Exception(); 4174 return Failure::Exception();
3805 } 4175 }
3806 4176
3807 4177
3808 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { 4178 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
3809 NoHandleAllocation ha; 4179 NoHandleAllocation ha;
3810 ASSERT(args.length() == 2); 4180 ASSERT(args.length() == 2);
(...skipping 9536 matching lines...) Expand 10 before | Expand all | Expand 10 after
13347 // Handle last resort GC and make sure to allow future allocations 13717 // Handle last resort GC and make sure to allow future allocations
13348 // to grow the heap without causing GCs (if possible). 13718 // to grow the heap without causing GCs (if possible).
13349 isolate->counters()->gc_last_resort_from_js()->Increment(); 13719 isolate->counters()->gc_last_resort_from_js()->Increment();
13350 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13720 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13351 "Runtime::PerformGC"); 13721 "Runtime::PerformGC");
13352 } 13722 }
13353 } 13723 }
13354 13724
13355 13725
13356 } } // namespace v8::internal 13726 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/mips/code-stubs-mips.cc ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698