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

Side by Side Diff: src/jsregexp.cc

Issue 565043003: Clean up regexp code gen a little (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: 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 2419 matching lines...) Expand 10 before | Expand all | Expand 10 after
2430 } 2430 }
2431 mask_ |= (pos->mask & char_mask) << char_shift; 2431 mask_ |= (pos->mask & char_mask) << char_shift;
2432 value_ |= (pos->value & char_mask) << char_shift; 2432 value_ |= (pos->value & char_mask) << char_shift;
2433 char_shift += asc ? 8 : 16; 2433 char_shift += asc ? 8 : 16;
2434 } 2434 }
2435 return found_useful_op; 2435 return found_useful_op;
2436 } 2436 }
2437 2437
2438 2438
2439 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, 2439 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
2440 Trace* bounds_check_trace,
2440 Trace* trace, 2441 Trace* trace,
2441 bool preload_has_checked_bounds, 2442 bool preload_has_checked_bounds,
2442 Label* on_possible_success, 2443 Label* on_possible_success,
2443 QuickCheckDetails* details, 2444 QuickCheckDetails* details,
2444 bool fall_through_on_failure) { 2445 bool fall_through_on_failure) {
2445 if (details->characters() == 0) return false; 2446 if (details->characters() == 0) return false;
2446 GetQuickCheckDetails( 2447 GetQuickCheckDetails(
2447 details, compiler, 0, trace->at_start() == Trace::FALSE_VALUE); 2448 details, compiler, 0, trace->at_start() == Trace::FALSE_VALUE);
2448 if (details->cannot_match()) return false; 2449 if (details->cannot_match()) return false;
2449 if (!details->Rationalize(compiler->one_byte())) return false; 2450 if (!details->Rationalize(compiler->one_byte())) return false;
2450 DCHECK(details->characters() == 1 || 2451 DCHECK(details->characters() == 1 ||
2451 compiler->macro_assembler()->CanReadUnaligned()); 2452 compiler->macro_assembler()->CanReadUnaligned());
2452 uint32_t mask = details->mask(); 2453 uint32_t mask = details->mask();
2453 uint32_t value = details->value(); 2454 uint32_t value = details->value();
2454 2455
2455 RegExpMacroAssembler* assembler = compiler->macro_assembler(); 2456 RegExpMacroAssembler* assembler = compiler->macro_assembler();
2456 2457
2457 if (trace->characters_preloaded() != details->characters()) { 2458 if (trace->characters_preloaded() != details->characters()) {
2459 DCHECK(trace->cp_offset() == bounds_check_trace->cp_offset());
2460 // We are attempting to preload the minimum number of characters
2461 // any choice would eat, so if the bounds check fails, then none of the
2462 // choices can succeed, so we can just immediately backtrack, rather
2463 // than go to the next choice.
2458 assembler->LoadCurrentCharacter(trace->cp_offset(), 2464 assembler->LoadCurrentCharacter(trace->cp_offset(),
2459 trace->backtrack(), 2465 bounds_check_trace->backtrack(),
2460 !preload_has_checked_bounds, 2466 !preload_has_checked_bounds,
2461 details->characters()); 2467 details->characters());
2462 } 2468 }
2463 2469
2464 2470
2465 bool need_mask = true; 2471 bool need_mask = true;
2466 2472
2467 if (details->characters() == 1) { 2473 if (details->characters() == 1) {
2468 // If number of characters preloaded is 1 then we used a byte or 16 bit 2474 // If number of characters preloaded is 1 then we used a byte or 16 bit
2469 // load so the value is already masked down. 2475 // load so the value is already masked down.
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after
3848 * | 3854 * |
3849 * R 3855 * R
3850 * | 3856 * |
3851 * backtrack V 3857 * backtrack V
3852 * <----------Q4 3858 * <----------Q4
3853 * \ F | 3859 * \ F |
3854 * \ |S 3860 * \ |S
3855 * \ F V 3861 * \ F V
3856 * \-----S4 3862 * \-----S4
3857 * 3863 *
3858 * For greedy loops we reverse our expectation and expect to match rather 3864 * For greedy loops we push the current position, then generate the code that
3859 * than fail. Therefore we want the loop code to look like this (U is the 3865 * eats the input specially in EmitGreedyLoop. The other choice (the
3860 * unwind code that steps back in the greedy loop). The following alternatives 3866 * continuation) is generated by the normal code in EmitChoices, and steps back
3861 * look the same as above. 3867 * in the input to the starting position when it fails to match. The loop code
3868 * looks like this (U is the unwind code that steps back in the greedy loop).
3869 *
3862 * _____ 3870 * _____
3863 * / \ 3871 * / \
3864 * V | 3872 * V |
3865 * ----------> S1 | 3873 * ----------> S1 |
3866 * /| | 3874 * /| |
3867 * / |S | 3875 * / |S |
3868 * F/ \_____/ 3876 * F/ \_____/
3869 * / 3877 * /
3870 * |<----------- 3878 * |<-----
3871 * | \ 3879 * | \
3872 * V \ 3880 * V |S
3873 * Q2 ---> S2 \ 3881 * Q2 ---> U----->backtrack
3874 * | S / | 3882 * | F /
3875 * F| / | 3883 * S| /
3876 * | F/ | 3884 * V F /
3877 * | / | 3885 * S2--/
3878 * | R |
3879 * | / |
3880 * F VL |
3881 * <------U |
3882 * back |S |
3883 * \______________/
3884 */ 3886 */
3885 3887
3886 GreedyLoopState::GreedyLoopState(bool not_at_start) { 3888 GreedyLoopState::GreedyLoopState(bool not_at_start) {
3887 counter_backtrack_trace_.set_backtrack(&label_); 3889 counter_backtrack_trace_.set_backtrack(&label_);
3888 if (not_at_start) counter_backtrack_trace_.set_at_start(false); 3890 if (not_at_start) counter_backtrack_trace_.set_at_start(false);
3889 } 3891 }
3890 3892
3891 3893
3892 void ChoiceNode::AssertGuardsMentionRegisters(Trace* trace) { 3894 void ChoiceNode::AssertGuardsMentionRegisters(Trace* trace) {
3893 #ifdef DEBUG 3895 #ifdef DEBUG
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
3959 // match the traces produced pre-cleanup. 3961 // match the traces produced pre-cleanup.
3960 Label second_choice; 3962 Label second_choice;
3961 compiler->macro_assembler()->Bind(&second_choice); 3963 compiler->macro_assembler()->Bind(&second_choice);
3962 3964
3963 preload.eats_at_least_ = EmitOptimizedUnanchoredSearch(compiler, trace); 3965 preload.eats_at_least_ = EmitOptimizedUnanchoredSearch(compiler, trace);
3964 3966
3965 EmitChoices(compiler, 3967 EmitChoices(compiler,
3966 &alt_gens, 3968 &alt_gens,
3967 0, 3969 0,
3968 trace, 3970 trace,
3969 false, // Not greedy loop.
3970 &preload); 3971 &preload);
3971 } 3972 }
3972 3973
3973 // At this point we need to generate slow checks for the alternatives where 3974 // At this point we need to generate slow checks for the alternatives where
3974 // the quick check was inlined. We can recognize these because the associated 3975 // the quick check was inlined. We can recognize these because the associated
3975 // label was bound. 3976 // label was bound.
3976 int new_flush_budget = trace->flush_budget() / choice_count; 3977 int new_flush_budget = trace->flush_budget() / choice_count;
3977 for (int i = 0; i < choice_count - 1; i++) { 3978 for (int i = 0; i < choice_count; i++) {
3978 AlternativeGeneration* alt_gen = alt_gens.at(i); 3979 AlternativeGeneration* alt_gen = alt_gens.at(i);
3979 Trace new_trace(*trace); 3980 Trace new_trace(*trace);
3980 // If there are actions to be flushed we have to limit how many times 3981 // If there are actions to be flushed we have to limit how many times
3981 // they are flushed. Take the budget of the parent trace and distribute 3982 // they are flushed. Take the budget of the parent trace and distribute
3982 // it fairly amongst the children. 3983 // it fairly amongst the children.
3983 if (new_trace.actions() != NULL) { 3984 if (new_trace.actions() != NULL) {
3984 new_trace.set_flush_budget(new_flush_budget); 3985 new_trace.set_flush_budget(new_flush_budget);
3985 } 3986 }
3987 bool next_expects_preload =
3988 i == choice_count - 1 ? false : alt_gens.at(i + 1)->expects_preload;
3986 EmitOutOfLineContinuation(compiler, 3989 EmitOutOfLineContinuation(compiler,
3987 &new_trace, 3990 &new_trace,
3988 alternatives_->at(i), 3991 alternatives_->at(i),
3989 alt_gen, 3992 alt_gen,
3990 preload.preload_characters_, 3993 preload.preload_characters_,
3991 alt_gens.at(i + 1)->expects_preload); 3994 next_expects_preload);
3992 } 3995 }
3993 } 3996 }
3994 3997
3995 3998
3996 Trace* ChoiceNode::EmitGreedyLoop(RegExpCompiler* compiler, 3999 Trace* ChoiceNode::EmitGreedyLoop(RegExpCompiler* compiler,
3997 Trace* trace, 4000 Trace* trace,
3998 AlternativeGenerationList* alt_gens, 4001 AlternativeGenerationList* alt_gens,
3999 PreloadState* preload, 4002 PreloadState* preload,
4000 GreedyLoopState* greedy_loop_state, 4003 GreedyLoopState* greedy_loop_state,
4001 int text_length) { 4004 int text_length) {
(...skipping 20 matching lines...) Expand all
4022 4025
4023 Label second_choice; // For use in greedy matches. 4026 Label second_choice; // For use in greedy matches.
4024 macro_assembler->Bind(&second_choice); 4027 macro_assembler->Bind(&second_choice);
4025 4028
4026 Trace* new_trace = greedy_loop_state->counter_backtrack_trace(); 4029 Trace* new_trace = greedy_loop_state->counter_backtrack_trace();
4027 4030
4028 EmitChoices(compiler, 4031 EmitChoices(compiler,
4029 alt_gens, 4032 alt_gens,
4030 1, 4033 1,
4031 new_trace, 4034 new_trace,
4032 true, // Is greedy loop.
4033 preload); 4035 preload);
4034 4036
4035 macro_assembler->Bind(greedy_loop_state->label()); 4037 macro_assembler->Bind(greedy_loop_state->label());
4036 // If we have unwound to the bottom then backtrack. 4038 // If we have unwound to the bottom then backtrack.
4037 macro_assembler->CheckGreedyLoop(trace->backtrack()); 4039 macro_assembler->CheckGreedyLoop(trace->backtrack());
4038 // Otherwise try the second priority at an earlier position. 4040 // Otherwise try the second priority at an earlier position.
4039 macro_assembler->AdvanceCurrentPosition(-text_length); 4041 macro_assembler->AdvanceCurrentPosition(-text_length);
4040 macro_assembler->GoTo(&second_choice); 4042 macro_assembler->GoTo(&second_choice);
4041 return new_trace; 4043 return new_trace;
4042 } 4044 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
4089 bm->EmitSkipInstructions(macro_assembler); 4091 bm->EmitSkipInstructions(macro_assembler);
4090 } 4092 }
4091 return eats_at_least; 4093 return eats_at_least;
4092 } 4094 }
4093 4095
4094 4096
4095 void ChoiceNode::EmitChoices(RegExpCompiler* compiler, 4097 void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
4096 AlternativeGenerationList* alt_gens, 4098 AlternativeGenerationList* alt_gens,
4097 int first_choice, 4099 int first_choice,
4098 Trace* trace, 4100 Trace* trace,
4099 bool is_greedy_loop,
4100 PreloadState* preload) { 4101 PreloadState* preload) {
4101 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); 4102 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4102 SetUpPreLoad(compiler, trace, preload); 4103 SetUpPreLoad(compiler, trace, preload);
4103 4104
4104 // For now we just call all choices one after the other. The idea ultimately 4105 // For now we just call all choices one after the other. The idea ultimately
4105 // is to use the Dispatch table to try only the relevant ones. 4106 // is to use the Dispatch table to try only the relevant ones.
4106 int choice_count = alternatives_->length(); 4107 int choice_count = alternatives_->length();
4107 4108
4108 int new_flush_budget = trace->flush_budget() / choice_count; 4109 int new_flush_budget = trace->flush_budget() / choice_count;
4109 4110
4110 for (int i = first_choice; i < choice_count; i++) { 4111 for (int i = first_choice; i < choice_count; i++) {
4111 bool is_last = i == choice_count - 1; 4112 bool is_last = i == choice_count - 1;
4113 bool fall_through_on_failure = !is_last;
4112 GuardedAlternative alternative = alternatives_->at(i); 4114 GuardedAlternative alternative = alternatives_->at(i);
4113 AlternativeGeneration* alt_gen = alt_gens->at(i); 4115 AlternativeGeneration* alt_gen = alt_gens->at(i);
4114 alt_gen->quick_check_details.set_characters(preload->preload_characters_); 4116 alt_gen->quick_check_details.set_characters(preload->preload_characters_);
4115 ZoneList<Guard*>* guards = alternative.guards(); 4117 ZoneList<Guard*>* guards = alternative.guards();
4116 int guard_count = (guards == NULL) ? 0 : guards->length(); 4118 int guard_count = (guards == NULL) ? 0 : guards->length();
4117 Trace new_trace(*trace); 4119 Trace new_trace(*trace);
4118 new_trace.set_characters_preloaded(preload->preload_is_current_ ? 4120 new_trace.set_characters_preloaded(preload->preload_is_current_ ?
4119 preload->preload_characters_ : 4121 preload->preload_characters_ :
4120 0); 4122 0);
4121 if (preload->preload_has_checked_bounds_) { 4123 if (preload->preload_has_checked_bounds_) {
4122 new_trace.set_bound_checked_up_to(preload->preload_characters_); 4124 new_trace.set_bound_checked_up_to(preload->preload_characters_);
4123 } 4125 }
4124 new_trace.quick_check_performed()->Clear(); 4126 new_trace.quick_check_performed()->Clear();
4125 if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE); 4127 if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE);
4128 if (!is_last) {
4129 new_trace.set_backtrack(&alt_gen->after);
4130 }
4126 alt_gen->expects_preload = preload->preload_is_current_; 4131 alt_gen->expects_preload = preload->preload_is_current_;
4127 bool generate_full_check_inline = false; 4132 bool generate_full_check_inline = false;
4128 if (FLAG_regexp_optimization && 4133 if (FLAG_regexp_optimization &&
4129 try_to_emit_quick_check_for_alternative(i == 0) && 4134 try_to_emit_quick_check_for_alternative(i == 0) &&
4130 alternative.node()->EmitQuickCheck(compiler, 4135 alternative.node()->EmitQuickCheck(compiler,
4136 trace,
4131 &new_trace, 4137 &new_trace,
4132 preload->preload_has_checked_bounds_, 4138 preload->preload_has_checked_bounds_,
4133 &alt_gen->possible_success, 4139 &alt_gen->possible_success,
4134 &alt_gen->quick_check_details, 4140 &alt_gen->quick_check_details,
4135 !is_last)) { 4141 fall_through_on_failure)) {
4136 // Quick check was generated for this choice. 4142 // Quick check was generated for this choice.
4137 preload->preload_is_current_ = true; 4143 preload->preload_is_current_ = true;
4138 preload->preload_has_checked_bounds_ = true; 4144 preload->preload_has_checked_bounds_ = true;
4139 // On the last choice in the ChoiceNode we generated the quick 4145 // If we generated the quick check to fall through on possible success,
4140 // check to fall through on possible success. So now we need to 4146 // we now need to generate the full check inline.
4141 // generate the full check inline. 4147 if (!fall_through_on_failure) {
4142 if (is_last) {
4143 macro_assembler->Bind(&alt_gen->possible_success); 4148 macro_assembler->Bind(&alt_gen->possible_success);
4144 new_trace.set_quick_check_performed(&alt_gen->quick_check_details); 4149 new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
4145 new_trace.set_characters_preloaded(preload->preload_characters_); 4150 new_trace.set_characters_preloaded(preload->preload_characters_);
4146 new_trace.set_bound_checked_up_to(preload->preload_characters_); 4151 new_trace.set_bound_checked_up_to(preload->preload_characters_);
4147 generate_full_check_inline = true; 4152 generate_full_check_inline = true;
4148 } 4153 }
4149 } else if (alt_gen->quick_check_details.cannot_match()) { 4154 } else if (alt_gen->quick_check_details.cannot_match()) {
4150 if (is_last && !is_greedy_loop) { 4155 if (!fall_through_on_failure) {
4151 macro_assembler->GoTo(trace->backtrack()); 4156 macro_assembler->GoTo(trace->backtrack());
4152 } // Else just fall through to the next test. 4157 }
4153 continue; 4158 continue;
4154 } else { 4159 } else {
4155 // No quick check was generated. Put the full code here. 4160 // No quick check was generated. Put the full code here.
4156 // If this is not the first choice then there could be slow checks from 4161 // If this is not the first choice then there could be slow checks from
4157 // previous cases that go here when they fail. There's no reason to 4162 // previous cases that go here when they fail. There's no reason to
4158 // insist that they preload characters since the slow check we are about 4163 // insist that they preload characters since the slow check we are about
4159 // to generate probably can't use it. 4164 // to generate probably can't use it.
4160 if (i != first_choice) { 4165 if (i != first_choice) {
4161 alt_gen->expects_preload = false; 4166 alt_gen->expects_preload = false;
4162 new_trace.InvalidateCurrentCharacter(); 4167 new_trace.InvalidateCurrentCharacter();
4163 } 4168 }
4164 if (!is_last) {
4165 new_trace.set_backtrack(&alt_gen->after);
4166 }
4167 generate_full_check_inline = true; 4169 generate_full_check_inline = true;
4168 } 4170 }
4169 if (generate_full_check_inline) { 4171 if (generate_full_check_inline) {
4170 if (new_trace.actions() != NULL) { 4172 if (new_trace.actions() != NULL) {
4171 new_trace.set_flush_budget(new_flush_budget); 4173 new_trace.set_flush_budget(new_flush_budget);
4172 } 4174 }
4173 for (int j = 0; j < guard_count; j++) { 4175 for (int j = 0; j < guard_count; j++) {
4174 GenerateGuard(macro_assembler, guards->at(j), &new_trace); 4176 GenerateGuard(macro_assembler, guards->at(j), &new_trace);
4175 } 4177 }
4176 alternative.node()->Emit(compiler, &new_trace); 4178 alternative.node()->Emit(compiler, &new_trace);
(...skipping 1974 matching lines...) Expand 10 before | Expand all | Expand 10 after
6151 } 6153 }
6152 6154
6153 return compiler.Assemble(&macro_assembler, 6155 return compiler.Assemble(&macro_assembler,
6154 node, 6156 node,
6155 data->capture_count, 6157 data->capture_count,
6156 pattern); 6158 pattern);
6157 } 6159 }
6158 6160
6159 6161
6160 }} // namespace v8::internal 6162 }} // 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