Index: src/jsregexp.cc |
diff --git a/src/jsregexp.cc b/src/jsregexp.cc |
index 03398cf6939165cf025c46bcfbfdda8d2a922d66..78cd7df3407bf409687c23189cb0cc8c820a7440 100644 |
--- a/src/jsregexp.cc |
+++ b/src/jsregexp.cc |
@@ -986,7 +986,12 @@ class RegExpCompiler { |
int capture_count, |
Handle<String> pattern); |
- inline void AddWork(RegExpNode* node) { work_list_->Add(node); } |
+ inline void AddWork(RegExpNode* node) { |
+ if (!node->on_work_list() && !node->label()->is_bound()) { |
+ node->set_on_work_list(true); |
+ work_list_->Add(node); |
+ } |
+ } |
static const int kImplementationOffset = 0; |
static const int kNumberOfRegistersOffset = 0; |
@@ -1006,6 +1011,10 @@ class RegExpCompiler { |
inline bool one_byte() { return one_byte_; } |
inline bool optimize() { return optimize_; } |
inline void set_optimize(bool value) { optimize_ = value; } |
+ inline bool limiting_recursion() { return limiting_recursion_; } |
+ inline void set_limiting_recursion(bool value) { |
+ limiting_recursion_ = value; |
+ } |
FrequencyCollator* frequency_collator() { return &frequency_collator_; } |
int current_expansion_factor() { return current_expansion_factor_; } |
@@ -1027,6 +1036,7 @@ class RegExpCompiler { |
bool ignore_case_; |
bool one_byte_; |
bool reg_exp_too_big_; |
+ bool limiting_recursion_; |
bool optimize_; |
int current_expansion_factor_; |
FrequencyCollator frequency_collator_; |
@@ -1061,6 +1071,7 @@ RegExpCompiler::RegExpCompiler(Isolate* isolate, Zone* zone, int capture_count, |
ignore_case_(ignore_case), |
one_byte_(one_byte), |
reg_exp_too_big_(false), |
+ limiting_recursion_(false), |
optimize_(FLAG_regexp_optimization), |
current_expansion_factor_(1), |
frequency_collator_(), |
@@ -1095,7 +1106,9 @@ RegExpEngine::CompilationResult RegExpCompiler::Assemble( |
macro_assembler_->Bind(&fail); |
macro_assembler_->Fail(); |
while (!work_list.is_empty()) { |
- work_list.RemoveLast()->Emit(this, &new_trace); |
+ RegExpNode* node = work_list.RemoveLast(); |
+ node->set_on_work_list(false); |
+ if (!node->label()->is_bound()) node->Emit(this, &new_trace); |
} |
if (reg_exp_too_big_) return IrregexpRegExpTooBig(isolate_); |
@@ -1371,8 +1384,13 @@ void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) { |
// Create a new trivial state and generate the node with that. |
Label undo; |
assembler->PushBacktrack(&undo); |
- Trace new_state; |
- successor->Emit(compiler, &new_state); |
+ if (successor->KeepRecursing(compiler)) { |
+ Trace new_state; |
+ successor->Emit(compiler, &new_state); |
+ } else { |
+ compiler->AddWork(successor); |
+ assembler->GoTo(successor->label()); |
+ } |
// On backtrack we need to restore state. |
assembler->Bind(&undo); |
@@ -2213,17 +2231,13 @@ RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, |
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
if (trace->is_trivial()) { |
- if (label_.is_bound()) { |
- // We are being asked to generate a generic version, but that's already |
- // been done so just go to it. |
+ if (label_.is_bound() || on_work_list() || !KeepRecursing(compiler)) { |
+ // If a generic version is already scheduled to be generated or we have |
+ // recursed too deeply then just generate a jump to that code. |
macro_assembler->GoTo(&label_); |
- return DONE; |
- } |
- if (compiler->recursion_depth() >= RegExpCompiler::kMaxRecursion) { |
- // To avoid too deep recursion we push the node to the work queue and just |
- // generate a goto here. |
+ // This will queue it up for generation of a generic version if it hasn't |
+ // already been queued. |
compiler->AddWork(this); |
- macro_assembler->GoTo(&label_); |
return DONE; |
} |
// Generate generic version of the node and bind the label for later use. |
@@ -2234,19 +2248,28 @@ RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, |
// We are being asked to make a non-generic version. Keep track of how many |
// non-generic versions we generate so as not to overdo it. |
trace_count_++; |
- if (compiler->optimize() && trace_count_ < kMaxCopiesCodeGenerated && |
- compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { |
+ if (KeepRecursing(compiler) && compiler->optimize() && |
+ trace_count_ < kMaxCopiesCodeGenerated) { |
return CONTINUE; |
} |
// If we get here code has been generated for this node too many times or |
// recursion is too deep. Time to switch to a generic version. The code for |
// generic versions above can handle deep recursion properly. |
+ bool was_limiting = compiler->limiting_recursion(); |
+ compiler->set_limiting_recursion(true); |
trace->Flush(compiler, this); |
+ compiler->set_limiting_recursion(was_limiting); |
return DONE; |
} |
+bool RegExpNode::KeepRecursing(RegExpCompiler* compiler) { |
+ return !compiler->limiting_recursion() && |
+ compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion; |
+} |
+ |
+ |
int ActionNode::EatsAtLeast(int still_to_find, |
int budget, |
bool not_at_start) { |
@@ -6025,7 +6048,7 @@ RegExpEngine::CompilationResult RegExpEngine::Compile( |
RegExpCompiler compiler(isolate, zone, data->capture_count, ignore_case, |
is_one_byte); |
- compiler.set_optimize(!TooMuchRegExpCode(pattern)); |
+ if (compiler.optimize()) compiler.set_optimize(!TooMuchRegExpCode(pattern)); |
// Sample some characters from the middle of the string. |
static const int kSampleSize = 128; |