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

Side by Side Diff: src/jsregexp.cc

Issue 19539: Irregexp: Added derived knowledge of whether we are at the start of input. (Closed)
Patch Set: Fixed lint issues. Created 11 years, 10 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
« no previous file with comments | « src/jsregexp.h ('k') | src/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 Handle<String> pattern) { 1262 Handle<String> pattern) {
1263 #ifdef DEBUG 1263 #ifdef DEBUG
1264 if (FLAG_trace_regexp_assembler) 1264 if (FLAG_trace_regexp_assembler)
1265 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); 1265 macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler);
1266 else 1266 else
1267 #endif 1267 #endif
1268 macro_assembler_ = macro_assembler; 1268 macro_assembler_ = macro_assembler;
1269 List <RegExpNode*> work_list(0); 1269 List <RegExpNode*> work_list(0);
1270 work_list_ = &work_list; 1270 work_list_ = &work_list;
1271 Label fail; 1271 Label fail;
1272 macro_assembler->PushBacktrack(&fail); 1272 macro_assembler_->PushBacktrack(&fail);
1273 Trace new_trace; 1273 Trace new_trace;
1274 start->Emit(this, &new_trace); 1274 start->Emit(this, &new_trace);
1275 macro_assembler_->Bind(&fail); 1275 macro_assembler_->Bind(&fail);
1276 macro_assembler_->Fail(); 1276 macro_assembler_->Fail();
1277 while (!work_list.is_empty()) { 1277 while (!work_list.is_empty()) {
1278 work_list.RemoveLast()->Emit(this, &new_trace); 1278 work_list.RemoveLast()->Emit(this, &new_trace);
1279 } 1279 }
1280 if (reg_exp_too_big_) return IrregexpRegExpTooBig(pattern); 1280 if (reg_exp_too_big_) return IrregexpRegExpTooBig(pattern);
1281 Handle<FixedArray> array = 1281 Handle<FixedArray> array =
1282 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength); 1282 Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength);
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after
2061 // Alternative 0 is the negative lookahead, alternative 1 is what comes 2061 // Alternative 0 is the negative lookahead, alternative 1 is what comes
2062 // afterwards. 2062 // afterwards.
2063 RegExpNode* node = alternatives_->at(1).node(); 2063 RegExpNode* node = alternatives_->at(1).node();
2064 return node->EatsAtLeast(still_to_find, recursion_depth + 1); 2064 return node->EatsAtLeast(still_to_find, recursion_depth + 1);
2065 } 2065 }
2066 2066
2067 2067
2068 void NegativeLookaheadChoiceNode::GetQuickCheckDetails( 2068 void NegativeLookaheadChoiceNode::GetQuickCheckDetails(
2069 QuickCheckDetails* details, 2069 QuickCheckDetails* details,
2070 RegExpCompiler* compiler, 2070 RegExpCompiler* compiler,
2071 int filled_in) { 2071 int filled_in,
2072 bool not_at_start) {
2072 // Alternative 0 is the negative lookahead, alternative 1 is what comes 2073 // Alternative 0 is the negative lookahead, alternative 1 is what comes
2073 // afterwards. 2074 // afterwards.
2074 RegExpNode* node = alternatives_->at(1).node(); 2075 RegExpNode* node = alternatives_->at(1).node();
2075 return node->GetQuickCheckDetails(details, compiler, filled_in); 2076 return node->GetQuickCheckDetails(details, compiler, filled_in, not_at_start);
2076 } 2077 }
2077 2078
2078 2079
2079 int ChoiceNode::EatsAtLeastHelper(int still_to_find, 2080 int ChoiceNode::EatsAtLeastHelper(int still_to_find,
2080 int recursion_depth, 2081 int recursion_depth,
2081 RegExpNode* ignore_this_node) { 2082 RegExpNode* ignore_this_node) {
2082 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0; 2083 if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
2083 int min = 100; 2084 int min = 100;
2084 int choice_count = alternatives_->length(); 2085 int choice_count = alternatives_->length();
2085 for (int i = 0; i < choice_count; i++) { 2086 for (int i = 0; i < choice_count; i++) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
2138 } 2139 }
2139 2140
2140 2141
2141 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, 2142 bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
2142 Trace* trace, 2143 Trace* trace,
2143 bool preload_has_checked_bounds, 2144 bool preload_has_checked_bounds,
2144 Label* on_possible_success, 2145 Label* on_possible_success,
2145 QuickCheckDetails* details, 2146 QuickCheckDetails* details,
2146 bool fall_through_on_failure) { 2147 bool fall_through_on_failure) {
2147 if (details->characters() == 0) return false; 2148 if (details->characters() == 0) return false;
2148 GetQuickCheckDetails(details, compiler, 0); 2149 GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE);
2150 if (details->cannot_match()) return false;
2149 if (!details->Rationalize(compiler->ascii())) return false; 2151 if (!details->Rationalize(compiler->ascii())) return false;
2150 uint32_t mask = details->mask(); 2152 uint32_t mask = details->mask();
2151 uint32_t value = details->value(); 2153 uint32_t value = details->value();
2152 2154
2153 RegExpMacroAssembler* assembler = compiler->macro_assembler(); 2155 RegExpMacroAssembler* assembler = compiler->macro_assembler();
2154 2156
2155 if (trace->characters_preloaded() != details->characters()) { 2157 if (trace->characters_preloaded() != details->characters()) {
2156 assembler->LoadCurrentCharacter(trace->cp_offset(), 2158 assembler->LoadCurrentCharacter(trace->cp_offset(),
2157 trace->backtrack(), 2159 trace->backtrack(),
2158 !preload_has_checked_bounds, 2160 !preload_has_checked_bounds,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2203 // Here is the meat of GetQuickCheckDetails (see also the comment on the 2205 // Here is the meat of GetQuickCheckDetails (see also the comment on the
2204 // super-class in the .h file). 2206 // super-class in the .h file).
2205 // 2207 //
2206 // We iterate along the text object, building up for each character a 2208 // We iterate along the text object, building up for each character a
2207 // mask and value that can be used to test for a quick failure to match. 2209 // mask and value that can be used to test for a quick failure to match.
2208 // The masks and values for the positions will be combined into a single 2210 // The masks and values for the positions will be combined into a single
2209 // machine word for the current character width in order to be used in 2211 // machine word for the current character width in order to be used in
2210 // generating a quick check. 2212 // generating a quick check.
2211 void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, 2213 void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
2212 RegExpCompiler* compiler, 2214 RegExpCompiler* compiler,
2213 int characters_filled_in) { 2215 int characters_filled_in,
2216 bool not_at_start) {
2214 ASSERT(characters_filled_in < details->characters()); 2217 ASSERT(characters_filled_in < details->characters());
2215 int characters = details->characters(); 2218 int characters = details->characters();
2216 int char_mask; 2219 int char_mask;
2217 int char_shift; 2220 int char_shift;
2218 if (compiler->ascii()) { 2221 if (compiler->ascii()) {
2219 char_mask = String::kMaxAsciiCharCode; 2222 char_mask = String::kMaxAsciiCharCode;
2220 char_shift = 8; 2223 char_shift = 8;
2221 } else { 2224 } else {
2222 char_mask = String::kMaxUC16CharCode; 2225 char_mask = String::kMaxUC16CharCode;
2223 char_shift = 16; 2226 char_shift = 16;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
2315 pos->value = bits; 2318 pos->value = bits;
2316 } 2319 }
2317 characters_filled_in++; 2320 characters_filled_in++;
2318 ASSERT(characters_filled_in <= details->characters()); 2321 ASSERT(characters_filled_in <= details->characters());
2319 if (characters_filled_in == details->characters()) { 2322 if (characters_filled_in == details->characters()) {
2320 return; 2323 return;
2321 } 2324 }
2322 } 2325 }
2323 } 2326 }
2324 ASSERT(characters_filled_in != details->characters()); 2327 ASSERT(characters_filled_in != details->characters());
2325 on_success()-> GetQuickCheckDetails(details, compiler, characters_filled_in); 2328 on_success()-> GetQuickCheckDetails(details,
2329 compiler,
2330 characters_filled_in,
2331 true);
2326 } 2332 }
2327 2333
2328 2334
2329 void QuickCheckDetails::Clear() { 2335 void QuickCheckDetails::Clear() {
2330 for (int i = 0; i < characters_; i++) { 2336 for (int i = 0; i < characters_; i++) {
2331 positions_[i].mask = 0; 2337 positions_[i].mask = 0;
2332 positions_[i].value = 0; 2338 positions_[i].value = 0;
2333 positions_[i].determines_perfectly = false; 2339 positions_[i].determines_perfectly = false;
2334 } 2340 }
2335 characters_ = 0; 2341 characters_ = 0;
(...skipping 16 matching lines...) Expand all
2352 } 2358 }
2353 characters_ -= by; 2359 characters_ -= by;
2354 // We could change mask_ and value_ here but we would never advance unless 2360 // We could change mask_ and value_ here but we would never advance unless
2355 // they had already been used in a check and they won't be used again because 2361 // they had already been used in a check and they won't be used again because
2356 // it would gain us nothing. So there's no point. 2362 // it would gain us nothing. So there's no point.
2357 } 2363 }
2358 2364
2359 2365
2360 void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) { 2366 void QuickCheckDetails::Merge(QuickCheckDetails* other, int from_index) {
2361 ASSERT(characters_ == other->characters_); 2367 ASSERT(characters_ == other->characters_);
2368 if (other->cannot_match_) {
2369 return;
2370 }
2371 if (cannot_match_) {
2372 *this = *other;
2373 return;
2374 }
2362 for (int i = from_index; i < characters_; i++) { 2375 for (int i = from_index; i < characters_; i++) {
2363 QuickCheckDetails::Position* pos = positions(i); 2376 QuickCheckDetails::Position* pos = positions(i);
2364 QuickCheckDetails::Position* other_pos = other->positions(i); 2377 QuickCheckDetails::Position* other_pos = other->positions(i);
2365 if (pos->mask != other_pos->mask || 2378 if (pos->mask != other_pos->mask ||
2366 pos->value != other_pos->value || 2379 pos->value != other_pos->value ||
2367 !other_pos->determines_perfectly) { 2380 !other_pos->determines_perfectly) {
2368 // Our mask-compare operation will be approximate unless we have the 2381 // Our mask-compare operation will be approximate unless we have the
2369 // exact same operation on both sides of the alternation. 2382 // exact same operation on both sides of the alternation.
2370 pos->determines_perfectly = false; 2383 pos->determines_perfectly = false;
2371 } 2384 }
(...skipping 16 matching lines...) Expand all
2388 ~VisitMarker() { 2401 ~VisitMarker() {
2389 info_->visited = false; 2402 info_->visited = false;
2390 } 2403 }
2391 private: 2404 private:
2392 NodeInfo* info_; 2405 NodeInfo* info_;
2393 }; 2406 };
2394 2407
2395 2408
2396 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, 2409 void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
2397 RegExpCompiler* compiler, 2410 RegExpCompiler* compiler,
2398 int characters_filled_in) { 2411 int characters_filled_in,
2412 bool not_at_start) {
2399 if (body_can_be_zero_length_ || info()->visited) return; 2413 if (body_can_be_zero_length_ || info()->visited) return;
2400 VisitMarker marker(info()); 2414 VisitMarker marker(info());
2401 return ChoiceNode::GetQuickCheckDetails(details, 2415 return ChoiceNode::GetQuickCheckDetails(details,
2402 compiler, 2416 compiler,
2403 characters_filled_in); 2417 characters_filled_in,
2418 not_at_start);
2404 } 2419 }
2405 2420
2406 2421
2407 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, 2422 void ChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
2408 RegExpCompiler* compiler, 2423 RegExpCompiler* compiler,
2409 int characters_filled_in) { 2424 int characters_filled_in,
2425 bool not_at_start) {
2426 not_at_start = not_at_start || not_at_start_;
2410 int choice_count = alternatives_->length(); 2427 int choice_count = alternatives_->length();
2411 ASSERT(choice_count > 0); 2428 ASSERT(choice_count > 0);
2412 alternatives_->at(0).node()->GetQuickCheckDetails(details, 2429 alternatives_->at(0).node()->GetQuickCheckDetails(details,
2413 compiler, 2430 compiler,
2414 characters_filled_in); 2431 characters_filled_in,
2432 not_at_start);
2415 for (int i = 1; i < choice_count; i++) { 2433 for (int i = 1; i < choice_count; i++) {
2416 QuickCheckDetails new_details(details->characters()); 2434 QuickCheckDetails new_details(details->characters());
2417 RegExpNode* node = alternatives_->at(i).node(); 2435 RegExpNode* node = alternatives_->at(i).node();
2418 node->GetQuickCheckDetails(&new_details, compiler, characters_filled_in); 2436 node->GetQuickCheckDetails(&new_details, compiler,
2437 characters_filled_in,
2438 not_at_start);
2419 // Here we merge the quick match details of the two branches. 2439 // Here we merge the quick match details of the two branches.
2420 details->Merge(&new_details, characters_filled_in); 2440 details->Merge(&new_details, characters_filled_in);
2421 } 2441 }
2422 } 2442 }
2423 2443
2424 2444
2425 // Check for [0-9A-Z_a-z]. 2445 // Check for [0-9A-Z_a-z].
2426 static void EmitWordCheck(RegExpMacroAssembler* assembler, 2446 static void EmitWordCheck(RegExpMacroAssembler* assembler,
2427 Label* word, 2447 Label* word,
2428 Label* non_word, 2448 Label* non_word,
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
2534 false); 2554 false);
2535 bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY); 2555 bool fall_through_on_word = (type == AssertionNode::AT_NON_BOUNDARY);
2536 EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word); 2556 EmitWordCheck(assembler, not_boundary, boundary, fall_through_on_word);
2537 2557
2538 assembler->Bind(&ok); 2558 assembler->Bind(&ok);
2539 2559
2540 on_success->Emit(compiler, &new_trace); 2560 on_success->Emit(compiler, &new_trace);
2541 } 2561 }
2542 2562
2543 2563
2564 void AssertionNode::GetQuickCheckDetails(QuickCheckDetails* details,
2565 RegExpCompiler* compiler,
2566 int filled_in,
2567 bool not_at_start) {
2568 if (type_ == AT_START && not_at_start) {
2569 details->set_cannot_match();
2570 return;
2571 }
2572 return on_success()->GetQuickCheckDetails(details,
2573 compiler,
2574 filled_in,
2575 not_at_start);
2576 }
2577
2578
2544 void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) { 2579 void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
2545 RegExpMacroAssembler* assembler = compiler->macro_assembler(); 2580 RegExpMacroAssembler* assembler = compiler->macro_assembler();
2546 switch (type_) { 2581 switch (type_) {
2547 case AT_END: { 2582 case AT_END: {
2548 Label ok; 2583 Label ok;
2549 assembler->CheckPosition(trace->cp_offset(), &ok); 2584 assembler->CheckPosition(trace->cp_offset(), &ok);
2550 assembler->GoTo(trace->backtrack()); 2585 assembler->GoTo(trace->backtrack());
2551 assembler->Bind(&ok); 2586 assembler->Bind(&ok);
2552 break; 2587 break;
2553 } 2588 }
2554 case AT_START: 2589 case AT_START: {
2555 assembler->CheckNotAtStart(trace->backtrack()); 2590 if (trace->at_start() == Trace::FALSE) {
2556 break; 2591 assembler->GoTo(trace->backtrack());
2592 return;
2593 }
2594 if (trace->at_start() == Trace::UNKNOWN) {
2595 assembler->CheckNotAtStart(trace->backtrack());
2596 Trace at_start_trace = *trace;
2597 at_start_trace.set_at_start(true);
2598 on_success()->Emit(compiler, &at_start_trace);
2599 return;
2600 }
2601 }
2602 break;
2557 case AFTER_NEWLINE: 2603 case AFTER_NEWLINE:
2558 EmitHat(compiler, on_success(), trace); 2604 EmitHat(compiler, on_success(), trace);
2559 return; 2605 return;
2560 case AT_NON_BOUNDARY: 2606 case AT_NON_BOUNDARY:
2561 case AT_BOUNDARY: 2607 case AT_BOUNDARY:
2562 EmitBoundaryCheck(type_, compiler, on_success(), trace); 2608 EmitBoundaryCheck(type_, compiler, on_success(), trace);
2563 return; 2609 return;
2564 } 2610 }
2565 on_success()->Emit(compiler, trace); 2611 on_success()->Emit(compiler, trace);
2566 } 2612 }
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
2765 &bound_checked_to); 2811 &bound_checked_to);
2766 } 2812 }
2767 TextEmitPass(compiler, 2813 TextEmitPass(compiler,
2768 CHARACTER_CLASS_MATCH, 2814 CHARACTER_CLASS_MATCH,
2769 false, 2815 false,
2770 trace, 2816 trace,
2771 first_elt_done, 2817 first_elt_done,
2772 &bound_checked_to); 2818 &bound_checked_to);
2773 2819
2774 Trace successor_trace(*trace); 2820 Trace successor_trace(*trace);
2821 successor_trace.set_at_start(false);
2775 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler); 2822 successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
2776 RecursionCheck rc(compiler); 2823 RecursionCheck rc(compiler);
2777 on_success()->Emit(compiler, &successor_trace); 2824 on_success()->Emit(compiler, &successor_trace);
2778 } 2825 }
2779 2826
2780 2827
2781 void Trace::InvalidateCurrentCharacter() { 2828 void Trace::InvalidateCurrentCharacter() {
2782 characters_preloaded_ = 0; 2829 characters_preloaded_ = 0;
2783 } 2830 }
2784 2831
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
3058 3105
3059 RecursionCheck rc(compiler); 3106 RecursionCheck rc(compiler);
3060 3107
3061 Trace* current_trace = trace; 3108 Trace* current_trace = trace;
3062 3109
3063 int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); 3110 int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
3064 bool greedy_loop = false; 3111 bool greedy_loop = false;
3065 Label greedy_loop_label; 3112 Label greedy_loop_label;
3066 Trace counter_backtrack_trace; 3113 Trace counter_backtrack_trace;
3067 counter_backtrack_trace.set_backtrack(&greedy_loop_label); 3114 counter_backtrack_trace.set_backtrack(&greedy_loop_label);
3115 if (not_at_start()) counter_backtrack_trace.set_at_start(false);
3116
3068 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) { 3117 if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
3069 // Here we have special handling for greedy loops containing only text nodes 3118 // Here we have special handling for greedy loops containing only text nodes
3070 // and other simple nodes. These are handled by pushing the current 3119 // and other simple nodes. These are handled by pushing the current
3071 // position on the stack and then incrementing the current position each 3120 // position on the stack and then incrementing the current position each
3072 // time around the switch. On backtrack we decrement the current position 3121 // time around the switch. On backtrack we decrement the current position
3073 // and check it against the pushed value. This avoids pushing backtrack 3122 // and check it against the pushed value. This avoids pushing backtrack
3074 // information for each iteration of the loop, which could take up a lot of 3123 // information for each iteration of the loop, which could take up a lot of
3075 // space. 3124 // space.
3076 greedy_loop = true; 3125 greedy_loop = true;
3077 ASSERT(trace->stop_node() == NULL); 3126 ASSERT(trace->stop_node() == NULL);
3078 macro_assembler->PushCurrentPosition(); 3127 macro_assembler->PushCurrentPosition();
3079 current_trace = &counter_backtrack_trace; 3128 current_trace = &counter_backtrack_trace;
3080 Label greedy_match_failed; 3129 Label greedy_match_failed;
3081 Trace greedy_match_trace; 3130 Trace greedy_match_trace;
3131 if (not_at_start()) greedy_match_trace.set_at_start(false);
3082 greedy_match_trace.set_backtrack(&greedy_match_failed); 3132 greedy_match_trace.set_backtrack(&greedy_match_failed);
3083 Label loop_label; 3133 Label loop_label;
3084 macro_assembler->Bind(&loop_label); 3134 macro_assembler->Bind(&loop_label);
3085 greedy_match_trace.set_stop_node(this); 3135 greedy_match_trace.set_stop_node(this);
3086 greedy_match_trace.set_loop_label(&loop_label); 3136 greedy_match_trace.set_loop_label(&loop_label);
3087 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace); 3137 alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
3088 macro_assembler->Bind(&greedy_match_failed); 3138 macro_assembler->Bind(&greedy_match_failed);
3089 } 3139 }
3090 3140
3091 Label second_choice; // For use in greedy matches. 3141 Label second_choice; // For use in greedy matches.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3132 // On the last choice in the ChoiceNode we generated the quick 3182 // On the last choice in the ChoiceNode we generated the quick
3133 // check to fall through on possible success. So now we need to 3183 // check to fall through on possible success. So now we need to
3134 // generate the full check inline. 3184 // generate the full check inline.
3135 if (i == choice_count - 1) { 3185 if (i == choice_count - 1) {
3136 macro_assembler->Bind(&alt_gen->possible_success); 3186 macro_assembler->Bind(&alt_gen->possible_success);
3137 new_trace.set_quick_check_performed(&alt_gen->quick_check_details); 3187 new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
3138 new_trace.set_characters_preloaded(preload_characters); 3188 new_trace.set_characters_preloaded(preload_characters);
3139 new_trace.set_bound_checked_up_to(preload_characters); 3189 new_trace.set_bound_checked_up_to(preload_characters);
3140 generate_full_check_inline = true; 3190 generate_full_check_inline = true;
3141 } 3191 }
3192 } else if (alt_gen->quick_check_details.cannot_match()) {
3193 if (i == choice_count - 1 && !greedy_loop) {
3194 macro_assembler->GoTo(trace->backtrack());
3195 }
3196 continue;
3142 } else { 3197 } else {
3143 // No quick check was generated. Put the full code here. 3198 // No quick check was generated. Put the full code here.
3144 // If this is not the first choice then there could be slow checks from 3199 // If this is not the first choice then there could be slow checks from
3145 // previous cases that go here when they fail. There's no reason to 3200 // previous cases that go here when they fail. There's no reason to
3146 // insist that they preload characters since the slow check we are about 3201 // insist that they preload characters since the slow check we are about
3147 // to generate probably can't use it. 3202 // to generate probably can't use it.
3148 if (i != first_normal_choice) { 3203 if (i != first_normal_choice) {
3149 alt_gen->expects_preload = false; 3204 alt_gen->expects_preload = false;
3150 new_trace.set_characters_preloaded(0); 3205 new_trace.set_characters_preloaded(0);
3151 } 3206 }
(...skipping 709 matching lines...) Expand 10 before | Expand all | Expand 10 after
3861 compiler, 3916 compiler,
3862 on_success); 3917 on_success);
3863 } 3918 }
3864 3919
3865 3920
3866 RegExpNode* RegExpQuantifier::ToNode(int min, 3921 RegExpNode* RegExpQuantifier::ToNode(int min,
3867 int max, 3922 int max,
3868 bool is_greedy, 3923 bool is_greedy,
3869 RegExpTree* body, 3924 RegExpTree* body,
3870 RegExpCompiler* compiler, 3925 RegExpCompiler* compiler,
3871 RegExpNode* on_success) { 3926 RegExpNode* on_success,
3927 bool not_at_start) {
3872 // x{f, t} becomes this: 3928 // x{f, t} becomes this:
3873 // 3929 //
3874 // (r++)<-. 3930 // (r++)<-.
3875 // | ` 3931 // | `
3876 // | (x) 3932 // | (x)
3877 // v ^ 3933 // v ^
3878 // (r=0)-->(?)---/ [if r < t] 3934 // (r=0)-->(?)---/ [if r < t]
3879 // | 3935 // |
3880 // [if r >= f] \----> ... 3936 // [if r >= f] \----> ...
3881 // 3937 //
(...skipping 18 matching lines...) Expand all
3900 Interval capture_registers = body->CaptureRegisters(); 3956 Interval capture_registers = body->CaptureRegisters();
3901 bool needs_capture_clearing = !capture_registers.is_empty(); 3957 bool needs_capture_clearing = !capture_registers.is_empty();
3902 if (body_can_be_empty) { 3958 if (body_can_be_empty) {
3903 body_start_reg = compiler->AllocateRegister(); 3959 body_start_reg = compiler->AllocateRegister();
3904 } else if (FLAG_irregexp_optimization && !needs_capture_clearing) { 3960 } else if (FLAG_irregexp_optimization && !needs_capture_clearing) {
3905 // Only unroll if there are no captures and the body can't be 3961 // Only unroll if there are no captures and the body can't be
3906 // empty. 3962 // empty.
3907 if (min > 0 && min <= kMaxUnrolledMinMatches) { 3963 if (min > 0 && min <= kMaxUnrolledMinMatches) {
3908 int new_max = (max == kInfinity) ? max : max - min; 3964 int new_max = (max == kInfinity) ? max : max - min;
3909 // Recurse once to get the loop or optional matches after the fixed ones. 3965 // Recurse once to get the loop or optional matches after the fixed ones.
3910 RegExpNode* answer = 3966 RegExpNode* answer = ToNode(
3911 ToNode(0, new_max, is_greedy, body, compiler, on_success); 3967 0, new_max, is_greedy, body, compiler, on_success, true);
3912 // Unroll the forced matches from 0 to min. This can cause chains of 3968 // Unroll the forced matches from 0 to min. This can cause chains of
3913 // TextNodes (which the parser does not generate). These should be 3969 // TextNodes (which the parser does not generate). These should be
3914 // combined if it turns out they hinder good code generation. 3970 // combined if it turns out they hinder good code generation.
3915 for (int i = 0; i < min; i++) { 3971 for (int i = 0; i < min; i++) {
3916 answer = body->ToNode(compiler, answer); 3972 answer = body->ToNode(compiler, answer);
3917 } 3973 }
3918 return answer; 3974 return answer;
3919 } 3975 }
3920 if (max <= kMaxUnrolledMaxMatches) { 3976 if (max <= kMaxUnrolledMaxMatches) {
3921 ASSERT(min == 0); 3977 ASSERT(min == 0);
3922 // Unroll the optional matches up to max. 3978 // Unroll the optional matches up to max.
3923 RegExpNode* answer = on_success; 3979 RegExpNode* answer = on_success;
3924 for (int i = 0; i < max; i++) { 3980 for (int i = 0; i < max; i++) {
3925 ChoiceNode* alternation = new ChoiceNode(2); 3981 ChoiceNode* alternation = new ChoiceNode(2);
3926 if (is_greedy) { 3982 if (is_greedy) {
3927 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, 3983 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler,
3928 answer))); 3984 answer)));
3929 alternation->AddAlternative(GuardedAlternative(on_success)); 3985 alternation->AddAlternative(GuardedAlternative(on_success));
3930 } else { 3986 } else {
3931 alternation->AddAlternative(GuardedAlternative(on_success)); 3987 alternation->AddAlternative(GuardedAlternative(on_success));
3932 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, 3988 alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler,
3933 answer))); 3989 answer)));
3934 } 3990 }
3935 answer = alternation; 3991 answer = alternation;
3992 if (not_at_start) alternation->set_not_at_start();
3936 } 3993 }
3937 return answer; 3994 return answer;
3938 } 3995 }
3939 } 3996 }
3940 bool has_min = min > 0; 3997 bool has_min = min > 0;
3941 bool has_max = max < RegExpTree::kInfinity; 3998 bool has_max = max < RegExpTree::kInfinity;
3942 bool needs_counter = has_min || has_max; 3999 bool needs_counter = has_min || has_max;
3943 int reg_ctr = needs_counter 4000 int reg_ctr = needs_counter
3944 ? compiler->AllocateRegister() 4001 ? compiler->AllocateRegister()
3945 : RegExpCompiler::kNoRegister; 4002 : RegExpCompiler::kNoRegister;
3946 LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0); 4003 LoopChoiceNode* center = new LoopChoiceNode(body->min_match() == 0);
4004 if (not_at_start) center->set_not_at_start();
3947 RegExpNode* loop_return = needs_counter 4005 RegExpNode* loop_return = needs_counter
3948 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) 4006 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
3949 : static_cast<RegExpNode*>(center); 4007 : static_cast<RegExpNode*>(center);
3950 if (body_can_be_empty) { 4008 if (body_can_be_empty) {
3951 // If the body can be empty we need to check if it was and then 4009 // If the body can be empty we need to check if it was and then
3952 // backtrack. 4010 // backtrack.
3953 loop_return = ActionNode::EmptyMatchCheck(body_start_reg, 4011 loop_return = ActionNode::EmptyMatchCheck(body_start_reg,
3954 reg_ctr, 4012 reg_ctr,
3955 min, 4013 min,
3956 loop_return); 4014 loop_return);
(...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after
4757 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii); 4815 RegExpCompiler compiler(data->capture_count, ignore_case, is_ascii);
4758 // Wrap the body of the regexp in capture #0. 4816 // Wrap the body of the regexp in capture #0.
4759 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, 4817 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree,
4760 0, 4818 0,
4761 &compiler, 4819 &compiler,
4762 compiler.accept()); 4820 compiler.accept());
4763 RegExpNode* node = captured_body; 4821 RegExpNode* node = captured_body;
4764 if (!data->tree->IsAnchored()) { 4822 if (!data->tree->IsAnchored()) {
4765 // Add a .*? at the beginning, outside the body capture, unless 4823 // Add a .*? at the beginning, outside the body capture, unless
4766 // this expression is anchored at the beginning. 4824 // this expression is anchored at the beginning.
4767 node = RegExpQuantifier::ToNode(0, 4825 RegExpNode* loop_node =
4768 RegExpTree::kInfinity, 4826 RegExpQuantifier::ToNode(0,
4769 false, 4827 RegExpTree::kInfinity,
4770 new RegExpCharacterClass('*'), 4828 false,
4771 &compiler, 4829 new RegExpCharacterClass('*'),
4772 captured_body); 4830 &compiler,
4831 captured_body,
4832 data->contains_anchor);
4833
4834 if (data->contains_anchor) {
4835 // Unroll once, and tell the loop that it's not at the start of the input.
4836 ChoiceNode* first_step_node = new ChoiceNode(2);
4837 first_step_node->AddAlternative(GuardedAlternative(captured_body));
4838 first_step_node->AddAlternative(GuardedAlternative(
4839 new TextNode(new RegExpCharacterClass('*'), loop_node)));
4840 node = first_step_node;
4841 } else {
4842 node = loop_node;
4843 }
4773 } 4844 }
4774 data->node = node; 4845 data->node = node;
4775 Analysis analysis(ignore_case); 4846 Analysis analysis(ignore_case);
4776 analysis.EnsureAnalyzed(node); 4847 analysis.EnsureAnalyzed(node);
4777 4848
4778 NodeInfo info = *node->info(); 4849 NodeInfo info = *node->info();
4779 4850
4780 if (FLAG_irregexp_native) { 4851 if (FLAG_irregexp_native) {
4781 #ifdef ARM 4852 #ifdef ARM
4782 // Unimplemented, fall-through to bytecode implementation. 4853 // Unimplemented, fall-through to bytecode implementation.
(...skipping 15 matching lines...) Expand all
4798 EmbeddedVector<byte, 1024> codes; 4869 EmbeddedVector<byte, 1024> codes;
4799 RegExpMacroAssemblerIrregexp macro_assembler(codes); 4870 RegExpMacroAssemblerIrregexp macro_assembler(codes);
4800 return compiler.Assemble(&macro_assembler, 4871 return compiler.Assemble(&macro_assembler,
4801 node, 4872 node,
4802 data->capture_count, 4873 data->capture_count,
4803 pattern); 4874 pattern);
4804 } 4875 }
4805 4876
4806 4877
4807 }} // namespace v8::internal 4878 }} // namespace v8::internal
OLDNEW
« no previous file with comments | « src/jsregexp.h ('k') | src/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698