Fixed crash-bug in the code generation for case independent 16 bit backreferences.
Made shells more robust in the presence of string conversion failures (issue 224).
Fixed a potential infinite loop when attempting to resolve eval (issue 221).
Miscellaneous fixes to the new regular expression engine.
Reduced binary by stripping unneeded text from JavaScript library and minifying some JavaScript files.
git-svn-id: http://v8.googlecode.com/svn/trunk@1243 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 590dd7d..dadec3b 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -1269,7 +1269,7 @@
List <RegExpNode*> work_list(0);
work_list_ = &work_list;
Label fail;
- macro_assembler->PushBacktrack(&fail);
+ macro_assembler_->PushBacktrack(&fail);
Trace new_trace;
start->Emit(this, &new_trace);
macro_assembler_->Bind(&fail);
@@ -1507,12 +1507,7 @@
void Trace::Flush(RegExpCompiler* compiler, RegExpNode* successor) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
- ASSERT(actions_ != NULL ||
- cp_offset_ != 0 ||
- backtrack() != NULL ||
- characters_preloaded_ != 0 ||
- quick_check_performed_.characters() != 0 ||
- bound_checked_up_to_ != 0);
+ ASSERT(!is_trivial());
if (actions_ == NULL && backtrack() == NULL) {
// Here we just have some deferred cp advances to fix and we are back to
@@ -2013,7 +2008,8 @@
// 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 (trace_count_ < kMaxCopiesCodeGenerated &&
+ if (FLAG_irregexp_optimization &&
+ trace_count_ < kMaxCopiesCodeGenerated &&
compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) {
return CONTINUE;
}
@@ -2067,11 +2063,12 @@
void NegativeLookaheadChoiceNode::GetQuickCheckDetails(
QuickCheckDetails* details,
RegExpCompiler* compiler,
- int filled_in) {
+ int filled_in,
+ bool not_at_start) {
// Alternative 0 is the negative lookahead, alternative 1 is what comes
// afterwards.
RegExpNode* node = alternatives_->at(1).node();
- return node->GetQuickCheckDetails(details, compiler, filled_in);
+ return node->GetQuickCheckDetails(details, compiler, filled_in, not_at_start);
}
@@ -2144,7 +2141,8 @@
QuickCheckDetails* details,
bool fall_through_on_failure) {
if (details->characters() == 0) return false;
- GetQuickCheckDetails(details, compiler, 0);
+ GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE);
+ if (details->cannot_match()) return false;
if (!details->Rationalize(compiler->ascii())) return false;
uint32_t mask = details->mask();
uint32_t value = details->value();
@@ -2209,7 +2207,8 @@
// generating a quick check.
void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
- int characters_filled_in) {
+ int characters_filled_in,
+ bool not_at_start) {
ASSERT(characters_filled_in < details->characters());
int characters = details->characters();
int char_mask;
@@ -2321,7 +2320,10 @@
}
}
ASSERT(characters_filled_in != details->characters());
- on_success()-> GetQuickCheckDetails(details, compiler, characters_filled_in);
+ on_success()-> GetQuickCheckDetails(details,
+ compiler,
+ characters_filled_in,
+ true);
}
@@ -2358,6 +2360,13 @@
void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) {
ASSERT(characters_ == other->characters_);
+ if (other->cannot_match_) {
+ return;
+ }
+ if (cannot_match_) {
+ *this = *other;
+ return;
+ }
for (int i = from_index; i < characters_; i++) {
QuickCheckDetails::Position* pos = positions(i);
QuickCheckDetails::Position* other_pos = other->positions(i);
@@ -2394,27 +2403,34 @@
void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
- int characters_filled_in) {
+ int characters_filled_in,
+ bool not_at_start) {
if (body_can_be_zero_length_ || info()->visited) return;
VisitMarker marker(info());
return ChoiceNode::GetQuickCheckDetails(details,
compiler,
- characters_filled_in);
+ characters_filled_in,
+ not_at_start);
}
void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
- int characters_filled_in) {
+ int characters_filled_in,
+ bool not_at_start) {
+ not_at_start = (not_at_start || not_at_start_);
int choice_count = alternatives_->length();
ASSERT(choice_count > 0);
alternatives_->at(0).node()->GetQuickCheckDetails(details,
compiler,
- characters_filled_in);
+ characters_filled_in,
+ not_at_start);
for (int i = 1; i < choice_count; i++) {
QuickCheckDetails new_details(details->characters());
RegExpNode* node = alternatives_->at(i).node();
- node->GetQuickCheckDetails(&new_details, compiler, characters_filled_in);
+ node->GetQuickCheckDetails(&new_details, compiler,
+ characters_filled_in,
+ not_at_start);
// Here we merge the quick match details of the two branches.
details->Merge(&new_details, characters_filled_in);
}
@@ -2540,6 +2556,21 @@
}
+void AssertionNode::GetQuickCheckDetails(QuickCheckDetails* details,
+ RegExpCompiler* compiler,
+ int filled_in,
+ bool not_at_start) {
+ if (type_ == AT_START && not_at_start) {
+ details->set_cannot_match();
+ return;
+ }
+ return on_success()->GetQuickCheckDetails(details,
+ compiler,
+ filled_in,
+ not_at_start);
+}
+
+
void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
switch (type_) {
@@ -2550,9 +2581,20 @@
assembler->Bind(&ok);
break;
}
- case AT_START:
- assembler->CheckNotAtStart(trace->backtrack());
- break;
+ case AT_START: {
+ if (trace->at_start() == Trace::FALSE) {
+ assembler->GoTo(trace->backtrack());
+ return;
+ }
+ if (trace->at_start() == Trace::UNKNOWN) {
+ assembler->CheckNotAtStart(trace->backtrack());
+ Trace at_start_trace = *trace;
+ at_start_trace.set_at_start(true);
+ on_success()->Emit(compiler, &at_start_trace);
+ return;
+ }
+ }
+ break;
case AFTER_NEWLINE:
EmitHat(compiler, on_success(), trace);
return;
@@ -2771,6 +2813,7 @@
&bound_checked_to);
Trace successor_trace(*trace);
+ successor_trace.set_at_start(false);
successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
RecursionCheck rc(compiler);
on_success()->Emit(compiler, &successor_trace);
@@ -3064,6 +3107,8 @@
Label greedy_loop_label;
Trace counter_backtrack_trace;
counter_backtrack_trace.set_backtrack(&greedy_loop_label);
+ if (not_at_start()) counter_backtrack_trace.set_at_start(false);
+
if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
// Here we have special handling for greedy loops containing only text nodes
// and other simple nodes. These are handled by pushing the current
@@ -3078,6 +3123,7 @@
current_trace = &counter_backtrack_trace;
Label greedy_match_failed;
Trace greedy_match_trace;
+ if (not_at_start()) greedy_match_trace.set_at_start(false);
greedy_match_trace.set_backtrack(&greedy_match_failed);
Label loop_label;
macro_assembler->Bind(&loop_label);
@@ -3115,9 +3161,11 @@
new_trace.set_bound_checked_up_to(preload_characters);
}
new_trace.quick_check_performed()->Clear();
+ if (not_at_start_) new_trace.set_at_start(Trace::FALSE);
alt_gen->expects_preload = preload_is_current;
bool generate_full_check_inline = false;
- if (try_to_emit_quick_check_for_alternative(i) &&
+ if (FLAG_irregexp_optimization &&
+ try_to_emit_quick_check_for_alternative(i) &&
alternative.node()->EmitQuickCheck(compiler,
&new_trace,
preload_has_checked_bounds,
@@ -3137,6 +3185,11 @@
new_trace.set_bound_checked_up_to(preload_characters);
generate_full_check_inline = true;
}
+ } else if (alt_gen->quick_check_details.cannot_match()) {
+ if (i == choice_count - 1 && !greedy_loop) {
+ macro_assembler->GoTo(trace->backtrack());
+ }
+ continue;
} else {
// No quick check was generated. Put the full code here.
// If this is not the first choice then there could be slow checks from
@@ -3197,6 +3250,7 @@
Trace out_of_line_trace(*trace);
out_of_line_trace.set_characters_preloaded(preload_characters);
out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details);
+ if (not_at_start_) out_of_line_trace.set_at_start(Trace::FALSE);
ZoneList<Guard*>* guards = alternative.guards();
int guard_count = (guards == NULL) ? 0 : guards->length();
if (next_expects_preload) {
@@ -3866,7 +3920,8 @@
bool is_greedy,
RegExpTree* body,
RegExpCompiler* compiler,
- RegExpNode* on_success) {
+ RegExpNode* on_success,
+ bool not_at_start) {
// x{f, t} becomes this:
//
// (r++)<-.
@@ -3899,14 +3954,14 @@
bool needs_capture_clearing = !capture_registers.is_empty();
if (body_can_be_empty) {
body_start_reg = compiler->AllocateRegister();
- } else if (!needs_capture_clearing) {
+ } else if (FLAG_irregexp_optimization && !needs_capture_clearing) {
// Only unroll if there are no captures and the body can't be
// empty.
if (min > 0 && min <= kMaxUnrolledMinMatches) {
int new_max = (max == kInfinity) ? max : max - min;
// Recurse once to get the loop or optional matches after the fixed ones.
- RegExpNode* answer =
- ToNode(0, new_max, is_greedy, body, compiler, on_success);
+ RegExpNode* answer = ToNode(
+ 0, new_max, is_greedy, body, compiler, on_success, true);
// Unroll the forced matches from 0 to min. This can cause chains of
// TextNodes (which the parser does not generate). These should be
// combined if it turns out they hinder good code generation.
@@ -3931,6 +3986,7 @@
answer)));
}
answer = alternation;
+ if (not_at_start) alternation->set_not_at_start();
}
return answer;
}
@@ -3942,6 +3998,7 @@
? compiler->AllocateRegister()
: RegExpCompiler::kNoRegister;
LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0);
+ if (not_at_start) center->set_not_at_start();
RegExpNode* loop_return = needs_counter
? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
: static_cast<RegExpNode*>(center);
@@ -4762,12 +4819,26 @@
if (!data->tree->IsAnchored()) {
// Add a .*? at the beginning, outside the body capture, unless
// this expression is anchored at the beginning.
- node = RegExpQuantifier::ToNode(0,
- RegExpTree::kInfinity,
- false,
- new RegExpCharacterClass('*'),
- &compiler,
- captured_body);
+ RegExpNode* loop_node =
+ RegExpQuantifier::ToNode(0,
+ RegExpTree::kInfinity,
+ false,
+ new RegExpCharacterClass('*'),
+ &compiler,
+ captured_body,
+ data->contains_anchor);
+
+ if (data->contains_anchor) {
+ // Unroll loop once, to take care of the case that might start
+ // at the start of input.
+ ChoiceNode* first_step_node = new ChoiceNode(2);
+ first_step_node->AddAlternative(GuardedAlternative(captured_body));
+ first_step_node->AddAlternative(GuardedAlternative(
+ new TextNode(new RegExpCharacterClass('*'), loop_node)));
+ node = first_step_node;
+ } else {
+ node = loop_node;
+ }
}
data->node = node;
Analysis analysis(ignore_case);