| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/regexp.h" | 5 #include "vm/regexp.h" |
| 6 | 6 |
| 7 #include "vm/dart_entry.h" | 7 #include "vm/dart_entry.h" |
| 8 #include "vm/regexp_assembler.h" | 8 #include "vm/regexp_assembler.h" |
| 9 #include "vm/regexp_ast.h" | 9 #include "vm/regexp_ast.h" |
| 10 #include "vm/unibrow-inl.h" | 10 #include "vm/unibrow-inl.h" |
| 11 #include "vm/unicode.h" | 11 #include "vm/unicode.h" |
| 12 #include "vm/symbols.h" | 12 #include "vm/symbols.h" |
| 13 #include "vm/thread.h" |
| 13 | 14 |
| 14 #define I (isolate()) | 15 #define Z (zone()) |
| 15 #define CI (compiler->isolate()) | |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 DECLARE_FLAG(bool, trace_irregexp); | 19 DECLARE_FLAG(bool, trace_irregexp); |
| 20 | 20 |
| 21 // Default to generating optimized regexp code. | 21 // Default to generating optimized regexp code. |
| 22 static const bool kRegexpOptimization = true; | 22 static const bool kRegexpOptimization = true; |
| 23 | 23 |
| 24 // More makes code generation slower, less makes V8 benchmark score lower. | 24 // More makes code generation slower, less makes V8 benchmark score lower. |
| 25 static const intptr_t kMaxLookaheadForBoyerMoore = 8; | 25 static const intptr_t kMaxLookaheadForBoyerMoore = 8; |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 specialization_cid_ == kExternalOneByteStringCid); | 327 specialization_cid_ == kExternalOneByteStringCid); |
| 328 } | 328 } |
| 329 inline intptr_t specialization_cid() { return specialization_cid_; } | 329 inline intptr_t specialization_cid() { return specialization_cid_; } |
| 330 FrequencyCollator* frequency_collator() { return &frequency_collator_; } | 330 FrequencyCollator* frequency_collator() { return &frequency_collator_; } |
| 331 | 331 |
| 332 intptr_t current_expansion_factor() { return current_expansion_factor_; } | 332 intptr_t current_expansion_factor() { return current_expansion_factor_; } |
| 333 void set_current_expansion_factor(intptr_t value) { | 333 void set_current_expansion_factor(intptr_t value) { |
| 334 current_expansion_factor_ = value; | 334 current_expansion_factor_ = value; |
| 335 } | 335 } |
| 336 | 336 |
| 337 Isolate* isolate() const { return isolate_; } | 337 Zone* zone() const { return zone_; } |
| 338 | 338 |
| 339 static const intptr_t kNoRegister = -1; | 339 static const intptr_t kNoRegister = -1; |
| 340 | 340 |
| 341 private: | 341 private: |
| 342 EndNode* accept_; | 342 EndNode* accept_; |
| 343 intptr_t next_register_; | 343 intptr_t next_register_; |
| 344 ZoneGrowableArray<RegExpNode*>* work_list_; | 344 ZoneGrowableArray<RegExpNode*>* work_list_; |
| 345 intptr_t recursion_depth_; | 345 intptr_t recursion_depth_; |
| 346 IRRegExpMacroAssembler* macro_assembler_; | 346 IRRegExpMacroAssembler* macro_assembler_; |
| 347 bool ignore_case_; | 347 bool ignore_case_; |
| 348 intptr_t specialization_cid_; | 348 intptr_t specialization_cid_; |
| 349 bool reg_exp_too_big_; | 349 bool reg_exp_too_big_; |
| 350 intptr_t current_expansion_factor_; | 350 intptr_t current_expansion_factor_; |
| 351 FrequencyCollator frequency_collator_; | 351 FrequencyCollator frequency_collator_; |
| 352 Isolate* isolate_; | 352 Zone* zone_; |
| 353 }; | 353 }; |
| 354 | 354 |
| 355 | 355 |
| 356 class RecursionCheck : public ValueObject { | 356 class RecursionCheck : public ValueObject { |
| 357 public: | 357 public: |
| 358 explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { | 358 explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { |
| 359 compiler->IncrementRecursionDepth(); | 359 compiler->IncrementRecursionDepth(); |
| 360 } | 360 } |
| 361 ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } | 361 ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } |
| 362 private: | 362 private: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 373 // a fixed array or a null handle depending on whether it succeeded. | 373 // a fixed array or a null handle depending on whether it succeeded. |
| 374 RegExpCompiler::RegExpCompiler(intptr_t capture_count, bool ignore_case, | 374 RegExpCompiler::RegExpCompiler(intptr_t capture_count, bool ignore_case, |
| 375 intptr_t specialization_cid) | 375 intptr_t specialization_cid) |
| 376 : next_register_(2 * (capture_count + 1)), | 376 : next_register_(2 * (capture_count + 1)), |
| 377 work_list_(NULL), | 377 work_list_(NULL), |
| 378 recursion_depth_(0), | 378 recursion_depth_(0), |
| 379 ignore_case_(ignore_case), | 379 ignore_case_(ignore_case), |
| 380 specialization_cid_(specialization_cid), | 380 specialization_cid_(specialization_cid), |
| 381 reg_exp_too_big_(false), | 381 reg_exp_too_big_(false), |
| 382 current_expansion_factor_(1), | 382 current_expansion_factor_(1), |
| 383 isolate_(Isolate::Current()) { | 383 zone_(Thread::Current()->zone()) { |
| 384 accept_ = new(I) EndNode(EndNode::ACCEPT, I); | 384 accept_ = new(Z) EndNode(EndNode::ACCEPT, Z); |
| 385 } | 385 } |
| 386 | 386 |
| 387 | 387 |
| 388 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | 388 RegExpEngine::CompilationResult RegExpCompiler::Assemble( |
| 389 IRRegExpMacroAssembler* macro_assembler, | 389 IRRegExpMacroAssembler* macro_assembler, |
| 390 RegExpNode* start, | 390 RegExpNode* start, |
| 391 intptr_t capture_count, | 391 intptr_t capture_count, |
| 392 const String& pattern) { | 392 const String& pattern) { |
| 393 static const bool use_slow_safe_regexp_compiler = false; | 393 static const bool use_slow_safe_regexp_compiler = false; |
| 394 | 394 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 } | 454 } |
| 455 } | 455 } |
| 456 return false; | 456 return false; |
| 457 } | 457 } |
| 458 | 458 |
| 459 | 459 |
| 460 // This is called as we come into a loop choice node and some other tricky | 460 // This is called as we come into a loop choice node and some other tricky |
| 461 // nodes. It normalizes the state of the code generator to ensure we can | 461 // nodes. It normalizes the state of the code generator to ensure we can |
| 462 // generate generic code. | 462 // generate generic code. |
| 463 intptr_t Trace::FindAffectedRegisters(OutSet* affected_registers, | 463 intptr_t Trace::FindAffectedRegisters(OutSet* affected_registers, |
| 464 Isolate* isolate) { | 464 Zone* zone) { |
| 465 intptr_t max_register = RegExpCompiler::kNoRegister; | 465 intptr_t max_register = RegExpCompiler::kNoRegister; |
| 466 for (DeferredAction* action = actions_; | 466 for (DeferredAction* action = actions_; |
| 467 action != NULL; | 467 action != NULL; |
| 468 action = action->next()) { | 468 action = action->next()) { |
| 469 if (action->action_type() == ActionNode::CLEAR_CAPTURES) { | 469 if (action->action_type() == ActionNode::CLEAR_CAPTURES) { |
| 470 Interval range = static_cast<DeferredClearCaptures*>(action)->range(); | 470 Interval range = static_cast<DeferredClearCaptures*>(action)->range(); |
| 471 for (intptr_t i = range.from(); i <= range.to(); i++) | 471 for (intptr_t i = range.from(); i <= range.to(); i++) |
| 472 affected_registers->Set(i, isolate); | 472 affected_registers->Set(i, zone); |
| 473 if (range.to() > max_register) max_register = range.to(); | 473 if (range.to() > max_register) max_register = range.to(); |
| 474 } else { | 474 } else { |
| 475 affected_registers->Set(action->reg(), isolate); | 475 affected_registers->Set(action->reg(), zone); |
| 476 if (action->reg() > max_register) max_register = action->reg(); | 476 if (action->reg() > max_register) max_register = action->reg(); |
| 477 } | 477 } |
| 478 } | 478 } |
| 479 return max_register; | 479 return max_register; |
| 480 } | 480 } |
| 481 | 481 |
| 482 | 482 |
| 483 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler, | 483 void Trace::RestoreAffectedRegisters(RegExpMacroAssembler* assembler, |
| 484 intptr_t max_register, | 484 intptr_t max_register, |
| 485 const OutSet& registers_to_pop, | 485 const OutSet& registers_to_pop, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 496 } | 496 } |
| 497 } | 497 } |
| 498 } | 498 } |
| 499 | 499 |
| 500 | 500 |
| 501 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler, | 501 void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler, |
| 502 intptr_t max_register, | 502 intptr_t max_register, |
| 503 const OutSet& affected_registers, | 503 const OutSet& affected_registers, |
| 504 OutSet* registers_to_pop, | 504 OutSet* registers_to_pop, |
| 505 OutSet* registers_to_clear, | 505 OutSet* registers_to_clear, |
| 506 Isolate* isolate) { | 506 Zone* zone) { |
| 507 for (intptr_t reg = 0; reg <= max_register; reg++) { | 507 for (intptr_t reg = 0; reg <= max_register; reg++) { |
| 508 if (!affected_registers.Get(reg)) { | 508 if (!affected_registers.Get(reg)) { |
| 509 continue; | 509 continue; |
| 510 } | 510 } |
| 511 | 511 |
| 512 // The chronologically first deferred action in the trace | 512 // The chronologically first deferred action in the trace |
| 513 // is used to infer the action needed to restore a register | 513 // is used to infer the action needed to restore a register |
| 514 // to its previous state (or not, if it's safe to ignore it). | 514 // to its previous state (or not, if it's safe to ignore it). |
| 515 enum DeferredActionUndoType { ACTION_IGNORE, ACTION_RESTORE, ACTION_CLEAR }; | 515 enum DeferredActionUndoType { ACTION_IGNORE, ACTION_RESTORE, ACTION_CLEAR }; |
| 516 DeferredActionUndoType undo_action = ACTION_IGNORE; | 516 DeferredActionUndoType undo_action = ACTION_IGNORE; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 } | 588 } |
| 589 default: | 589 default: |
| 590 UNREACHABLE(); | 590 UNREACHABLE(); |
| 591 break; | 591 break; |
| 592 } | 592 } |
| 593 } | 593 } |
| 594 } | 594 } |
| 595 // Prepare for the undo-action (e.g., push if it's going to be popped). | 595 // Prepare for the undo-action (e.g., push if it's going to be popped). |
| 596 if (undo_action == ACTION_RESTORE) { | 596 if (undo_action == ACTION_RESTORE) { |
| 597 assembler->PushRegister(reg); | 597 assembler->PushRegister(reg); |
| 598 registers_to_pop->Set(reg, isolate); | 598 registers_to_pop->Set(reg, zone); |
| 599 } else if (undo_action == ACTION_CLEAR) { | 599 } else if (undo_action == ACTION_CLEAR) { |
| 600 registers_to_clear->Set(reg, isolate); | 600 registers_to_clear->Set(reg, zone); |
| 601 } | 601 } |
| 602 // Perform the chronologically last action (or accumulated increment) | 602 // Perform the chronologically last action (or accumulated increment) |
| 603 // for the register. | 603 // for the register. |
| 604 if (store_position != -1) { | 604 if (store_position != -1) { |
| 605 assembler->WriteCurrentPositionToRegister(reg, store_position); | 605 assembler->WriteCurrentPositionToRegister(reg, store_position); |
| 606 } else if (clear) { | 606 } else if (clear) { |
| 607 assembler->ClearRegisters(reg, reg); | 607 assembler->ClearRegisters(reg, reg); |
| 608 } else if (absolute) { | 608 } else if (absolute) { |
| 609 assembler->SetRegister(reg, value); | 609 assembler->SetRegister(reg, value); |
| 610 } else if (value != 0) { | 610 } else if (value != 0) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 635 | 635 |
| 636 // Generate deferred actions here along with code to undo them again. | 636 // Generate deferred actions here along with code to undo them again. |
| 637 OutSet affected_registers; | 637 OutSet affected_registers; |
| 638 | 638 |
| 639 if (backtrack() != NULL) { | 639 if (backtrack() != NULL) { |
| 640 // Here we have a concrete backtrack location. These are set up by choice | 640 // Here we have a concrete backtrack location. These are set up by choice |
| 641 // nodes and so they indicate that we have a deferred save of the current | 641 // nodes and so they indicate that we have a deferred save of the current |
| 642 // position which we may need to emit here. | 642 // position which we may need to emit here. |
| 643 assembler->PushCurrentPosition(); | 643 assembler->PushCurrentPosition(); |
| 644 } | 644 } |
| 645 | 645 Zone* zone = successor->zone(); |
| 646 intptr_t max_register = FindAffectedRegisters(&affected_registers, CI); | 646 intptr_t max_register = FindAffectedRegisters(&affected_registers, zone); |
| 647 OutSet registers_to_pop; | 647 OutSet registers_to_pop; |
| 648 OutSet registers_to_clear; | 648 OutSet registers_to_clear; |
| 649 PerformDeferredActions(assembler, | 649 PerformDeferredActions(assembler, |
| 650 max_register, | 650 max_register, |
| 651 affected_registers, | 651 affected_registers, |
| 652 ®isters_to_pop, | 652 ®isters_to_pop, |
| 653 ®isters_to_clear, | 653 ®isters_to_clear, |
| 654 CI); | 654 zone); |
| 655 if (cp_offset_ != 0) { | 655 if (cp_offset_ != 0) { |
| 656 assembler->AdvanceCurrentPosition(cp_offset_); | 656 assembler->AdvanceCurrentPosition(cp_offset_); |
| 657 } | 657 } |
| 658 | 658 |
| 659 // Create a new trivial state and generate the node with that. | 659 // Create a new trivial state and generate the node with that. |
| 660 BlockLabel undo; | 660 BlockLabel undo; |
| 661 assembler->PushBacktrack(&undo); | 661 assembler->PushBacktrack(&undo); |
| 662 Trace new_state; | 662 Trace new_state; |
| 663 successor->Emit(compiler, &new_state); | 663 successor->Emit(compiler, &new_state); |
| 664 | 664 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 assembler->GoTo(trace->backtrack()); | 721 assembler->GoTo(trace->backtrack()); |
| 722 return; | 722 return; |
| 723 case NEGATIVE_SUBMATCH_SUCCESS: | 723 case NEGATIVE_SUBMATCH_SUCCESS: |
| 724 // This case is handled in a different virtual method. | 724 // This case is handled in a different virtual method. |
| 725 UNREACHABLE(); | 725 UNREACHABLE(); |
| 726 } | 726 } |
| 727 UNIMPLEMENTED(); | 727 UNIMPLEMENTED(); |
| 728 } | 728 } |
| 729 | 729 |
| 730 | 730 |
| 731 void GuardedAlternative::AddGuard(Guard* guard, Isolate* isolate) { | 731 void GuardedAlternative::AddGuard(Guard* guard, Zone* zone) { |
| 732 if (guards_ == NULL) | 732 if (guards_ == NULL) |
| 733 guards_ = new(isolate) ZoneGrowableArray<Guard*>(1); | 733 guards_ = new(zone) ZoneGrowableArray<Guard*>(1); |
| 734 guards_->Add(guard); | 734 guards_->Add(guard); |
| 735 } | 735 } |
| 736 | 736 |
| 737 | 737 |
| 738 ActionNode* ActionNode::SetRegister(intptr_t reg, | 738 ActionNode* ActionNode::SetRegister(intptr_t reg, |
| 739 intptr_t val, | 739 intptr_t val, |
| 740 RegExpNode* on_success) { | 740 RegExpNode* on_success) { |
| 741 ActionNode* result = | 741 ActionNode* result = |
| 742 new(on_success->isolate()) ActionNode(SET_REGISTER, on_success); | 742 new(on_success->zone()) ActionNode(SET_REGISTER, on_success); |
| 743 result->data_.u_store_register.reg = reg; | 743 result->data_.u_store_register.reg = reg; |
| 744 result->data_.u_store_register.value = val; | 744 result->data_.u_store_register.value = val; |
| 745 return result; | 745 return result; |
| 746 } | 746 } |
| 747 | 747 |
| 748 | 748 |
| 749 ActionNode* ActionNode::IncrementRegister(intptr_t reg, | 749 ActionNode* ActionNode::IncrementRegister(intptr_t reg, |
| 750 RegExpNode* on_success) { | 750 RegExpNode* on_success) { |
| 751 ActionNode* result = | 751 ActionNode* result = |
| 752 new(on_success->isolate()) ActionNode(INCREMENT_REGISTER, on_success); | 752 new(on_success->zone()) ActionNode(INCREMENT_REGISTER, on_success); |
| 753 result->data_.u_increment_register.reg = reg; | 753 result->data_.u_increment_register.reg = reg; |
| 754 return result; | 754 return result; |
| 755 } | 755 } |
| 756 | 756 |
| 757 | 757 |
| 758 ActionNode* ActionNode::StorePosition(intptr_t reg, | 758 ActionNode* ActionNode::StorePosition(intptr_t reg, |
| 759 bool is_capture, | 759 bool is_capture, |
| 760 RegExpNode* on_success) { | 760 RegExpNode* on_success) { |
| 761 ActionNode* result = | 761 ActionNode* result = |
| 762 new(on_success->isolate()) ActionNode(STORE_POSITION, on_success); | 762 new(on_success->zone()) ActionNode(STORE_POSITION, on_success); |
| 763 result->data_.u_position_register.reg = reg; | 763 result->data_.u_position_register.reg = reg; |
| 764 result->data_.u_position_register.is_capture = is_capture; | 764 result->data_.u_position_register.is_capture = is_capture; |
| 765 return result; | 765 return result; |
| 766 } | 766 } |
| 767 | 767 |
| 768 | 768 |
| 769 ActionNode* ActionNode::ClearCaptures(Interval range, | 769 ActionNode* ActionNode::ClearCaptures(Interval range, |
| 770 RegExpNode* on_success) { | 770 RegExpNode* on_success) { |
| 771 ActionNode* result = | 771 ActionNode* result = |
| 772 new(on_success->isolate()) ActionNode(CLEAR_CAPTURES, on_success); | 772 new(on_success->zone()) ActionNode(CLEAR_CAPTURES, on_success); |
| 773 result->data_.u_clear_captures.range_from = range.from(); | 773 result->data_.u_clear_captures.range_from = range.from(); |
| 774 result->data_.u_clear_captures.range_to = range.to(); | 774 result->data_.u_clear_captures.range_to = range.to(); |
| 775 return result; | 775 return result; |
| 776 } | 776 } |
| 777 | 777 |
| 778 | 778 |
| 779 ActionNode* ActionNode::BeginSubmatch(intptr_t stack_reg, | 779 ActionNode* ActionNode::BeginSubmatch(intptr_t stack_reg, |
| 780 intptr_t position_reg, | 780 intptr_t position_reg, |
| 781 RegExpNode* on_success) { | 781 RegExpNode* on_success) { |
| 782 ActionNode* result = | 782 ActionNode* result = |
| 783 new(on_success->isolate()) ActionNode(BEGIN_SUBMATCH, on_success); | 783 new(on_success->zone()) ActionNode(BEGIN_SUBMATCH, on_success); |
| 784 result->data_.u_submatch.stack_pointer_register = stack_reg; | 784 result->data_.u_submatch.stack_pointer_register = stack_reg; |
| 785 result->data_.u_submatch.current_position_register = position_reg; | 785 result->data_.u_submatch.current_position_register = position_reg; |
| 786 return result; | 786 return result; |
| 787 } | 787 } |
| 788 | 788 |
| 789 | 789 |
| 790 ActionNode* ActionNode::PositiveSubmatchSuccess(intptr_t stack_reg, | 790 ActionNode* ActionNode::PositiveSubmatchSuccess(intptr_t stack_reg, |
| 791 intptr_t position_reg, | 791 intptr_t position_reg, |
| 792 intptr_t clear_register_count, | 792 intptr_t clear_register_count, |
| 793 intptr_t clear_register_from, | 793 intptr_t clear_register_from, |
| 794 RegExpNode* on_success) { | 794 RegExpNode* on_success) { |
| 795 ActionNode* result = | 795 ActionNode* result = |
| 796 new(on_success->isolate()) ActionNode(POSITIVE_SUBMATCH_SUCCESS, | 796 new(on_success->zone()) ActionNode(POSITIVE_SUBMATCH_SUCCESS, |
| 797 on_success); | 797 on_success); |
| 798 result->data_.u_submatch.stack_pointer_register = stack_reg; | 798 result->data_.u_submatch.stack_pointer_register = stack_reg; |
| 799 result->data_.u_submatch.current_position_register = position_reg; | 799 result->data_.u_submatch.current_position_register = position_reg; |
| 800 result->data_.u_submatch.clear_register_count = clear_register_count; | 800 result->data_.u_submatch.clear_register_count = clear_register_count; |
| 801 result->data_.u_submatch.clear_register_from = clear_register_from; | 801 result->data_.u_submatch.clear_register_from = clear_register_from; |
| 802 return result; | 802 return result; |
| 803 } | 803 } |
| 804 | 804 |
| 805 | 805 |
| 806 ActionNode* ActionNode::EmptyMatchCheck(intptr_t start_register, | 806 ActionNode* ActionNode::EmptyMatchCheck(intptr_t start_register, |
| 807 intptr_t repetition_register, | 807 intptr_t repetition_register, |
| 808 intptr_t repetition_limit, | 808 intptr_t repetition_limit, |
| 809 RegExpNode* on_success) { | 809 RegExpNode* on_success) { |
| 810 ActionNode* result = | 810 ActionNode* result = |
| 811 new(on_success->isolate()) ActionNode(EMPTY_MATCH_CHECK, on_success); | 811 new(on_success->zone()) ActionNode(EMPTY_MATCH_CHECK, on_success); |
| 812 result->data_.u_empty_match_check.start_register = start_register; | 812 result->data_.u_empty_match_check.start_register = start_register; |
| 813 result->data_.u_empty_match_check.repetition_register = repetition_register; | 813 result->data_.u_empty_match_check.repetition_register = repetition_register; |
| 814 result->data_.u_empty_match_check.repetition_limit = repetition_limit; | 814 result->data_.u_empty_match_check.repetition_limit = repetition_limit; |
| 815 return result; | 815 return result; |
| 816 } | 816 } |
| 817 | 817 |
| 818 | 818 |
| 819 #define DEFINE_ACCEPT(Type) \ | 819 #define DEFINE_ACCEPT(Type) \ |
| 820 void Type##Node::Accept(NodeVisitor* visitor) { \ | 820 void Type##Node::Accept(NodeVisitor* visitor) { \ |
| 821 visitor->Visit##Type(this); \ | 821 visitor->Visit##Type(this); \ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 871 } | 871 } |
| 872 | 872 |
| 873 // The standard requires that non-ASCII characters cannot have ASCII | 873 // The standard requires that non-ASCII characters cannot have ASCII |
| 874 // character codes in their equivalence class. | 874 // character codes in their equivalence class. |
| 875 // TODO(dcarney): issue 3550 this is not actually true for Latin1 anymore, | 875 // TODO(dcarney): issue 3550 this is not actually true for Latin1 anymore, |
| 876 // is it? For example, \u00C5 is equivalent to \u212B. | 876 // is it? For example, \u00C5 is equivalent to \u212B. |
| 877 return 0; | 877 return 0; |
| 878 } | 878 } |
| 879 | 879 |
| 880 | 880 |
| 881 static inline bool EmitSimpleCharacter(Isolate* isolate, | 881 static inline bool EmitSimpleCharacter(Zone* zone, |
| 882 RegExpCompiler* compiler, | 882 RegExpCompiler* compiler, |
| 883 uint16_t c, | 883 uint16_t c, |
| 884 BlockLabel* on_failure, | 884 BlockLabel* on_failure, |
| 885 intptr_t cp_offset, | 885 intptr_t cp_offset, |
| 886 bool check, | 886 bool check, |
| 887 bool preloaded) { | 887 bool preloaded) { |
| 888 RegExpMacroAssembler* assembler = compiler->macro_assembler(); | 888 RegExpMacroAssembler* assembler = compiler->macro_assembler(); |
| 889 bool bound_checked = false; | 889 bool bound_checked = false; |
| 890 if (!preloaded) { | 890 if (!preloaded) { |
| 891 assembler->LoadCurrentCharacter( | 891 assembler->LoadCurrentCharacter( |
| 892 cp_offset, | 892 cp_offset, |
| 893 on_failure, | 893 on_failure, |
| 894 check); | 894 check); |
| 895 bound_checked = true; | 895 bound_checked = true; |
| 896 } | 896 } |
| 897 assembler->CheckNotCharacter(c, on_failure); | 897 assembler->CheckNotCharacter(c, on_failure); |
| 898 return bound_checked; | 898 return bound_checked; |
| 899 } | 899 } |
| 900 | 900 |
| 901 | 901 |
| 902 // Only emits non-letters (things that don't have case). Only used for case | 902 // Only emits non-letters (things that don't have case). Only used for case |
| 903 // independent matches. | 903 // independent matches. |
| 904 static inline bool EmitAtomNonLetter(Isolate* isolate, | 904 static inline bool EmitAtomNonLetter(Zone* zone, |
| 905 RegExpCompiler* compiler, | 905 RegExpCompiler* compiler, |
| 906 uint16_t c, | 906 uint16_t c, |
| 907 BlockLabel* on_failure, | 907 BlockLabel* on_failure, |
| 908 intptr_t cp_offset, | 908 intptr_t cp_offset, |
| 909 bool check, | 909 bool check, |
| 910 bool preloaded) { | 910 bool preloaded) { |
| 911 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 911 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 912 bool one_byte = compiler->one_byte(); | 912 bool one_byte = compiler->one_byte(); |
| 913 int32_t chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 913 int32_t chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 914 intptr_t length = GetCaseIndependentLetters(c, one_byte, chars); | 914 intptr_t length = GetCaseIndependentLetters(c, one_byte, chars); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 967 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff, | 967 macro_assembler->CheckNotCharacterAfterMinusAnd(c1 - diff, |
| 968 diff, | 968 diff, |
| 969 mask, | 969 mask, |
| 970 on_failure); | 970 on_failure); |
| 971 return true; | 971 return true; |
| 972 } | 972 } |
| 973 return false; | 973 return false; |
| 974 } | 974 } |
| 975 | 975 |
| 976 | 976 |
| 977 typedef bool EmitCharacterFunction(Isolate* isolate, | 977 typedef bool EmitCharacterFunction(Zone* zone, |
| 978 RegExpCompiler* compiler, | 978 RegExpCompiler* compiler, |
| 979 uint16_t c, | 979 uint16_t c, |
| 980 BlockLabel* on_failure, | 980 BlockLabel* on_failure, |
| 981 intptr_t cp_offset, | 981 intptr_t cp_offset, |
| 982 bool check, | 982 bool check, |
| 983 bool preloaded); | 983 bool preloaded); |
| 984 | 984 |
| 985 // Only emits letters (things that have case). Only used for case independent | 985 // Only emits letters (things that have case). Only used for case independent |
| 986 // matches. | 986 // matches. |
| 987 static inline bool EmitAtomLetter(Isolate* isolate, | 987 static inline bool EmitAtomLetter(Zone* zone, |
| 988 RegExpCompiler* compiler, | 988 RegExpCompiler* compiler, |
| 989 uint16_t c, | 989 uint16_t c, |
| 990 BlockLabel* on_failure, | 990 BlockLabel* on_failure, |
| 991 intptr_t cp_offset, | 991 intptr_t cp_offset, |
| 992 bool check, | 992 bool check, |
| 993 bool preloaded) { | 993 bool preloaded) { |
| 994 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); | 994 RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); |
| 995 bool one_byte = compiler->one_byte(); | 995 bool one_byte = compiler->one_byte(); |
| 996 int32_t chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; | 996 int32_t chars[unibrow::Ecma262UnCanonicalize::kMaxWidth]; |
| 997 intptr_t length = GetCaseIndependentLetters(c, one_byte, chars); | 997 intptr_t length = GetCaseIndependentLetters(c, one_byte, chars); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 for (j = (ranges->At(i) & kMask); j < (ranges->At(i + 1) & kMask); j++) { | 1116 for (j = (ranges->At(i) & kMask); j < (ranges->At(i + 1) & kMask); j++) { |
| 1117 templ[j] = bit; | 1117 templ[j] = bit; |
| 1118 } | 1118 } |
| 1119 bit ^= 1; | 1119 bit ^= 1; |
| 1120 } | 1120 } |
| 1121 for (intptr_t i = j; i < kSize; i++) { | 1121 for (intptr_t i = j; i < kSize; i++) { |
| 1122 templ[i] = bit; | 1122 templ[i] = bit; |
| 1123 } | 1123 } |
| 1124 // TODO(erikcorry): Cache these. | 1124 // TODO(erikcorry): Cache these. |
| 1125 const TypedData& ba = TypedData::ZoneHandle( | 1125 const TypedData& ba = TypedData::ZoneHandle( |
| 1126 masm->isolate(), | 1126 masm->zone(), |
| 1127 TypedData::New(kTypedDataUint8ArrayCid, kSize, Heap::kOld)); | 1127 TypedData::New(kTypedDataUint8ArrayCid, kSize, Heap::kOld)); |
| 1128 for (intptr_t i = 0; i < kSize; i++) { | 1128 for (intptr_t i = 0; i < kSize; i++) { |
| 1129 ba.SetUint8(i, templ[i]); | 1129 ba.SetUint8(i, templ[i]); |
| 1130 } | 1130 } |
| 1131 masm->CheckBitInTable(ba, on_bit_set); | 1131 masm->CheckBitInTable(ba, on_bit_set); |
| 1132 if (on_bit_clear != fall_through) masm->GoTo(on_bit_clear); | 1132 if (on_bit_clear != fall_through) masm->GoTo(on_bit_clear); |
| 1133 } | 1133 } |
| 1134 | 1134 |
| 1135 | 1135 |
| 1136 static void CutOutRange(RegExpMacroAssembler* masm, | 1136 static void CutOutRange(RegExpMacroAssembler* masm, |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 } | 1388 } |
| 1389 | 1389 |
| 1390 | 1390 |
| 1391 static void EmitCharClass(RegExpMacroAssembler* macro_assembler, | 1391 static void EmitCharClass(RegExpMacroAssembler* macro_assembler, |
| 1392 RegExpCharacterClass* cc, | 1392 RegExpCharacterClass* cc, |
| 1393 bool one_byte, | 1393 bool one_byte, |
| 1394 BlockLabel* on_failure, | 1394 BlockLabel* on_failure, |
| 1395 intptr_t cp_offset, | 1395 intptr_t cp_offset, |
| 1396 bool check_offset, | 1396 bool check_offset, |
| 1397 bool preloaded, | 1397 bool preloaded, |
| 1398 Isolate* isolate) { | 1398 Zone* zone) { |
| 1399 ZoneGrowableArray<CharacterRange>* ranges = cc->ranges(); | 1399 ZoneGrowableArray<CharacterRange>* ranges = cc->ranges(); |
| 1400 if (!CharacterRange::IsCanonical(ranges)) { | 1400 if (!CharacterRange::IsCanonical(ranges)) { |
| 1401 CharacterRange::Canonicalize(ranges); | 1401 CharacterRange::Canonicalize(ranges); |
| 1402 } | 1402 } |
| 1403 | 1403 |
| 1404 intptr_t max_char; | 1404 intptr_t max_char; |
| 1405 if (one_byte) { | 1405 if (one_byte) { |
| 1406 max_char = Symbols::kMaxOneCharCodeSymbol; | 1406 max_char = Symbols::kMaxOneCharCodeSymbol; |
| 1407 } else { | 1407 } else { |
| 1408 max_char = Utf16::kMaxCodeUnit; | 1408 max_char = Utf16::kMaxCodeUnit; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1462 } | 1462 } |
| 1463 | 1463 |
| 1464 | 1464 |
| 1465 // A new list with ascending entries. Each entry is a code unit | 1465 // A new list with ascending entries. Each entry is a code unit |
| 1466 // where there is a boundary between code units that are part of | 1466 // where there is a boundary between code units that are part of |
| 1467 // the class and code units that are not. Normally we insert an | 1467 // the class and code units that are not. Normally we insert an |
| 1468 // entry at zero which goes to the failure label, but if there | 1468 // entry at zero which goes to the failure label, but if there |
| 1469 // was already one there we fall through for success on that entry. | 1469 // was already one there we fall through for success on that entry. |
| 1470 // Subsequent entries have alternating meaning (success/failure). | 1470 // Subsequent entries have alternating meaning (success/failure). |
| 1471 ZoneGrowableArray<int>* range_boundaries = | 1471 ZoneGrowableArray<int>* range_boundaries = |
| 1472 new(isolate) ZoneGrowableArray<int>(last_valid_range); | 1472 new(zone) ZoneGrowableArray<int>(last_valid_range); |
| 1473 | 1473 |
| 1474 bool zeroth_entry_is_failure = !cc->is_negated(); | 1474 bool zeroth_entry_is_failure = !cc->is_negated(); |
| 1475 | 1475 |
| 1476 for (intptr_t i = 0; i <= last_valid_range; i++) { | 1476 for (intptr_t i = 0; i <= last_valid_range; i++) { |
| 1477 CharacterRange& range = (*ranges)[i]; | 1477 CharacterRange& range = (*ranges)[i]; |
| 1478 if (range.from() == 0) { | 1478 if (range.from() == 0) { |
| 1479 ASSERT(i == 0); | 1479 ASSERT(i == 0); |
| 1480 zeroth_entry_is_failure = !zeroth_entry_is_failure; | 1480 zeroth_entry_is_failure = !zeroth_entry_is_failure; |
| 1481 } else { | 1481 } else { |
| 1482 range_boundaries->Add(range.from()); | 1482 range_boundaries->Add(range.from()); |
| (...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2188 } | 2188 } |
| 2189 if (surviving < 2) return set_replacement(survivor); | 2189 if (surviving < 2) return set_replacement(survivor); |
| 2190 | 2190 |
| 2191 set_replacement(this); | 2191 set_replacement(this); |
| 2192 if (surviving == choice_count) { | 2192 if (surviving == choice_count) { |
| 2193 return this; | 2193 return this; |
| 2194 } | 2194 } |
| 2195 // Only some of the nodes survived the filtering. We need to rebuild the | 2195 // Only some of the nodes survived the filtering. We need to rebuild the |
| 2196 // alternatives list. | 2196 // alternatives list. |
| 2197 ZoneGrowableArray<GuardedAlternative>* new_alternatives = | 2197 ZoneGrowableArray<GuardedAlternative>* new_alternatives = |
| 2198 new(I) ZoneGrowableArray<GuardedAlternative>(surviving); | 2198 new(Z) ZoneGrowableArray<GuardedAlternative>(surviving); |
| 2199 for (intptr_t i = 0; i < choice_count; i++) { | 2199 for (intptr_t i = 0; i < choice_count; i++) { |
| 2200 RegExpNode* replacement = | 2200 RegExpNode* replacement = |
| 2201 (*alternatives_)[i].node()->FilterOneByte(depth - 1, ignore_case); | 2201 (*alternatives_)[i].node()->FilterOneByte(depth - 1, ignore_case); |
| 2202 if (replacement != NULL) { | 2202 if (replacement != NULL) { |
| 2203 (*alternatives_)[i].set_node(replacement); | 2203 (*alternatives_)[i].set_node(replacement); |
| 2204 new_alternatives->Add((*alternatives_)[i]); | 2204 new_alternatives->Add((*alternatives_)[i]); |
| 2205 } | 2205 } |
| 2206 } | 2206 } |
| 2207 alternatives_ = new_alternatives; | 2207 alternatives_ = new_alternatives; |
| 2208 return this; | 2208 return this; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2350 bool not_at_start = (trace->at_start() == Trace::FALSE_VALUE); | 2350 bool not_at_start = (trace->at_start() == Trace::FALSE_VALUE); |
| 2351 BoyerMooreLookahead* lookahead = bm_info(not_at_start); | 2351 BoyerMooreLookahead* lookahead = bm_info(not_at_start); |
| 2352 if (lookahead == NULL) { | 2352 if (lookahead == NULL) { |
| 2353 intptr_t eats_at_least = | 2353 intptr_t eats_at_least = |
| 2354 Utils::Minimum(kMaxLookaheadForBoyerMoore, | 2354 Utils::Minimum(kMaxLookaheadForBoyerMoore, |
| 2355 EatsAtLeast(kMaxLookaheadForBoyerMoore, | 2355 EatsAtLeast(kMaxLookaheadForBoyerMoore, |
| 2356 kRecursionBudget, | 2356 kRecursionBudget, |
| 2357 not_at_start)); | 2357 not_at_start)); |
| 2358 if (eats_at_least >= 1) { | 2358 if (eats_at_least >= 1) { |
| 2359 BoyerMooreLookahead* bm = | 2359 BoyerMooreLookahead* bm = |
| 2360 new(I) BoyerMooreLookahead(eats_at_least, compiler, I); | 2360 new(Z) BoyerMooreLookahead(eats_at_least, compiler, Z); |
| 2361 FillInBMInfo(0, kRecursionBudget, bm, not_at_start); | 2361 FillInBMInfo(0, kRecursionBudget, bm, not_at_start); |
| 2362 if (bm->at(0)->is_non_word()) | 2362 if (bm->at(0)->is_non_word()) |
| 2363 next_is_word_character = Trace::FALSE_VALUE; | 2363 next_is_word_character = Trace::FALSE_VALUE; |
| 2364 if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE_VALUE; | 2364 if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE_VALUE; |
| 2365 } | 2365 } |
| 2366 } else { | 2366 } else { |
| 2367 if (lookahead->at(0)->is_non_word()) | 2367 if (lookahead->at(0)->is_non_word()) |
| 2368 next_is_word_character = Trace::FALSE_VALUE; | 2368 next_is_word_character = Trace::FALSE_VALUE; |
| 2369 if (lookahead->at(0)->is_word()) | 2369 if (lookahead->at(0)->is_word()) |
| 2370 next_is_word_character = Trace::TRUE_VALUE; | 2370 next_is_word_character = Trace::TRUE_VALUE; |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2562 case SIMPLE_CHARACTER_MATCH: | 2562 case SIMPLE_CHARACTER_MATCH: |
| 2563 emit_function = &EmitSimpleCharacter; | 2563 emit_function = &EmitSimpleCharacter; |
| 2564 break; | 2564 break; |
| 2565 case CASE_CHARACTER_MATCH: | 2565 case CASE_CHARACTER_MATCH: |
| 2566 emit_function = &EmitAtomLetter; | 2566 emit_function = &EmitAtomLetter; |
| 2567 break; | 2567 break; |
| 2568 default: | 2568 default: |
| 2569 break; | 2569 break; |
| 2570 } | 2570 } |
| 2571 if (emit_function != NULL) { | 2571 if (emit_function != NULL) { |
| 2572 bool bound_checked = emit_function(I, | 2572 bool bound_checked = emit_function(Z, |
| 2573 compiler, | 2573 compiler, |
| 2574 quarks->At(j), | 2574 quarks->At(j), |
| 2575 backtrack, | 2575 backtrack, |
| 2576 cp_offset + j, | 2576 cp_offset + j, |
| 2577 *checked_up_to < cp_offset + j, | 2577 *checked_up_to < cp_offset + j, |
| 2578 preloaded); | 2578 preloaded); |
| 2579 if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to); | 2579 if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to); |
| 2580 } | 2580 } |
| 2581 } | 2581 } |
| 2582 } else { | 2582 } else { |
| 2583 ASSERT(elm.text_type() == TextElement::CHAR_CLASS); | 2583 ASSERT(elm.text_type() == TextElement::CHAR_CLASS); |
| 2584 if (pass == CHARACTER_CLASS_MATCH) { | 2584 if (pass == CHARACTER_CLASS_MATCH) { |
| 2585 if (first_element_checked && i == 0) continue; | 2585 if (first_element_checked && i == 0) continue; |
| 2586 if (DeterminedAlready(quick_check, elm.cp_offset())) continue; | 2586 if (DeterminedAlready(quick_check, elm.cp_offset())) continue; |
| 2587 RegExpCharacterClass* cc = elm.char_class(); | 2587 RegExpCharacterClass* cc = elm.char_class(); |
| 2588 EmitCharClass(assembler, | 2588 EmitCharClass(assembler, |
| 2589 cc, | 2589 cc, |
| 2590 one_byte, | 2590 one_byte, |
| 2591 backtrack, | 2591 backtrack, |
| 2592 cp_offset, | 2592 cp_offset, |
| 2593 *checked_up_to < cp_offset, | 2593 *checked_up_to < cp_offset, |
| 2594 preloaded, | 2594 preloaded, |
| 2595 I); | 2595 Z); |
| 2596 UpdateBoundsCheck(cp_offset, checked_up_to); | 2596 UpdateBoundsCheck(cp_offset, checked_up_to); |
| 2597 } | 2597 } |
| 2598 } | 2598 } |
| 2599 } | 2599 } |
| 2600 } | 2600 } |
| 2601 | 2601 |
| 2602 | 2602 |
| 2603 intptr_t TextNode::Length() { | 2603 intptr_t TextNode::Length() { |
| 2604 TextElement elm = elms_->Last(); | 2604 TextElement elm = elms_->Last(); |
| 2605 ASSERT(elm.cp_offset() >= 0); | 2605 ASSERT(elm.cp_offset() >= 0); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2708 for (intptr_t i = 0; i < element_count; i++) { | 2708 for (intptr_t i = 0; i < element_count; i++) { |
| 2709 TextElement elm = elms_->At(i); | 2709 TextElement elm = elms_->At(i); |
| 2710 if (elm.text_type() == TextElement::CHAR_CLASS) { | 2710 if (elm.text_type() == TextElement::CHAR_CLASS) { |
| 2711 RegExpCharacterClass* cc = elm.char_class(); | 2711 RegExpCharacterClass* cc = elm.char_class(); |
| 2712 // None of the standard character classes is different in the case | 2712 // None of the standard character classes is different in the case |
| 2713 // independent case and it slows us down if we don't know that. | 2713 // independent case and it slows us down if we don't know that. |
| 2714 if (cc->is_standard()) continue; | 2714 if (cc->is_standard()) continue; |
| 2715 ZoneGrowableArray<CharacterRange>* ranges = cc->ranges(); | 2715 ZoneGrowableArray<CharacterRange>* ranges = cc->ranges(); |
| 2716 intptr_t range_count = ranges->length(); | 2716 intptr_t range_count = ranges->length(); |
| 2717 for (intptr_t j = 0; j < range_count; j++) { | 2717 for (intptr_t j = 0; j < range_count; j++) { |
| 2718 (*ranges)[j].AddCaseEquivalents(ranges, is_one_byte, I); | 2718 (*ranges)[j].AddCaseEquivalents(ranges, is_one_byte, Z); |
| 2719 } | 2719 } |
| 2720 } | 2720 } |
| 2721 } | 2721 } |
| 2722 } | 2722 } |
| 2723 | 2723 |
| 2724 | 2724 |
| 2725 intptr_t TextNode::GreedyLoopTextLength() { | 2725 intptr_t TextNode::GreedyLoopTextLength() { |
| 2726 TextElement elm = elms_->At(elms_->length() - 1); | 2726 TextElement elm = elms_->At(elms_->length() - 1); |
| 2727 return elm.cp_offset() + elm.length(); | 2727 return elm.cp_offset() + elm.length(); |
| 2728 } | 2728 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2939 void BoyerMoorePositionInfo::SetAll() { | 2939 void BoyerMoorePositionInfo::SetAll() { |
| 2940 s_ = w_ = d_ = kLatticeUnknown; | 2940 s_ = w_ = d_ = kLatticeUnknown; |
| 2941 if (map_count_ != kMapSize) { | 2941 if (map_count_ != kMapSize) { |
| 2942 map_count_ = kMapSize; | 2942 map_count_ = kMapSize; |
| 2943 for (intptr_t i = 0; i < kMapSize; i++) (*map_)[i] = true; | 2943 for (intptr_t i = 0; i < kMapSize; i++) (*map_)[i] = true; |
| 2944 } | 2944 } |
| 2945 } | 2945 } |
| 2946 | 2946 |
| 2947 | 2947 |
| 2948 BoyerMooreLookahead::BoyerMooreLookahead( | 2948 BoyerMooreLookahead::BoyerMooreLookahead( |
| 2949 intptr_t length, RegExpCompiler* compiler, Isolate* isolate) | 2949 intptr_t length, RegExpCompiler* compiler, Zone* zone) |
| 2950 : length_(length), | 2950 : length_(length), |
| 2951 compiler_(compiler) { | 2951 compiler_(compiler) { |
| 2952 if (compiler->one_byte()) { | 2952 if (compiler->one_byte()) { |
| 2953 max_char_ = Symbols::kMaxOneCharCodeSymbol; | 2953 max_char_ = Symbols::kMaxOneCharCodeSymbol; |
| 2954 } else { | 2954 } else { |
| 2955 max_char_ = Utf16::kMaxCodeUnit; | 2955 max_char_ = Utf16::kMaxCodeUnit; |
| 2956 } | 2956 } |
| 2957 bitmaps_ = new(isolate) ZoneGrowableArray<BoyerMoorePositionInfo*>(length); | 2957 bitmaps_ = new(zone) ZoneGrowableArray<BoyerMoorePositionInfo*>(length); |
| 2958 for (intptr_t i = 0; i < length; i++) { | 2958 for (intptr_t i = 0; i < length; i++) { |
| 2959 bitmaps_->Add(new(isolate) BoyerMoorePositionInfo(isolate)); | 2959 bitmaps_->Add(new(zone) BoyerMoorePositionInfo(zone)); |
| 2960 } | 2960 } |
| 2961 } | 2961 } |
| 2962 | 2962 |
| 2963 | 2963 |
| 2964 // Find the longest range of lookahead that has the fewest number of different | 2964 // Find the longest range of lookahead that has the fewest number of different |
| 2965 // characters that can occur at a given position. Since we are optimizing two | 2965 // characters that can occur at a given position. Since we are optimizing two |
| 2966 // different parameters at once this is a tradeoff. | 2966 // different parameters at once this is a tradeoff. |
| 2967 bool BoyerMooreLookahead::FindWorthwhileInterval(intptr_t* from, intptr_t* to) { | 2967 bool BoyerMooreLookahead::FindWorthwhileInterval(intptr_t* from, intptr_t* to) { |
| 2968 intptr_t biggest_points = 0; | 2968 intptr_t biggest_points = 0; |
| 2969 // If more than 32 characters out of 128 can occur it is unlikely that we can | 2969 // If more than 32 characters out of 128 can occur it is unlikely that we can |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3114 } else { | 3114 } else { |
| 3115 masm->CheckCharacter(single_character, &cont); | 3115 masm->CheckCharacter(single_character, &cont); |
| 3116 } | 3116 } |
| 3117 masm->AdvanceCurrentPosition(lookahead_width); | 3117 masm->AdvanceCurrentPosition(lookahead_width); |
| 3118 masm->GoTo(&again); | 3118 masm->GoTo(&again); |
| 3119 masm->BindBlock(&cont); | 3119 masm->BindBlock(&cont); |
| 3120 return; | 3120 return; |
| 3121 } | 3121 } |
| 3122 | 3122 |
| 3123 const TypedData& boolean_skip_table = TypedData::ZoneHandle( | 3123 const TypedData& boolean_skip_table = TypedData::ZoneHandle( |
| 3124 compiler_->isolate(), | 3124 compiler_->zone(), |
| 3125 TypedData::New(kTypedDataUint8ArrayCid, kSize, Heap::kOld)); | 3125 TypedData::New(kTypedDataUint8ArrayCid, kSize, Heap::kOld)); |
| 3126 intptr_t skip_distance = GetSkipTable( | 3126 intptr_t skip_distance = GetSkipTable( |
| 3127 min_lookahead, max_lookahead, boolean_skip_table); | 3127 min_lookahead, max_lookahead, boolean_skip_table); |
| 3128 ASSERT(skip_distance != 0); | 3128 ASSERT(skip_distance != 0); |
| 3129 | 3129 |
| 3130 BlockLabel cont, again; | 3130 BlockLabel cont, again; |
| 3131 | 3131 |
| 3132 masm->BindBlock(&again); | 3132 masm->BindBlock(&again); |
| 3133 masm->LoadCurrentCharacter(max_lookahead, &cont, true); | 3133 masm->LoadCurrentCharacter(max_lookahead, &cont, true); |
| 3134 masm->CheckBitInTable(boolean_skip_table, &cont); | 3134 masm->CheckBitInTable(boolean_skip_table, &cont); |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3403 // and step forwards 3 if the character is not one of abc. Abc need | 3403 // and step forwards 3 if the character is not one of abc. Abc need |
| 3404 // not be atoms, they can be any reasonably limited character class or | 3404 // not be atoms, they can be any reasonably limited character class or |
| 3405 // small alternation. | 3405 // small alternation. |
| 3406 BoyerMooreLookahead* bm = bm_info(false); | 3406 BoyerMooreLookahead* bm = bm_info(false); |
| 3407 if (bm == NULL) { | 3407 if (bm == NULL) { |
| 3408 eats_at_least = Utils::Minimum(kMaxLookaheadForBoyerMoore, | 3408 eats_at_least = Utils::Minimum(kMaxLookaheadForBoyerMoore, |
| 3409 EatsAtLeast(kMaxLookaheadForBoyerMoore, | 3409 EatsAtLeast(kMaxLookaheadForBoyerMoore, |
| 3410 kRecursionBudget, | 3410 kRecursionBudget, |
| 3411 false)); | 3411 false)); |
| 3412 if (eats_at_least >= 1) { | 3412 if (eats_at_least >= 1) { |
| 3413 bm = new(I) BoyerMooreLookahead(eats_at_least, compiler, I); | 3413 bm = new(Z) BoyerMooreLookahead(eats_at_least, compiler, Z); |
| 3414 GuardedAlternative alt0 = alternatives_->At(0); | 3414 GuardedAlternative alt0 = alternatives_->At(0); |
| 3415 alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, false); | 3415 alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, false); |
| 3416 } | 3416 } |
| 3417 } | 3417 } |
| 3418 if (bm != NULL) { | 3418 if (bm != NULL) { |
| 3419 bm->EmitSkipInstructions(macro_assembler); | 3419 bm->EmitSkipInstructions(macro_assembler); |
| 3420 } | 3420 } |
| 3421 return eats_at_least; | 3421 return eats_at_least; |
| 3422 } | 3422 } |
| 3423 | 3423 |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3941 printer.PrintNode(label, node); | 3941 printer.PrintNode(label, node); |
| 3942 } | 3942 } |
| 3943 | 3943 |
| 3944 | 3944 |
| 3945 #endif // DEBUG | 3945 #endif // DEBUG |
| 3946 | 3946 |
| 3947 | 3947 |
| 3948 // ------------------------------------------------------------------- | 3948 // ------------------------------------------------------------------- |
| 3949 // Tree to graph conversion | 3949 // Tree to graph conversion |
| 3950 | 3950 |
| 3951 // The zone in which we allocate graph nodes. |
| 3952 #define OZ (on_success->zone()) |
| 3953 |
| 3951 RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler, | 3954 RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler, |
| 3952 RegExpNode* on_success) { | 3955 RegExpNode* on_success) { |
| 3953 ZoneGrowableArray<TextElement>* elms = | 3956 ZoneGrowableArray<TextElement>* elms = |
| 3954 new(CI) ZoneGrowableArray<TextElement>(1); | 3957 new(OZ) ZoneGrowableArray<TextElement>(1); |
| 3955 elms->Add(TextElement::Atom(this)); | 3958 elms->Add(TextElement::Atom(this)); |
| 3956 return new(CI) TextNode(elms, on_success); | 3959 return new(OZ) TextNode(elms, on_success); |
| 3957 } | 3960 } |
| 3958 | 3961 |
| 3959 | 3962 |
| 3960 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler, | 3963 RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler, |
| 3961 RegExpNode* on_success) { | 3964 RegExpNode* on_success) { |
| 3962 ZoneGrowableArray<TextElement>* elms = | 3965 ZoneGrowableArray<TextElement>* elms = |
| 3963 new(CI) ZoneGrowableArray<TextElement>(1); | 3966 new(OZ) ZoneGrowableArray<TextElement>(1); |
| 3964 for (intptr_t i = 0; i < elements()->length(); i++) { | 3967 for (intptr_t i = 0; i < elements()->length(); i++) { |
| 3965 elms->Add(elements()->At(i)); | 3968 elms->Add(elements()->At(i)); |
| 3966 } | 3969 } |
| 3967 return new(CI) TextNode(elms, on_success); | 3970 return new(OZ) TextNode(elms, on_success); |
| 3968 } | 3971 } |
| 3969 | 3972 |
| 3970 | 3973 |
| 3971 static bool CompareInverseRanges(ZoneGrowableArray<CharacterRange>* ranges, | 3974 static bool CompareInverseRanges(ZoneGrowableArray<CharacterRange>* ranges, |
| 3972 const intptr_t* special_class, | 3975 const intptr_t* special_class, |
| 3973 intptr_t length) { | 3976 intptr_t length) { |
| 3974 length--; // Remove final 0x10000. | 3977 length--; // Remove final 0x10000. |
| 3975 ASSERT(special_class[length] == 0x10000); | 3978 ASSERT(special_class[length] == 0x10000); |
| 3976 ASSERT(ranges->length() != 0); | 3979 ASSERT(ranges->length() != 0); |
| 3977 ASSERT(length != 0); | 3980 ASSERT(length != 0); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4054 if (CompareInverseRanges(set_.ranges(), kWordRanges, kWordRangeCount)) { | 4057 if (CompareInverseRanges(set_.ranges(), kWordRanges, kWordRangeCount)) { |
| 4055 set_.set_standard_set_type('W'); | 4058 set_.set_standard_set_type('W'); |
| 4056 return true; | 4059 return true; |
| 4057 } | 4060 } |
| 4058 return false; | 4061 return false; |
| 4059 } | 4062 } |
| 4060 | 4063 |
| 4061 | 4064 |
| 4062 RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler, | 4065 RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler, |
| 4063 RegExpNode* on_success) { | 4066 RegExpNode* on_success) { |
| 4064 return new(CI) TextNode(this, on_success); | 4067 return new(OZ) TextNode(this, on_success); |
| 4065 } | 4068 } |
| 4066 | 4069 |
| 4067 | 4070 |
| 4068 RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler, | 4071 RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler, |
| 4069 RegExpNode* on_success) { | 4072 RegExpNode* on_success) { |
| 4070 ZoneGrowableArray<RegExpTree*>* alternatives = this->alternatives(); | 4073 ZoneGrowableArray<RegExpTree*>* alternatives = this->alternatives(); |
| 4071 intptr_t length = alternatives->length(); | 4074 intptr_t length = alternatives->length(); |
| 4072 ChoiceNode* result = | 4075 ChoiceNode* result = |
| 4073 new(CI) ChoiceNode(length, CI); | 4076 new(OZ) ChoiceNode(length, OZ); |
| 4074 for (intptr_t i = 0; i < length; i++) { | 4077 for (intptr_t i = 0; i < length; i++) { |
| 4075 GuardedAlternative alternative(alternatives->At(i)->ToNode(compiler, | 4078 GuardedAlternative alternative(alternatives->At(i)->ToNode(compiler, |
| 4076 on_success)); | 4079 on_success)); |
| 4077 result->AddAlternative(alternative); | 4080 result->AddAlternative(alternative); |
| 4078 } | 4081 } |
| 4079 return result; | 4082 return result; |
| 4080 } | 4083 } |
| 4081 | 4084 |
| 4082 | 4085 |
| 4083 RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler, | 4086 RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4158 // this case. | 4161 // this case. |
| 4159 // Unroll (foo)+ and (foo){3,} | 4162 // Unroll (foo)+ and (foo){3,} |
| 4160 static const intptr_t kMaxUnrolledMinMatches = 3; | 4163 static const intptr_t kMaxUnrolledMinMatches = 3; |
| 4161 // Unroll (foo)? and (foo){x,3} | 4164 // Unroll (foo)? and (foo){x,3} |
| 4162 static const intptr_t kMaxUnrolledMaxMatches = 3; | 4165 static const intptr_t kMaxUnrolledMaxMatches = 3; |
| 4163 if (max == 0) return on_success; // This can happen due to recursion. | 4166 if (max == 0) return on_success; // This can happen due to recursion. |
| 4164 bool body_can_be_empty = (body->min_match() == 0); | 4167 bool body_can_be_empty = (body->min_match() == 0); |
| 4165 intptr_t body_start_reg = RegExpCompiler::kNoRegister; | 4168 intptr_t body_start_reg = RegExpCompiler::kNoRegister; |
| 4166 Interval capture_registers = body->CaptureRegisters(); | 4169 Interval capture_registers = body->CaptureRegisters(); |
| 4167 bool needs_capture_clearing = !capture_registers.is_empty(); | 4170 bool needs_capture_clearing = !capture_registers.is_empty(); |
| 4168 Isolate* isolate = compiler->isolate(); | 4171 Zone* zone = compiler->zone(); |
| 4169 | 4172 |
| 4170 if (body_can_be_empty) { | 4173 if (body_can_be_empty) { |
| 4171 body_start_reg = compiler->AllocateRegister(); | 4174 body_start_reg = compiler->AllocateRegister(); |
| 4172 } else if (kRegexpOptimization && !needs_capture_clearing) { | 4175 } else if (kRegexpOptimization && !needs_capture_clearing) { |
| 4173 // Only unroll if there are no captures and the body can't be | 4176 // Only unroll if there are no captures and the body can't be |
| 4174 // empty. | 4177 // empty. |
| 4175 { | 4178 { |
| 4176 RegExpExpansionLimiter limiter( | 4179 RegExpExpansionLimiter limiter( |
| 4177 compiler, min + ((max != min) ? 1 : 0)); | 4180 compiler, min + ((max != min) ? 1 : 0)); |
| 4178 if (min > 0 && min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) { | 4181 if (min > 0 && min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4190 return answer; | 4193 return answer; |
| 4191 } | 4194 } |
| 4192 } | 4195 } |
| 4193 if (max <= kMaxUnrolledMaxMatches && min == 0) { | 4196 if (max <= kMaxUnrolledMaxMatches && min == 0) { |
| 4194 ASSERT(max > 0); // Due to the 'if' above. | 4197 ASSERT(max > 0); // Due to the 'if' above. |
| 4195 RegExpExpansionLimiter limiter(compiler, max); | 4198 RegExpExpansionLimiter limiter(compiler, max); |
| 4196 if (limiter.ok_to_expand()) { | 4199 if (limiter.ok_to_expand()) { |
| 4197 // Unroll the optional matches up to max. | 4200 // Unroll the optional matches up to max. |
| 4198 RegExpNode* answer = on_success; | 4201 RegExpNode* answer = on_success; |
| 4199 for (intptr_t i = 0; i < max; i++) { | 4202 for (intptr_t i = 0; i < max; i++) { |
| 4200 ChoiceNode* alternation = new(isolate) ChoiceNode(2, isolate); | 4203 ChoiceNode* alternation = new(zone) ChoiceNode(2, zone); |
| 4201 if (is_greedy) { | 4204 if (is_greedy) { |
| 4202 alternation->AddAlternative( | 4205 alternation->AddAlternative( |
| 4203 GuardedAlternative(body->ToNode(compiler, answer))); | 4206 GuardedAlternative(body->ToNode(compiler, answer))); |
| 4204 alternation->AddAlternative(GuardedAlternative(on_success)); | 4207 alternation->AddAlternative(GuardedAlternative(on_success)); |
| 4205 } else { | 4208 } else { |
| 4206 alternation->AddAlternative(GuardedAlternative(on_success)); | 4209 alternation->AddAlternative(GuardedAlternative(on_success)); |
| 4207 alternation->AddAlternative( | 4210 alternation->AddAlternative( |
| 4208 GuardedAlternative(body->ToNode(compiler, answer))); | 4211 GuardedAlternative(body->ToNode(compiler, answer))); |
| 4209 } | 4212 } |
| 4210 answer = alternation; | 4213 answer = alternation; |
| 4211 if (not_at_start) alternation->set_not_at_start(); | 4214 if (not_at_start) alternation->set_not_at_start(); |
| 4212 } | 4215 } |
| 4213 return answer; | 4216 return answer; |
| 4214 } | 4217 } |
| 4215 } | 4218 } |
| 4216 } | 4219 } |
| 4217 bool has_min = min > 0; | 4220 bool has_min = min > 0; |
| 4218 bool has_max = max < RegExpTree::kInfinity; | 4221 bool has_max = max < RegExpTree::kInfinity; |
| 4219 bool needs_counter = has_min || has_max; | 4222 bool needs_counter = has_min || has_max; |
| 4220 intptr_t reg_ctr = needs_counter | 4223 intptr_t reg_ctr = needs_counter |
| 4221 ? compiler->AllocateRegister() | 4224 ? compiler->AllocateRegister() |
| 4222 : RegExpCompiler::kNoRegister; | 4225 : RegExpCompiler::kNoRegister; |
| 4223 LoopChoiceNode* center = new(isolate) LoopChoiceNode(body->min_match() == 0, | 4226 LoopChoiceNode* center = new(zone) LoopChoiceNode(body->min_match() == 0, |
| 4224 isolate); | 4227 zone); |
| 4225 if (not_at_start) center->set_not_at_start(); | 4228 if (not_at_start) center->set_not_at_start(); |
| 4226 RegExpNode* loop_return = needs_counter | 4229 RegExpNode* loop_return = needs_counter |
| 4227 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) | 4230 ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center)) |
| 4228 : static_cast<RegExpNode*>(center); | 4231 : static_cast<RegExpNode*>(center); |
| 4229 if (body_can_be_empty) { | 4232 if (body_can_be_empty) { |
| 4230 // If the body can be empty we need to check if it was and then | 4233 // If the body can be empty we need to check if it was and then |
| 4231 // backtrack. | 4234 // backtrack. |
| 4232 loop_return = ActionNode::EmptyMatchCheck(body_start_reg, | 4235 loop_return = ActionNode::EmptyMatchCheck(body_start_reg, |
| 4233 reg_ctr, | 4236 reg_ctr, |
| 4234 min, | 4237 min, |
| 4235 loop_return); | 4238 loop_return); |
| 4236 } | 4239 } |
| 4237 RegExpNode* body_node = body->ToNode(compiler, loop_return); | 4240 RegExpNode* body_node = body->ToNode(compiler, loop_return); |
| 4238 if (body_can_be_empty) { | 4241 if (body_can_be_empty) { |
| 4239 // If the body can be empty we need to store the start position | 4242 // If the body can be empty we need to store the start position |
| 4240 // so we can bail out if it was empty. | 4243 // so we can bail out if it was empty. |
| 4241 body_node = ActionNode::StorePosition(body_start_reg, false, body_node); | 4244 body_node = ActionNode::StorePosition(body_start_reg, false, body_node); |
| 4242 } | 4245 } |
| 4243 if (needs_capture_clearing) { | 4246 if (needs_capture_clearing) { |
| 4244 // Before entering the body of this loop we need to clear captures. | 4247 // Before entering the body of this loop we need to clear captures. |
| 4245 body_node = ActionNode::ClearCaptures(capture_registers, body_node); | 4248 body_node = ActionNode::ClearCaptures(capture_registers, body_node); |
| 4246 } | 4249 } |
| 4247 GuardedAlternative body_alt(body_node); | 4250 GuardedAlternative body_alt(body_node); |
| 4248 if (has_max) { | 4251 if (has_max) { |
| 4249 Guard* body_guard = | 4252 Guard* body_guard = |
| 4250 new(isolate) Guard(reg_ctr, Guard::LT, max); | 4253 new(zone) Guard(reg_ctr, Guard::LT, max); |
| 4251 body_alt.AddGuard(body_guard, isolate); | 4254 body_alt.AddGuard(body_guard, zone); |
| 4252 } | 4255 } |
| 4253 GuardedAlternative rest_alt(on_success); | 4256 GuardedAlternative rest_alt(on_success); |
| 4254 if (has_min) { | 4257 if (has_min) { |
| 4255 Guard* rest_guard = new(isolate) Guard(reg_ctr, Guard::GEQ, min); | 4258 Guard* rest_guard = new(zone) Guard(reg_ctr, Guard::GEQ, min); |
| 4256 rest_alt.AddGuard(rest_guard, isolate); | 4259 rest_alt.AddGuard(rest_guard, zone); |
| 4257 } | 4260 } |
| 4258 if (is_greedy) { | 4261 if (is_greedy) { |
| 4259 center->AddLoopAlternative(body_alt); | 4262 center->AddLoopAlternative(body_alt); |
| 4260 center->AddContinueAlternative(rest_alt); | 4263 center->AddContinueAlternative(rest_alt); |
| 4261 } else { | 4264 } else { |
| 4262 center->AddContinueAlternative(rest_alt); | 4265 center->AddContinueAlternative(rest_alt); |
| 4263 center->AddLoopAlternative(body_alt); | 4266 center->AddLoopAlternative(body_alt); |
| 4264 } | 4267 } |
| 4265 if (needs_counter) { | 4268 if (needs_counter) { |
| 4266 return ActionNode::SetRegister(reg_ctr, 0, center); | 4269 return ActionNode::SetRegister(reg_ctr, 0, center); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4283 return AssertionNode::AtNonBoundary(on_success); | 4286 return AssertionNode::AtNonBoundary(on_success); |
| 4284 case END_OF_INPUT: | 4287 case END_OF_INPUT: |
| 4285 return AssertionNode::AtEnd(on_success); | 4288 return AssertionNode::AtEnd(on_success); |
| 4286 case END_OF_LINE: { | 4289 case END_OF_LINE: { |
| 4287 // Compile $ in multiline regexps as an alternation with a positive | 4290 // Compile $ in multiline regexps as an alternation with a positive |
| 4288 // lookahead in one side and an end-of-input on the other side. | 4291 // lookahead in one side and an end-of-input on the other side. |
| 4289 // We need two registers for the lookahead. | 4292 // We need two registers for the lookahead. |
| 4290 intptr_t stack_pointer_register = compiler->AllocateRegister(); | 4293 intptr_t stack_pointer_register = compiler->AllocateRegister(); |
| 4291 intptr_t position_register = compiler->AllocateRegister(); | 4294 intptr_t position_register = compiler->AllocateRegister(); |
| 4292 // The ChoiceNode to distinguish between a newline and end-of-input. | 4295 // The ChoiceNode to distinguish between a newline and end-of-input. |
| 4293 ChoiceNode* result = new ChoiceNode(2, on_success->isolate()); | 4296 ChoiceNode* result = new ChoiceNode(2, on_success->zone()); |
| 4294 // Create a newline atom. | 4297 // Create a newline atom. |
| 4295 ZoneGrowableArray<CharacterRange>* newline_ranges = | 4298 ZoneGrowableArray<CharacterRange>* newline_ranges = |
| 4296 new ZoneGrowableArray<CharacterRange>(3); | 4299 new ZoneGrowableArray<CharacterRange>(3); |
| 4297 CharacterRange::AddClassEscape('n', newline_ranges); | 4300 CharacterRange::AddClassEscape('n', newline_ranges); |
| 4298 RegExpCharacterClass* newline_atom = new RegExpCharacterClass('n'); | 4301 RegExpCharacterClass* newline_atom = new RegExpCharacterClass('n'); |
| 4299 TextNode* newline_matcher = new TextNode( | 4302 TextNode* newline_matcher = new TextNode( |
| 4300 newline_atom, | 4303 newline_atom, |
| 4301 ActionNode::PositiveSubmatchSuccess(stack_pointer_register, | 4304 ActionNode::PositiveSubmatchSuccess(stack_pointer_register, |
| 4302 position_register, | 4305 position_register, |
| 4303 0, // No captures inside. | 4306 0, // No captures inside. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4317 } | 4320 } |
| 4318 default: | 4321 default: |
| 4319 UNREACHABLE(); | 4322 UNREACHABLE(); |
| 4320 } | 4323 } |
| 4321 return on_success; | 4324 return on_success; |
| 4322 } | 4325 } |
| 4323 | 4326 |
| 4324 | 4327 |
| 4325 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler, | 4328 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler, |
| 4326 RegExpNode* on_success) { | 4329 RegExpNode* on_success) { |
| 4327 return new(CI) | 4330 return new(OZ) |
| 4328 BackReferenceNode(RegExpCapture::StartRegister(index()), | 4331 BackReferenceNode(RegExpCapture::StartRegister(index()), |
| 4329 RegExpCapture::EndRegister(index()), | 4332 RegExpCapture::EndRegister(index()), |
| 4330 on_success); | 4333 on_success); |
| 4331 } | 4334 } |
| 4332 | 4335 |
| 4333 | 4336 |
| 4334 RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler, | 4337 RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler, |
| 4335 RegExpNode* on_success) { | 4338 RegExpNode* on_success) { |
| 4336 return on_success; | 4339 return on_success; |
| 4337 } | 4340 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4369 // NegativeSubmatchSuccess will unwind the stack including everything the | 4372 // NegativeSubmatchSuccess will unwind the stack including everything the |
| 4370 // choice node set up and backtrack. If the first alternative fails then | 4373 // choice node set up and backtrack. If the first alternative fails then |
| 4371 // the second alternative is tried, which is exactly the desired result | 4374 // the second alternative is tried, which is exactly the desired result |
| 4372 // for a negative lookahead. The NegativeLookaheadChoiceNode is a special | 4375 // for a negative lookahead. The NegativeLookaheadChoiceNode is a special |
| 4373 // ChoiceNode that knows to ignore the first exit when calculating quick | 4376 // ChoiceNode that knows to ignore the first exit when calculating quick |
| 4374 // checks. | 4377 // checks. |
| 4375 | 4378 |
| 4376 GuardedAlternative body_alt( | 4379 GuardedAlternative body_alt( |
| 4377 body()->ToNode( | 4380 body()->ToNode( |
| 4378 compiler, | 4381 compiler, |
| 4379 success = new(CI) NegativeSubmatchSuccess(stack_pointer_register, | 4382 success = new(OZ) NegativeSubmatchSuccess(stack_pointer_register, |
| 4380 position_register, | 4383 position_register, |
| 4381 register_count, | 4384 register_count, |
| 4382 register_start, | 4385 register_start, |
| 4383 CI))); | 4386 OZ))); |
| 4384 ChoiceNode* choice_node = | 4387 ChoiceNode* choice_node = |
| 4385 new(CI) NegativeLookaheadChoiceNode(body_alt, | 4388 new(OZ) NegativeLookaheadChoiceNode(body_alt, |
| 4386 GuardedAlternative(on_success), | 4389 GuardedAlternative(on_success), |
| 4387 CI); | 4390 OZ); |
| 4388 return ActionNode::BeginSubmatch(stack_pointer_register, | 4391 return ActionNode::BeginSubmatch(stack_pointer_register, |
| 4389 position_register, | 4392 position_register, |
| 4390 choice_node); | 4393 choice_node); |
| 4391 } | 4394 } |
| 4392 } | 4395 } |
| 4393 | 4396 |
| 4394 | 4397 |
| 4395 RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler, | 4398 RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler, |
| 4396 RegExpNode* on_success) { | 4399 RegExpNode* on_success) { |
| 4397 return ToNode(body(), index(), compiler, on_success); | 4400 return ToNode(body(), index(), compiler, on_success); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4492 break; | 4495 break; |
| 4493 default: | 4496 default: |
| 4494 UNREACHABLE(); | 4497 UNREACHABLE(); |
| 4495 } | 4498 } |
| 4496 } | 4499 } |
| 4497 | 4500 |
| 4498 | 4501 |
| 4499 void CharacterRange::AddCaseEquivalents( | 4502 void CharacterRange::AddCaseEquivalents( |
| 4500 ZoneGrowableArray<CharacterRange>* ranges, | 4503 ZoneGrowableArray<CharacterRange>* ranges, |
| 4501 bool is_one_byte, | 4504 bool is_one_byte, |
| 4502 Isolate* isolate) { | 4505 Zone* zone) { |
| 4503 uint16_t bottom = from(); | 4506 uint16_t bottom = from(); |
| 4504 uint16_t top = to(); | 4507 uint16_t top = to(); |
| 4505 if (is_one_byte && !RangeContainsLatin1Equivalents(*this)) { | 4508 if (is_one_byte && !RangeContainsLatin1Equivalents(*this)) { |
| 4506 if (bottom > Symbols::kMaxOneCharCodeSymbol) return; | 4509 if (bottom > Symbols::kMaxOneCharCodeSymbol) return; |
| 4507 if (top > Symbols::kMaxOneCharCodeSymbol) { | 4510 if (top > Symbols::kMaxOneCharCodeSymbol) { |
| 4508 top = Symbols::kMaxOneCharCodeSymbol; | 4511 top = Symbols::kMaxOneCharCodeSymbol; |
| 4509 } | 4512 } |
| 4510 } | 4513 } |
| 4511 | 4514 |
| 4512 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize; | 4515 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> jsregexp_uncanonicalize; |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4746 unsigned value) { | 4749 unsigned value) { |
| 4747 for (intptr_t i = 0; i < array->length(); i++) { | 4750 for (intptr_t i = 0; i < array->length(); i++) { |
| 4748 if (array->At(i) == value) { | 4751 if (array->At(i) == value) { |
| 4749 return true; | 4752 return true; |
| 4750 } | 4753 } |
| 4751 } | 4754 } |
| 4752 return false; | 4755 return false; |
| 4753 } | 4756 } |
| 4754 | 4757 |
| 4755 | 4758 |
| 4756 void OutSet::Set(unsigned value, Isolate* isolate) { | 4759 void OutSet::Set(unsigned value, Zone* zone) { |
| 4757 if (value < kFirstLimit) { | 4760 if (value < kFirstLimit) { |
| 4758 first_ |= (1 << value); | 4761 first_ |= (1 << value); |
| 4759 } else { | 4762 } else { |
| 4760 if (remaining_ == NULL) | 4763 if (remaining_ == NULL) |
| 4761 remaining_ = new(isolate) ZoneGrowableArray<unsigned>(1); | 4764 remaining_ = new(zone) ZoneGrowableArray<unsigned>(1); |
| 4762 | 4765 |
| 4763 bool remaining_contains_value = ArrayContains(remaining_, value); | 4766 bool remaining_contains_value = ArrayContains(remaining_, value); |
| 4764 if (remaining_->is_empty() || !remaining_contains_value) { | 4767 if (remaining_->is_empty() || !remaining_contains_value) { |
| 4765 remaining_->Add(value); | 4768 remaining_->Add(value); |
| 4766 } | 4769 } |
| 4767 } | 4770 } |
| 4768 } | 4771 } |
| 4769 | 4772 |
| 4770 | 4773 |
| 4771 bool OutSet::Get(unsigned value) const { | 4774 bool OutSet::Get(unsigned value) const { |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4970 bm, | 4973 bm, |
| 4971 true); // Not at start after a text node. | 4974 true); // Not at start after a text node. |
| 4972 if (initial_offset == 0) set_bm_info(not_at_start, bm); | 4975 if (initial_offset == 0) set_bm_info(not_at_start, bm); |
| 4973 } | 4976 } |
| 4974 | 4977 |
| 4975 | 4978 |
| 4976 RegExpEngine::CompilationResult RegExpEngine::Compile( | 4979 RegExpEngine::CompilationResult RegExpEngine::Compile( |
| 4977 RegExpCompileData* data, | 4980 RegExpCompileData* data, |
| 4978 const ParsedFunction* parsed_function, | 4981 const ParsedFunction* parsed_function, |
| 4979 const ZoneGrowableArray<const ICData*>& ic_data_array) { | 4982 const ZoneGrowableArray<const ICData*>& ic_data_array) { |
| 4980 Isolate* isolate = Isolate::Current(); | 4983 Zone* zone = Thread::Current()->zone(); |
| 4981 | 4984 |
| 4982 const Function& function = parsed_function->function(); | 4985 const Function& function = parsed_function->function(); |
| 4983 const intptr_t specialization_cid = function.regexp_cid(); | 4986 const intptr_t specialization_cid = function.regexp_cid(); |
| 4984 const bool is_one_byte = (specialization_cid == kOneByteStringCid || | 4987 const bool is_one_byte = (specialization_cid == kOneByteStringCid || |
| 4985 specialization_cid == kExternalOneByteStringCid); | 4988 specialization_cid == kExternalOneByteStringCid); |
| 4986 JSRegExp& regexp = JSRegExp::Handle(isolate, function.regexp()); | 4989 JSRegExp& regexp = JSRegExp::Handle(zone, function.regexp()); |
| 4987 const String& pattern = String::Handle(isolate, regexp.pattern()); | 4990 const String& pattern = String::Handle(zone, regexp.pattern()); |
| 4988 | 4991 |
| 4989 ASSERT(!regexp.IsNull()); | 4992 ASSERT(!regexp.IsNull()); |
| 4990 ASSERT(!pattern.IsNull()); | 4993 ASSERT(!pattern.IsNull()); |
| 4991 | 4994 |
| 4992 const bool ignore_case = regexp.is_ignore_case(); | 4995 const bool ignore_case = regexp.is_ignore_case(); |
| 4993 const bool is_global = regexp.is_global(); | 4996 const bool is_global = regexp.is_global(); |
| 4994 | 4997 |
| 4995 RegExpCompiler compiler(data->capture_count, ignore_case, specialization_cid); | 4998 RegExpCompiler compiler(data->capture_count, ignore_case, specialization_cid); |
| 4996 | 4999 |
| 4997 // TODO(zerny): Frequency sampling is currently disabled because of several | 5000 // TODO(zerny): Frequency sampling is currently disabled because of several |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5013 bool is_end_anchored = data->tree->IsAnchoredAtEnd(); | 5016 bool is_end_anchored = data->tree->IsAnchoredAtEnd(); |
| 5014 bool is_start_anchored = data->tree->IsAnchoredAtStart(); | 5017 bool is_start_anchored = data->tree->IsAnchoredAtStart(); |
| 5015 intptr_t max_length = data->tree->max_match(); | 5018 intptr_t max_length = data->tree->max_match(); |
| 5016 if (!is_start_anchored) { | 5019 if (!is_start_anchored) { |
| 5017 // Add a .*? at the beginning, outside the body capture, unless | 5020 // Add a .*? at the beginning, outside the body capture, unless |
| 5018 // this expression is anchored at the beginning. | 5021 // this expression is anchored at the beginning. |
| 5019 RegExpNode* loop_node = | 5022 RegExpNode* loop_node = |
| 5020 RegExpQuantifier::ToNode(0, | 5023 RegExpQuantifier::ToNode(0, |
| 5021 RegExpTree::kInfinity, | 5024 RegExpTree::kInfinity, |
| 5022 false, | 5025 false, |
| 5023 new(isolate) RegExpCharacterClass('*'), | 5026 new(zone) RegExpCharacterClass('*'), |
| 5024 &compiler, | 5027 &compiler, |
| 5025 captured_body, | 5028 captured_body, |
| 5026 data->contains_anchor); | 5029 data->contains_anchor); |
| 5027 | 5030 |
| 5028 if (data->contains_anchor) { | 5031 if (data->contains_anchor) { |
| 5029 // Unroll loop once, to take care of the case that might start | 5032 // Unroll loop once, to take care of the case that might start |
| 5030 // at the start of input. | 5033 // at the start of input. |
| 5031 ChoiceNode* first_step_node = new(isolate) ChoiceNode(2, isolate); | 5034 ChoiceNode* first_step_node = new(zone) ChoiceNode(2, zone); |
| 5032 first_step_node->AddAlternative(GuardedAlternative(captured_body)); | 5035 first_step_node->AddAlternative(GuardedAlternative(captured_body)); |
| 5033 first_step_node->AddAlternative(GuardedAlternative( | 5036 first_step_node->AddAlternative(GuardedAlternative( |
| 5034 new(isolate) TextNode( | 5037 new(zone) TextNode( |
| 5035 new(isolate) RegExpCharacterClass('*'), loop_node))); | 5038 new(zone) RegExpCharacterClass('*'), loop_node))); |
| 5036 node = first_step_node; | 5039 node = first_step_node; |
| 5037 } else { | 5040 } else { |
| 5038 node = loop_node; | 5041 node = loop_node; |
| 5039 } | 5042 } |
| 5040 } | 5043 } |
| 5041 if (is_one_byte) { | 5044 if (is_one_byte) { |
| 5042 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | 5045 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); |
| 5043 // Do it again to propagate the new nodes to places where they were not | 5046 // Do it again to propagate the new nodes to places where they were not |
| 5044 // put because they had not been calculated yet. | 5047 // put because they had not been calculated yet. |
| 5045 if (node != NULL) { | 5048 if (node != NULL) { |
| 5046 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | 5049 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); |
| 5047 } | 5050 } |
| 5048 } | 5051 } |
| 5049 | 5052 |
| 5050 if (node == NULL) node = new(isolate) EndNode(EndNode::BACKTRACK, isolate); | 5053 if (node == NULL) node = new(zone) EndNode(EndNode::BACKTRACK, zone); |
| 5051 data->node = node; | 5054 data->node = node; |
| 5052 Analysis analysis(ignore_case, is_one_byte); | 5055 Analysis analysis(ignore_case, is_one_byte); |
| 5053 analysis.EnsureAnalyzed(node); | 5056 analysis.EnsureAnalyzed(node); |
| 5054 if (analysis.has_failed()) { | 5057 if (analysis.has_failed()) { |
| 5055 const char* error_message = analysis.error_message(); | 5058 const char* error_message = analysis.error_message(); |
| 5056 return CompilationResult(error_message); | 5059 return CompilationResult(error_message); |
| 5057 } | 5060 } |
| 5058 | 5061 |
| 5059 // Native regexp implementation. | 5062 // Native regexp implementation. |
| 5060 | 5063 |
| 5061 IRRegExpMacroAssembler* macro_assembler = | 5064 IRRegExpMacroAssembler* macro_assembler = |
| 5062 new(isolate) IRRegExpMacroAssembler(specialization_cid, | 5065 new(zone) IRRegExpMacroAssembler(specialization_cid, |
| 5063 data->capture_count, | 5066 data->capture_count, |
| 5064 parsed_function, | 5067 parsed_function, |
| 5065 ic_data_array, | 5068 ic_data_array, |
| 5066 isolate); | 5069 zone); |
| 5067 | 5070 |
| 5068 // Inserted here, instead of in Assembler, because it depends on information | 5071 // Inserted here, instead of in Assembler, because it depends on information |
| 5069 // in the AST that isn't replicated in the Node structure. | 5072 // in the AST that isn't replicated in the Node structure. |
| 5070 static const intptr_t kMaxBacksearchLimit = 1024; | 5073 static const intptr_t kMaxBacksearchLimit = 1024; |
| 5071 if (is_end_anchored && | 5074 if (is_end_anchored && |
| 5072 !is_start_anchored && | 5075 !is_start_anchored && |
| 5073 max_length < kMaxBacksearchLimit) { | 5076 max_length < kMaxBacksearchLimit) { |
| 5074 macro_assembler->SetCurrentPositionFromEnd(max_length); | 5077 macro_assembler->SetCurrentPositionFromEnd(max_length); |
| 5075 } | 5078 } |
| 5076 | 5079 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 5088 pattern); | 5091 pattern); |
| 5089 | 5092 |
| 5090 if (FLAG_trace_irregexp) { | 5093 if (FLAG_trace_irregexp) { |
| 5091 macro_assembler->PrintBlocks(); | 5094 macro_assembler->PrintBlocks(); |
| 5092 } | 5095 } |
| 5093 | 5096 |
| 5094 return result; | 5097 return result; |
| 5095 } | 5098 } |
| 5096 | 5099 |
| 5097 | 5100 |
| 5098 static void CreateSpecializedFunction(Isolate* isolate, | 5101 static void CreateSpecializedFunction(Zone* zone, |
| 5099 const JSRegExp& regexp, | 5102 const JSRegExp& regexp, |
| 5100 intptr_t specialization_cid, | 5103 intptr_t specialization_cid, |
| 5101 const Object& owner) { | 5104 const Object& owner) { |
| 5102 const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; | 5105 const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; |
| 5103 | 5106 |
| 5104 Function& fn = Function::Handle(isolate, Function::New( | 5107 Function& fn = Function::Handle(zone, Function::New( |
| 5105 // Append the regexp pattern to the function name. | 5108 // Append the regexp pattern to the function name. |
| 5106 String::Handle(isolate, Symbols::New( | 5109 String::Handle(zone, Symbols::New( |
| 5107 String::Handle(isolate, String::Concat( | 5110 String::Handle(zone, String::Concat( |
| 5108 String::Handle(isolate, String::Concat( | 5111 String::Handle(zone, String::Concat( |
| 5109 Symbols::Irregexp(), | 5112 Symbols::Irregexp(), |
| 5110 Symbols::ColonSpace(), Heap::kOld)), | 5113 Symbols::ColonSpace(), Heap::kOld)), |
| 5111 String::Handle(regexp.pattern()), Heap::kOld)))), | 5114 String::Handle(regexp.pattern()), Heap::kOld)))), |
| 5112 RawFunction::kIrregexpFunction, | 5115 RawFunction::kIrregexpFunction, |
| 5113 true, // Static. | 5116 true, // Static. |
| 5114 false, // Not const. | 5117 false, // Not const. |
| 5115 false, // Not abstract. | 5118 false, // Not abstract. |
| 5116 false, // Not external. | 5119 false, // Not external. |
| 5117 false, // Not native. | 5120 false, // Not native. |
| 5118 owner, | 5121 owner, |
| 5119 0)); // No token position. | 5122 0)); // No token position. |
| 5120 | 5123 |
| 5121 // TODO(zerny): Share these arrays between all irregexp functions. | 5124 // TODO(zerny): Share these arrays between all irregexp functions. |
| 5122 fn.set_num_fixed_parameters(kParamCount); | 5125 fn.set_num_fixed_parameters(kParamCount); |
| 5123 fn.set_parameter_types(Array::Handle(isolate, Array::New(kParamCount, | 5126 fn.set_parameter_types(Array::Handle(zone, Array::New(kParamCount, |
| 5124 Heap::kOld))); | 5127 Heap::kOld))); |
| 5125 fn.set_parameter_names(Array::Handle(isolate, Array::New(kParamCount, | 5128 fn.set_parameter_names(Array::Handle(zone, Array::New(kParamCount, |
| 5126 Heap::kOld))); | 5129 Heap::kOld))); |
| 5127 fn.SetParameterTypeAt(0, Type::Handle(isolate, Type::DynamicType())); | 5130 fn.SetParameterTypeAt(0, Type::Handle(zone, Type::DynamicType())); |
| 5128 fn.SetParameterNameAt(0, Symbols::string_param()); | 5131 fn.SetParameterNameAt(0, Symbols::string_param()); |
| 5129 fn.SetParameterTypeAt(1, Type::Handle(isolate, Type::DynamicType())); | 5132 fn.SetParameterTypeAt(1, Type::Handle(zone, Type::DynamicType())); |
| 5130 fn.SetParameterNameAt(1, Symbols::start_index_param()); | 5133 fn.SetParameterNameAt(1, Symbols::start_index_param()); |
| 5131 fn.set_result_type(Type::Handle(isolate, Type::ArrayType())); | 5134 fn.set_result_type(Type::Handle(zone, Type::ArrayType())); |
| 5132 | 5135 |
| 5133 // Cache the result. | 5136 // Cache the result. |
| 5134 regexp.set_function(specialization_cid, fn); | 5137 regexp.set_function(specialization_cid, fn); |
| 5135 | 5138 |
| 5136 fn.set_regexp(regexp); | 5139 fn.set_regexp(regexp); |
| 5137 fn.set_regexp_cid(specialization_cid); | 5140 fn.set_regexp_cid(specialization_cid); |
| 5138 fn.set_is_debuggable(false); | 5141 fn.set_is_debuggable(false); |
| 5139 | 5142 |
| 5140 // The function is compiled lazily during the first call. | 5143 // The function is compiled lazily during the first call. |
| 5141 } | 5144 } |
| 5142 | 5145 |
| 5143 | 5146 |
| 5144 RawJSRegExp* RegExpEngine::CreateJSRegExp(Isolate* isolate, | 5147 RawJSRegExp* RegExpEngine::CreateJSRegExp(Zone* zone, |
| 5145 const String& pattern, | 5148 const String& pattern, |
| 5146 bool multi_line, | 5149 bool multi_line, |
| 5147 bool ignore_case) { | 5150 bool ignore_case) { |
| 5148 const JSRegExp& regexp = JSRegExp::Handle(JSRegExp::New(0)); | 5151 const JSRegExp& regexp = JSRegExp::Handle(JSRegExp::New(0)); |
| 5149 | 5152 |
| 5150 regexp.set_pattern(pattern); | 5153 regexp.set_pattern(pattern); |
| 5151 | 5154 |
| 5152 if (multi_line) { | 5155 if (multi_line) { |
| 5153 regexp.set_is_multi_line(); | 5156 regexp.set_is_multi_line(); |
| 5154 } | 5157 } |
| 5155 if (ignore_case) { | 5158 if (ignore_case) { |
| 5156 regexp.set_is_ignore_case(); | 5159 regexp.set_is_ignore_case(); |
| 5157 } | 5160 } |
| 5158 | 5161 |
| 5159 // TODO(zerny): We might want to use normal string searching algorithms | 5162 // TODO(zerny): We might want to use normal string searching algorithms |
| 5160 // for simple patterns. | 5163 // for simple patterns. |
| 5161 regexp.set_is_complex(); | 5164 regexp.set_is_complex(); |
| 5162 regexp.set_is_global(); // All dart regexps are global. | 5165 regexp.set_is_global(); // All dart regexps are global. |
| 5163 | 5166 |
| 5164 const Library& lib = Library::Handle(isolate, Library::CoreLibrary()); | 5167 const Library& lib = Library::Handle(zone, Library::CoreLibrary()); |
| 5165 const Class& owner = Class::Handle( | 5168 const Class& owner = Class::Handle( |
| 5166 isolate, lib.LookupClass(Symbols::RegExp())); | 5169 zone, lib.LookupClass(Symbols::RegExp())); |
| 5167 | 5170 |
| 5168 CreateSpecializedFunction(isolate, regexp, kOneByteStringCid, owner); | 5171 CreateSpecializedFunction(zone, regexp, kOneByteStringCid, owner); |
| 5169 CreateSpecializedFunction(isolate, regexp, kTwoByteStringCid, owner); | 5172 CreateSpecializedFunction(zone, regexp, kTwoByteStringCid, owner); |
| 5170 CreateSpecializedFunction(isolate, regexp, kExternalOneByteStringCid, owner); | 5173 CreateSpecializedFunction(zone, regexp, kExternalOneByteStringCid, owner); |
| 5171 CreateSpecializedFunction(isolate, regexp, kExternalTwoByteStringCid, owner); | 5174 CreateSpecializedFunction(zone, regexp, kExternalTwoByteStringCid, owner); |
| 5172 | 5175 |
| 5173 return regexp.raw(); | 5176 return regexp.raw(); |
| 5174 } | 5177 } |
| 5175 | 5178 |
| 5176 | 5179 |
| 5177 } // namespace dart | 5180 } // namespace dart |
| OLD | NEW |