Commit 9c608b2c authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Limit how many places we generate code to flush the same actions. This gives a

13% code size reduction in the php regexp with no discernable performance loss.
Review URL: http://codereview.chromium.org/20457

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1309 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 195753ff
......@@ -1527,6 +1527,13 @@ void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
// Generate deferred actions here along with code to undo them again.
OutSet affected_registers;
if (backtrack() != NULL) {
// Here we have a concrete backtrack location. These are set up by choice
// nodes and so they indicate that we have a deferred save of the current
// position which we may need to emit here.
assembler->PushCurrentPosition();
}
int max_register = FindAffectedRegisters(&affected_registers);
OutSet registers_to_pop;
OutSet registers_to_clear;
......@@ -1535,12 +1542,6 @@ void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
affected_registers,
&registers_to_pop,
&registers_to_clear);
if (backtrack() != NULL) {
// Here we have a concrete backtrack location. These are set up by choice
// nodes and so they indicate that we have a deferred save of the current
// position which we may need to emit here.
assembler->PushCurrentPosition();
}
if (cp_offset_ != 0) {
assembler->AdvanceCurrentPosition(cp_offset_);
}
......@@ -1553,9 +1554,6 @@ void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
// On backtrack we need to restore state.
assembler->Bind(&undo);
if (backtrack() != NULL) {
assembler->PopCurrentPosition();
}
RestoreAffectedRegisters(assembler,
max_register,
registers_to_pop,
......@@ -1563,6 +1561,7 @@ void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
if (backtrack() == NULL) {
assembler->Backtrack();
} else {
assembler->PopCurrentPosition();
assembler->GoTo(backtrack());
}
}
......@@ -3053,10 +3052,6 @@ class AlternativeGenerationList {
}
}
~AlternativeGenerationList() {
for (int i = 0; i < alt_gens_.length(); i++) {
alt_gens_[i]->possible_success.Unuse();
alt_gens_[i]->after.Unuse();
}
for (int i = kAFew; i < alt_gens_.length(); i++) {
delete alt_gens_[i];
alt_gens_[i] = NULL;
......@@ -3170,6 +3165,12 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
if (limit_result == DONE) return;
ASSERT(limit_result == CONTINUE);
int new_flush_budget = trace->flush_budget() / choice_count;
if (trace->flush_budget() == 0 && trace->actions() != NULL) {
trace->Flush(compiler, this);
return;
}
RecursionCheck rc(compiler);
Trace* current_trace = trace;
......@@ -3278,6 +3279,9 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
generate_full_check_inline = true;
}
if (generate_full_check_inline) {
if (new_trace.actions() != NULL) {
new_trace.set_flush_budget(new_flush_budget);
}
for (int j = 0; j < guard_count; j++) {
GenerateGuard(macro_assembler, guards->at(j), &new_trace);
}
......@@ -3294,13 +3298,21 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
macro_assembler->AdvanceCurrentPosition(-text_length);
macro_assembler->GoTo(&second_choice);
}
// At this point we need to generate slow checks for the alternatives where
// the quick check was inlined. We can recognize these because the associated
// label was bound.
for (int i = first_normal_choice; i < choice_count - 1; i++) {
AlternativeGeneration* alt_gen = alt_gens.at(i);
Trace new_trace(*current_trace);
// If there are actions to be flushed we have to limit how many times
// they are flushed. Take the budget of the parent trace and distribute
// it fairly amongst the children.
if (new_trace.actions() != NULL) {
new_trace.set_flush_budget(new_flush_budget);
}
EmitOutOfLineContinuation(compiler,
current_trace,
&new_trace,
alternatives_->at(i),
alt_gen,
preload_characters,
......
......@@ -1180,6 +1180,7 @@ class Trace {
loop_label_(NULL),
characters_preloaded_(0),
bound_checked_up_to_(0),
flush_budget_(100),
at_start_(UNKNOWN) { }
// End the trace. This involves flushing the deferred actions in the trace
......@@ -1215,6 +1216,7 @@ class Trace {
RegExpNode* stop_node() { return stop_node_; }
int characters_preloaded() { return characters_preloaded_; }
int bound_checked_up_to() { return bound_checked_up_to_; }
int flush_budget() { return flush_budget_; }
QuickCheckDetails* quick_check_performed() { return &quick_check_performed_; }
bool mentions_reg(int reg);
// Returns true if a deferred position store exists to the specified
......@@ -1233,6 +1235,7 @@ class Trace {
void set_loop_label(Label* label) { loop_label_ = label; }
void set_characters_preloaded(int cpre) { characters_preloaded_ = cpre; }
void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; }
void set_flush_budget(int to) { flush_budget_ = to; }
void set_quick_check_performed(QuickCheckDetails* d) {
quick_check_performed_ = *d;
}
......@@ -1257,6 +1260,7 @@ class Trace {
int characters_preloaded_;
int bound_checked_up_to_;
QuickCheckDetails quick_check_performed_;
int flush_budget_;
TriBool at_start_;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment