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

Side by Side Diff: src/jsregexp.cc

Issue 537913002: Regexp: Refactor ChoiceNode::Emit (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Nixed 'not' nit Created 6 years, 3 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/jsregexp.h ('k') | no next file » | 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 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/ast.h" 7 #include "src/ast.h"
8 #include "src/base/platform/platform.h" 8 #include "src/base/platform/platform.h"
9 #include "src/compilation-cache.h" 9 #include "src/compilation-cache.h"
10 #include "src/compiler.h" 10 #include "src/compiler.h"
(...skipping 3475 matching lines...) Expand 10 before | Expand all | Expand 10 after
3486 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) { 3486 void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) {
3487 DCHECK_EQ(continue_node_, NULL); 3487 DCHECK_EQ(continue_node_, NULL);
3488 AddAlternative(alt); 3488 AddAlternative(alt);
3489 continue_node_ = alt.node(); 3489 continue_node_ = alt.node();
3490 } 3490 }
3491 3491
3492 3492
3493 void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { 3493 void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
3494 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); 3494 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
3495 if (trace->stop_node() == this) { 3495 if (trace->stop_node() == this) {
3496 // Back edge of greedy optimized loop node graph.
3496 int text_length = 3497 int text_length =
3497 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); 3498 GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
3498 DCHECK(text_length != kNodeIsTooComplexForGreedyLoops); 3499 DCHECK(text_length != kNodeIsTooComplexForGreedyLoops);
3499 // Update the counter-based backtracking info on the stack. This is an 3500 // Update the counter-based backtracking info on the stack. This is an
3500 // optimization for greedy loops (see below). 3501 // optimization for greedy loops (see below).
3501 DCHECK(trace->cp_offset() == text_length); 3502 DCHECK(trace->cp_offset() == text_length);
3502 macro_assembler->AdvanceCurrentPosition(text_length); 3503 macro_assembler->AdvanceCurrentPosition(text_length);
3503 macro_assembler->GoTo(trace->loop_label()); 3504 macro_assembler->GoTo(trace->loop_label());
3504 return; 3505 return;
3505 } 3506 }
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
3752 boolean_skip_table->set(j, kDontSkipArrayEntry); 3753 boolean_skip_table->set(j, kDontSkipArrayEntry);
3753 } 3754 }
3754 } 3755 }
3755 } 3756 }
3756 3757
3757 return skip; 3758 return skip;
3758 } 3759 }
3759 3760
3760 3761
3761 // See comment above on the implementation of GetSkipTable. 3762 // See comment above on the implementation of GetSkipTable.
3762 bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) { 3763 void BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
3763 const int kSize = RegExpMacroAssembler::kTableSize; 3764 const int kSize = RegExpMacroAssembler::kTableSize;
3764 3765
3765 int min_lookahead = 0; 3766 int min_lookahead = 0;
3766 int max_lookahead = 0; 3767 int max_lookahead = 0;
3767 3768
3768 if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead)) return false; 3769 if (!FindWorthwhileInterval(&min_lookahead, &max_lookahead)) return;
3769 3770
3770 bool found_single_character = false; 3771 bool found_single_character = false;
3771 int single_character = 0; 3772 int single_character = 0;
3772 for (int i = max_lookahead; i >= min_lookahead; i--) { 3773 for (int i = max_lookahead; i >= min_lookahead; i--) {
3773 BoyerMoorePositionInfo* map = bitmaps_->at(i); 3774 BoyerMoorePositionInfo* map = bitmaps_->at(i);
3774 if (map->map_count() > 1 || 3775 if (map->map_count() > 1 ||
3775 (found_single_character && map->map_count() != 0)) { 3776 (found_single_character && map->map_count() != 0)) {
3776 found_single_character = false; 3777 found_single_character = false;
3777 break; 3778 break;
3778 } 3779 }
3779 for (int j = 0; j < kSize; j++) { 3780 for (int j = 0; j < kSize; j++) {
3780 if (map->at(j)) { 3781 if (map->at(j)) {
3781 found_single_character = true; 3782 found_single_character = true;
3782 single_character = j; 3783 single_character = j;
3783 break; 3784 break;
3784 } 3785 }
3785 } 3786 }
3786 } 3787 }
3787 3788
3788 int lookahead_width = max_lookahead + 1 - min_lookahead; 3789 int lookahead_width = max_lookahead + 1 - min_lookahead;
3789 3790
3790 if (found_single_character && lookahead_width == 1 && max_lookahead < 3) { 3791 if (found_single_character && lookahead_width == 1 && max_lookahead < 3) {
3791 // The mask-compare can probably handle this better. 3792 // The mask-compare can probably handle this better.
3792 return false; 3793 return;
3793 } 3794 }
3794 3795
3795 if (found_single_character) { 3796 if (found_single_character) {
3796 Label cont, again; 3797 Label cont, again;
3797 masm->Bind(&again); 3798 masm->Bind(&again);
3798 masm->LoadCurrentCharacter(max_lookahead, &cont, true); 3799 masm->LoadCurrentCharacter(max_lookahead, &cont, true);
3799 if (max_char_ > kSize) { 3800 if (max_char_ > kSize) {
3800 masm->CheckCharacterAfterAnd(single_character, 3801 masm->CheckCharacterAfterAnd(single_character,
3801 RegExpMacroAssembler::kTableMask, 3802 RegExpMacroAssembler::kTableMask,
3802 &cont); 3803 &cont);
3803 } else { 3804 } else {
3804 masm->CheckCharacter(single_character, &cont); 3805 masm->CheckCharacter(single_character, &cont);
3805 } 3806 }
3806 masm->AdvanceCurrentPosition(lookahead_width); 3807 masm->AdvanceCurrentPosition(lookahead_width);
3807 masm->GoTo(&again); 3808 masm->GoTo(&again);
3808 masm->Bind(&cont); 3809 masm->Bind(&cont);
3809 return true; 3810 return;
3810 } 3811 }
3811 3812
3812 Factory* factory = masm->zone()->isolate()->factory(); 3813 Factory* factory = masm->zone()->isolate()->factory();
3813 Handle<ByteArray> boolean_skip_table = factory->NewByteArray(kSize, TENURED); 3814 Handle<ByteArray> boolean_skip_table = factory->NewByteArray(kSize, TENURED);
3814 int skip_distance = GetSkipTable( 3815 int skip_distance = GetSkipTable(
3815 min_lookahead, max_lookahead, boolean_skip_table); 3816 min_lookahead, max_lookahead, boolean_skip_table);
3816 DCHECK(skip_distance != 0); 3817 DCHECK(skip_distance != 0);
3817 3818
3818 Label cont, again; 3819 Label cont, again;
3819 masm->Bind(&again); 3820 masm->Bind(&again);
3820 masm->LoadCurrentCharacter(max_lookahead, &cont, true); 3821 masm->LoadCurrentCharacter(max_lookahead, &cont, true);
3821 masm->CheckBitInTable(boolean_skip_table, &cont); 3822 masm->CheckBitInTable(boolean_skip_table, &cont);
3822 masm->AdvanceCurrentPosition(skip_distance); 3823 masm->AdvanceCurrentPosition(skip_distance);
3823 masm->GoTo(&again); 3824 masm->GoTo(&again);
3824 masm->Bind(&cont); 3825 masm->Bind(&cont);
3825
3826 return true;
3827 } 3826 }
3828 3827
3829 3828
3830 /* Code generation for choice nodes. 3829 /* Code generation for choice nodes.
3831 * 3830 *
3832 * We generate quick checks that do a mask and compare to eliminate a 3831 * We generate quick checks that do a mask and compare to eliminate a
3833 * choice. If the quick check succeeds then it jumps to the continuation to 3832 * choice. If the quick check succeeds then it jumps to the continuation to
3834 * do slow checks and check subsequent nodes. If it fails (the common case) 3833 * do slow checks and check subsequent nodes. If it fails (the common case)
3835 * it falls through to the next choice. 3834 * it falls through to the next choice.
3836 * 3835 *
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
3898 * | F/ | 3897 * | F/ |
3899 * | / | 3898 * | / |
3900 * | R | 3899 * | R |
3901 * | / | 3900 * | / |
3902 * F VL | 3901 * F VL |
3903 * <------U | 3902 * <------U |
3904 * back |S | 3903 * back |S |
3905 * \______________/ 3904 * \______________/
3906 */ 3905 */
3907 3906
3908 void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { 3907 GreedyLoopState::GreedyLoopState(bool not_at_start) {
3909 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); 3908 counter_backtrack_trace_.set_backtrack(&label_);
3909 if (not_at_start) counter_backtrack_trace_.set_at_start(false);
3910 }
3911
3912
3913 void ChoiceNode::AssertGuardsMentionRegisters(Trace* trace) {
3914 #ifdef DEBUG
3910 int choice_count = alternatives_->length(); 3915 int choice_count = alternatives_->length();
3911 #ifdef DEBUG
3912 for (int i = 0; i < choice_count - 1; i++) { 3916 for (int i = 0; i < choice_count - 1; i++) {
3913 GuardedAlternative alternative = alternatives_->at(i); 3917 GuardedAlternative alternative = alternatives_->at(i);
3914 ZoneList<Guard*>* guards = alternative.guards(); 3918 ZoneList<Guard*>* guards = alternative.guards();
3915 int guard_count = (guards == NULL) ? 0 : guards->length(); 3919 int guard_count = (guards == NULL) ? 0 : guards->length();
3916 for (int j = 0; j < guard_count; j++) { 3920 for (int j = 0; j < guard_count; j++) {
3917 DCHECK(!trace->mentions_reg(guards->at(j)->reg())); 3921 DCHECK(!trace->mentions_reg(guards->at(j)->reg()));
3918 } 3922 }
3919 } 3923 }
3920 #endif 3924 #endif
3925 }
3926
3927
3928 void ChoiceNode::SetUpPreLoad(RegExpCompiler* compiler,
3929 Trace* current_trace,
3930 PreloadState* state) {
3931 if (state->eats_at_least_ == PreloadState::kEatsAtLeastNotYetInitialized) {
3932 // Save some time by looking at most one machine word ahead.
3933 state->eats_at_least_ =
3934 EatsAtLeast(compiler->ascii() ? 4 : 2,
3935 kRecursionBudget,
3936 current_trace->at_start() == Trace::FALSE_VALUE);
3937 }
3938 state->preload_characters_ =
3939 CalculatePreloadCharacters(compiler, state->eats_at_least_);
3940
3941 state->preload_is_current_ =
3942 (current_trace->characters_preloaded() == state->preload_characters_);
3943 state->preload_has_checked_bounds_ = state->preload_is_current_;
3944 }
3945
3946
3947 void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
3948 int choice_count = alternatives_->length();
3949
3950 AssertGuardsMentionRegisters(trace);
3921 3951
3922 LimitResult limit_result = LimitVersions(compiler, trace); 3952 LimitResult limit_result = LimitVersions(compiler, trace);
3923 if (limit_result == DONE) return; 3953 if (limit_result == DONE) return;
3924 DCHECK(limit_result == CONTINUE); 3954 DCHECK(limit_result == CONTINUE);
3925 3955
3926 int new_flush_budget = trace->flush_budget() / choice_count; 3956 // For loop nodes we already flushed (see LoopChoiceNode::Emit), but for
3957 // other choice nodes we only flush if we are out of code size budget.
3927 if (trace->flush_budget() == 0 && trace->actions() != NULL) { 3958 if (trace->flush_budget() == 0 && trace->actions() != NULL) {
3928 trace->Flush(compiler, this); 3959 trace->Flush(compiler, this);
3929 return; 3960 return;
3930 } 3961 }
3931 3962
3932 RecursionCheck rc(compiler); 3963 RecursionCheck rc(compiler);
3933 3964
3934 Trace* current_trace = trace; 3965 PreloadState preload;
3935 3966 preload.init();
3936 int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0))); 3967 GreedyLoopState greedy_loop_state(not_at_start());
3937 bool greedy_loop = false; 3968
3938 Label greedy_loop_label; 3969 int text_length = GreedyLoopTextLengthForAlternative(&alternatives_->at(0));
3939 Trace counter_backtrack_trace; 3970 AlternativeGenerationList alt_gens(choice_count, zone());
3940 counter_backtrack_trace.set_backtrack(&greedy_loop_label);
3941 if (not_at_start()) counter_backtrack_trace.set_at_start(false);
3942 3971
3943 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { 3972 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
3944 // Here we have special handling for greedy loops containing only text nodes 3973 trace = EmitGreedyLoop(compiler,
3945 // and other simple nodes. These are handled by pushing the current 3974 trace,
3946 // position on the stack and then incrementing the current position each 3975 &alt_gens,
3947 // time around the switch. On backtrack we decrement the current position 3976 &preload,
3948 // and check it against the pushed value. This avoids pushing backtrack 3977 &greedy_loop_state,
3949 // information for each iteration of the loop, which could take up a lot of 3978 text_length);
3950 // space. 3979 } else {
3951 greedy_loop = true; 3980 // TODO(erikcorry): Delete this. We don't need this label, but it makes us
3952 DCHECK(trace->stop_node() == NULL); 3981 // match the traces produced pre-cleanup.
3953 macro_assembler->PushCurrentPosition(); 3982 Label second_choice;
3954 current_trace = &counter_backtrack_trace; 3983 compiler->macro_assembler()->Bind(&second_choice);
3955 Label greedy_match_failed; 3984
3956 Trace greedy_match_trace; 3985 preload.eats_at_least_ = EmitOptimizedUnanchoredSearch(compiler, trace);
3957 if (not_at_start()) greedy_match_trace.set_at_start(false); 3986
3958 greedy_match_trace.set_backtrack(&greedy_match_failed); 3987 EmitChoices(compiler,
3959 Label loop_label; 3988 &alt_gens,
3960 macro_assembler->Bind(&loop_label); 3989 0,
3961 greedy_match_trace.set_stop_node(this); 3990 trace,
3962 greedy_match_trace.set_loop_label(&loop_label); 3991 false, // Not greedy loop.
3963 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace); 3992 &preload);
3964 macro_assembler->Bind(&greedy_match_failed); 3993 }
3965 } 3994
3995 // At this point we need to generate slow checks for the alternatives where
3996 // the quick check was inlined. We can recognize these because the associated
3997 // label was bound.
3998 int new_flush_budget = trace->flush_budget() / choice_count;
3999 for (int i = 0; i < choice_count - 1; i++) {
4000 AlternativeGeneration* alt_gen = alt_gens.at(i);
4001 Trace new_trace(*trace);
4002 // If there are actions to be flushed we have to limit how many times
4003 // they are flushed. Take the budget of the parent trace and distribute
4004 // it fairly amongst the children.
4005 if (new_trace.actions() != NULL) {
4006 new_trace.set_flush_budget(new_flush_budget);
4007 }
4008 EmitOutOfLineContinuation(compiler,
4009 &new_trace,
4010 alternatives_->at(i),
4011 alt_gen,
4012 preload.preload_characters_,
4013 alt_gens.at(i + 1)->expects_preload);
4014 }
4015 }
4016
4017
4018 Trace* ChoiceNode::EmitGreedyLoop(RegExpCompiler* compiler,
4019 Trace* trace,
4020 AlternativeGenerationList* alt_gens,
4021 PreloadState* preload,
4022 GreedyLoopState* greedy_loop_state,
4023 int text_length) {
4024 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4025 // Here we have special handling for greedy loops containing only text nodes
4026 // and other simple nodes. These are handled by pushing the current
4027 // position on the stack and then incrementing the current position each
4028 // time around the switch. On backtrack we decrement the current position
4029 // and check it against the pushed value. This avoids pushing backtrack
4030 // information for each iteration of the loop, which could take up a lot of
4031 // space.
4032 DCHECK(trace->stop_node() == NULL);
4033 macro_assembler->PushCurrentPosition();
4034 Label greedy_match_failed;
4035 Trace greedy_match_trace;
4036 if (not_at_start()) greedy_match_trace.set_at_start(false);
4037 greedy_match_trace.set_backtrack(&greedy_match_failed);
4038 Label loop_label;
4039 macro_assembler->Bind(&loop_label);
4040 greedy_match_trace.set_stop_node(this);
4041 greedy_match_trace.set_loop_label(&loop_label);
4042 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
4043 macro_assembler->Bind(&greedy_match_failed);
3966 4044
3967 Label second_choice; // For use in greedy matches. 4045 Label second_choice; // For use in greedy matches.
3968 macro_assembler->Bind(&second_choice); 4046 macro_assembler->Bind(&second_choice);
3969 4047
3970 int first_normal_choice = greedy_loop ? 1 : 0; 4048 Trace* new_trace = greedy_loop_state->counter_backtrack_trace();
3971 4049
3972 bool not_at_start = current_trace->at_start() == Trace::FALSE_VALUE; 4050 EmitChoices(compiler,
3973 const int kEatsAtLeastNotYetInitialized = -1; 4051 alt_gens,
3974 int eats_at_least = kEatsAtLeastNotYetInitialized; 4052 1,
3975 4053 new_trace,
3976 bool skip_was_emitted = false; 4054 true, // Is greedy loop.
3977 4055 preload);
3978 if (!greedy_loop && choice_count == 2) { 4056
3979 GuardedAlternative alt1 = alternatives_->at(1); 4057 macro_assembler->Bind(greedy_loop_state->label());
3980 if (alt1.guards() == NULL || alt1.guards()->length() == 0) { 4058 // If we have unwound to the bottom then backtrack.
3981 RegExpNode* eats_anything_node = alt1.node(); 4059 macro_assembler->CheckGreedyLoop(trace->backtrack());
3982 if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) == 4060 // Otherwise try the second priority at an earlier position.
3983 this) { 4061 macro_assembler->AdvanceCurrentPosition(-text_length);
3984 // At this point we know that we are at a non-greedy loop that will eat 4062 macro_assembler->GoTo(&second_choice);
3985 // any character one at a time. Any non-anchored regexp has such a 4063 return new_trace;
3986 // loop prepended to it in order to find where it starts. We look for 4064 }
3987 // a pattern of the form ...abc... where we can look 6 characters ahead 4065
3988 // and step forwards 3 if the character is not one of abc. Abc need 4066 int ChoiceNode::EmitOptimizedUnanchoredSearch(RegExpCompiler* compiler,
3989 // not be atoms, they can be any reasonably limited character class or 4067 Trace* trace) {
3990 // small alternation. 4068 int eats_at_least = PreloadState::kEatsAtLeastNotYetInitialized;
3991 DCHECK(trace->is_trivial()); // This is the case on LoopChoiceNodes. 4069 if (alternatives_->length() != 2) return eats_at_least;
3992 BoyerMooreLookahead* lookahead = bm_info(not_at_start); 4070
3993 if (lookahead == NULL) { 4071 GuardedAlternative alt1 = alternatives_->at(1);
3994 eats_at_least = Min(kMaxLookaheadForBoyerMoore, 4072 if (alt1.guards() != NULL && alt1.guards()->length() != 0) {
3995 EatsAtLeast(kMaxLookaheadForBoyerMoore, 4073 return eats_at_least;
3996 kRecursionBudget, 4074 }
3997 not_at_start)); 4075 RegExpNode* eats_anything_node = alt1.node();
3998 if (eats_at_least >= 1) { 4076 if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) != this) {
3999 BoyerMooreLookahead* bm = 4077 return eats_at_least;
4000 new(zone()) BoyerMooreLookahead(eats_at_least, 4078 }
4001 compiler, 4079
4002 zone()); 4080 // Really we should be creating a new trace when we execute this function,
4003 GuardedAlternative alt0 = alternatives_->at(0); 4081 // but there is no need, because the code it generates cannot backtrack, and
4004 alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, not_at_start); 4082 // we always arrive here with a trivial trace (since it's the entry to a
4005 skip_was_emitted = bm->EmitSkipInstructions(macro_assembler); 4083 // loop. That also implies that there are no preloaded characters, which is
4006 } 4084 // good, because it means we won't be violating any assumptions by
4007 } else { 4085 // overwriting those characters with new load instructions.
4008 skip_was_emitted = lookahead->EmitSkipInstructions(macro_assembler); 4086 DCHECK(trace->is_trivial());
4009 } 4087
4010 } 4088 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4089 // At this point we know that we are at a non-greedy loop that will eat
4090 // any character one at a time. Any non-anchored regexp has such a
4091 // loop prepended to it in order to find where it starts. We look for
4092 // a pattern of the form ...abc... where we can look 6 characters ahead
4093 // and step forwards 3 if the character is not one of abc. Abc need
4094 // not be atoms, they can be any reasonably limited character class or
4095 // small alternation.
4096 BoyerMooreLookahead* bm = bm_info(false);
4097 if (bm == NULL) {
4098 eats_at_least = Min(kMaxLookaheadForBoyerMoore,
4099 EatsAtLeast(kMaxLookaheadForBoyerMoore,
4100 kRecursionBudget,
4101 false));
4102 if (eats_at_least >= 1) {
4103 bm = new(zone()) BoyerMooreLookahead(eats_at_least,
4104 compiler,
4105 zone());
4106 GuardedAlternative alt0 = alternatives_->at(0);
4107 alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, false);
4011 } 4108 }
4012 } 4109 }
4013 4110 if (bm != NULL) {
4014 if (eats_at_least == kEatsAtLeastNotYetInitialized) { 4111 bm->EmitSkipInstructions(macro_assembler);
4015 // Save some time by looking at most one machine word ahead. 4112 }
4016 eats_at_least = 4113 return eats_at_least;
4017 EatsAtLeast(compiler->ascii() ? 4 : 2, kRecursionBudget, not_at_start); 4114 }
4018 } 4115
4019 int preload_characters = CalculatePreloadCharacters(compiler, eats_at_least); 4116
4020 4117 void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
4021 bool preload_is_current = !skip_was_emitted && 4118 AlternativeGenerationList* alt_gens,
4022 (current_trace->characters_preloaded() == preload_characters); 4119 int first_choice,
4023 bool preload_has_checked_bounds = preload_is_current; 4120 Trace* trace,
4024 4121 bool is_greedy_loop,
4025 AlternativeGenerationList alt_gens(choice_count, zone()); 4122 PreloadState* preload) {
4123 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4124 SetUpPreLoad(compiler, trace, preload);
4026 4125
4027 // For now we just call all choices one after the other. The idea ultimately 4126 // For now we just call all choices one after the other. The idea ultimately
4028 // is to use the Dispatch table to try only the relevant ones. 4127 // is to use the Dispatch table to try only the relevant ones.
4029 for (int i = first_normal_choice; i < choice_count; i++) { 4128 int choice_count = alternatives_->length();
4129
4130 int new_flush_budget = trace->flush_budget() / choice_count;
4131
4132 for (int i = first_choice; i < choice_count; i++) {
4133 bool is_last = i == choice_count - 1;
4030 GuardedAlternative alternative = alternatives_->at(i); 4134 GuardedAlternative alternative = alternatives_->at(i);
4031 AlternativeGeneration* alt_gen = alt_gens.at(i); 4135 AlternativeGeneration* alt_gen = alt_gens->at(i);
4032 alt_gen->quick_check_details.set_characters(preload_characters); 4136 alt_gen->quick_check_details.set_characters(preload->preload_characters_);
4033 ZoneList<Guard*>* guards = alternative.guards(); 4137 ZoneList<Guard*>* guards = alternative.guards();
4034 int guard_count = (guards == NULL) ? 0 : guards->length(); 4138 int guard_count = (guards == NULL) ? 0 : guards->length();
4035 Trace new_trace(*current_trace); 4139 Trace new_trace(*trace);
4036 new_trace.set_characters_preloaded(preload_is_current ? 4140 new_trace.set_characters_preloaded(preload->preload_is_current_ ?
4037 preload_characters : 4141 preload->preload_characters_ :
4038 0); 4142 0);
4039 if (preload_has_checked_bounds) { 4143 if (preload->preload_has_checked_bounds_) {
4040 new_trace.set_bound_checked_up_to(preload_characters); 4144 new_trace.set_bound_checked_up_to(preload->preload_characters_);
4041 } 4145 }
4042 new_trace.quick_check_performed()->Clear(); 4146 new_trace.quick_check_performed()->Clear();
4043 if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE); 4147 if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE);
4044 alt_gen->expects_preload = preload_is_current; 4148 alt_gen->expects_preload = preload->preload_is_current_;
4045 bool generate_full_check_inline = false; 4149 bool generate_full_check_inline = false;
4046 if (FLAG_regexp_optimization && 4150 if (FLAG_regexp_optimization &&
4047 try_to_emit_quick_check_for_alternative(i) && 4151 try_to_emit_quick_check_for_alternative(i == 0) &&
4048 alternative.node()->EmitQuickCheck(compiler, 4152 alternative.node()->EmitQuickCheck(compiler,
4049 &new_trace, 4153 &new_trace,
4050 preload_has_checked_bounds, 4154 preload->preload_has_checked_bounds_,
4051 &alt_gen->possible_success, 4155 &alt_gen->possible_success,
4052 &alt_gen->quick_check_details, 4156 &alt_gen->quick_check_details,
4053 i < choice_count - 1)) { 4157 !is_last)) {
4054 // Quick check was generated for this choice. 4158 // Quick check was generated for this choice.
4055 preload_is_current = true; 4159 preload->preload_is_current_ = true;
4056 preload_has_checked_bounds = true; 4160 preload->preload_has_checked_bounds_ = true;
4057 // On the last choice in the ChoiceNode we generated the quick 4161 // On the last choice in the ChoiceNode we generated the quick
4058 // check to fall through on possible success. So now we need to 4162 // check to fall through on possible success. So now we need to
4059 // generate the full check inline. 4163 // generate the full check inline.
4060 if (i == choice_count - 1) { 4164 if (is_last) {
4061 macro_assembler->Bind(&alt_gen->possible_success); 4165 macro_assembler->Bind(&alt_gen->possible_success);
4062 new_trace.set_quick_check_performed(&alt_gen->quick_check_details); 4166 new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
4063 new_trace.set_characters_preloaded(preload_characters); 4167 new_trace.set_characters_preloaded(preload->preload_characters_);
4064 new_trace.set_bound_checked_up_to(preload_characters); 4168 new_trace.set_bound_checked_up_to(preload->preload_characters_);
4065 generate_full_check_inline = true; 4169 generate_full_check_inline = true;
4066 } 4170 }
4067 } else if (alt_gen->quick_check_details.cannot_match()) { 4171 } else if (alt_gen->quick_check_details.cannot_match()) {
4068 if (i == choice_count - 1 && !greedy_loop) { 4172 if (is_last && !is_greedy_loop) {
4069 macro_assembler->GoTo(trace->backtrack()); 4173 macro_assembler->GoTo(trace->backtrack());
4070 } 4174 } // Else just fall through to the next test.
4071 continue; 4175 continue;
4072 } else { 4176 } else {
4073 // No quick check was generated. Put the full code here. 4177 // No quick check was generated. Put the full code here.
4074 // If this is not the first choice then there could be slow checks from 4178 // If this is not the first choice then there could be slow checks from
4075 // previous cases that go here when they fail. There's no reason to 4179 // previous cases that go here when they fail. There's no reason to
4076 // insist that they preload characters since the slow check we are about 4180 // insist that they preload characters since the slow check we are about
4077 // to generate probably can't use it. 4181 // to generate probably can't use it.
4078 if (i != first_normal_choice) { 4182 if (i != first_choice) {
4079 alt_gen->expects_preload = false; 4183 alt_gen->expects_preload = false;
4080 new_trace.InvalidateCurrentCharacter(); 4184 new_trace.InvalidateCurrentCharacter();
4081 } 4185 }
4082 if (i < choice_count - 1) { 4186 if (!is_last) {
4083 new_trace.set_backtrack(&alt_gen->after); 4187 new_trace.set_backtrack(&alt_gen->after);
4084 } 4188 }
4085 generate_full_check_inline = true; 4189 generate_full_check_inline = true;
4086 } 4190 }
4087 if (generate_full_check_inline) { 4191 if (generate_full_check_inline) {
4088 if (new_trace.actions() != NULL) { 4192 if (new_trace.actions() != NULL) {
4089 new_trace.set_flush_budget(new_flush_budget); 4193 new_trace.set_flush_budget(new_flush_budget);
4090 } 4194 }
4091 for (int j = 0; j < guard_count; j++) { 4195 for (int j = 0; j < guard_count; j++) {
4092 GenerateGuard(macro_assembler, guards->at(j), &new_trace); 4196 GenerateGuard(macro_assembler, guards->at(j), &new_trace);
4093 } 4197 }
4094 alternative.node()->Emit(compiler, &new_trace); 4198 alternative.node()->Emit(compiler, &new_trace);
4095 preload_is_current = false; 4199 preload->preload_is_current_ = false;
4096 } 4200 }
4097 macro_assembler->Bind(&alt_gen->after); 4201 macro_assembler->Bind(&alt_gen->after);
4098 } 4202 }
4099 if (greedy_loop) {
4100 macro_assembler->Bind(&greedy_loop_label);
4101 // If we have unwound to the bottom then backtrack.
4102 macro_assembler->CheckGreedyLoop(trace->backtrack());
4103 // Otherwise try the second priority at an earlier position.
4104 macro_assembler->AdvanceCurrentPosition(-text_length);
4105 macro_assembler->GoTo(&second_choice);
4106 }
4107
4108 // At this point we need to generate slow checks for the alternatives where
4109 // the quick check was inlined. We can recognize these because the associated
4110 // label was bound.
4111 for (int i = first_normal_choice; i < choice_count - 1; i++) {
4112 AlternativeGeneration* alt_gen = alt_gens.at(i);
4113 Trace new_trace(*current_trace);
4114 // If there are actions to be flushed we have to limit how many times
4115 // they are flushed. Take the budget of the parent trace and distribute
4116 // it fairly amongst the children.
4117 if (new_trace.actions() != NULL) {
4118 new_trace.set_flush_budget(new_flush_budget);
4119 }
4120 EmitOutOfLineContinuation(compiler,
4121 &new_trace,
4122 alternatives_->at(i),
4123 alt_gen,
4124 preload_characters,
4125 alt_gens.at(i + 1)->expects_preload);
4126 }
4127 } 4203 }
4128 4204
4129 4205
4130 void ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler, 4206 void ChoiceNode::EmitOutOfLineContinuation(RegExpCompiler* compiler,
4131 Trace* trace, 4207 Trace* trace,
4132 GuardedAlternative alternative, 4208 GuardedAlternative alternative,
4133 AlternativeGeneration* alt_gen, 4209 AlternativeGeneration* alt_gen,
4134 int preload_characters, 4210 int preload_characters,
4135 bool next_expects_preload) { 4211 bool next_expects_preload) {
4136 if (!alt_gen->possible_success.is_linked()) return; 4212 if (!alt_gen->possible_success.is_linked()) return;
(...skipping 1966 matching lines...) Expand 10 before | Expand all | Expand 10 after
6103 } 6179 }
6104 6180
6105 return compiler.Assemble(&macro_assembler, 6181 return compiler.Assemble(&macro_assembler,
6106 node, 6182 node,
6107 data->capture_count, 6183 data->capture_count,
6108 pattern); 6184 pattern);
6109 } 6185 }
6110 6186
6111 6187
6112 }} // namespace v8::internal 6188 }} // namespace v8::internal
OLDNEW
« no previous file with comments | « src/jsregexp.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698