| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 4798 EmbeddedVector<byte, 1024> codes; | 4869 EmbeddedVector<byte, 1024> codes; |
| 4799 RegExpMacroAssemblerIrregexp macro_assembler(codes); | 4870 RegExpMacroAssemblerIrregexp macro_assembler(codes); |
| 4800 return compiler.Assemble(¯o_assembler, | 4871 return compiler.Assemble(¯o_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 |
| OLD | NEW |