| 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_assembler_ir.h" | 5 #include "vm/regexp_assembler_ir.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 * indices of -1 denote non-matched groups. Note that we store these indices | 71 * indices of -1 denote non-matched groups. Note that we store these indices |
| 72 * as a negative offset from the end of the string in registers_array_ | 72 * as a negative offset from the end of the string in registers_array_ |
| 73 * during processing, and convert them to standard indexes when copying them | 73 * during processing, and convert them to standard indexes when copying them |
| 74 * to matches_param_ on successful match. | 74 * to matches_param_ on successful match. |
| 75 */ | 75 */ |
| 76 IRRegExpMacroAssembler::IRRegExpMacroAssembler( | 76 IRRegExpMacroAssembler::IRRegExpMacroAssembler( |
| 77 intptr_t specialization_cid, | 77 intptr_t specialization_cid, |
| 78 intptr_t capture_count, | 78 intptr_t capture_count, |
| 79 const ParsedFunction* parsed_function, | 79 const ParsedFunction* parsed_function, |
| 80 const ZoneGrowableArray<const ICData*>& ic_data_array, | 80 const ZoneGrowableArray<const ICData*>& ic_data_array, |
| 81 intptr_t osr_id, |
| 81 Zone* zone) | 82 Zone* zone) |
| 82 : RegExpMacroAssembler(zone), | 83 : RegExpMacroAssembler(zone), |
| 83 thread_(Thread::Current()), | 84 thread_(Thread::Current()), |
| 84 specialization_cid_(specialization_cid), | 85 specialization_cid_(specialization_cid), |
| 85 parsed_function_(parsed_function), | 86 parsed_function_(parsed_function), |
| 86 ic_data_array_(ic_data_array), | 87 ic_data_array_(ic_data_array), |
| 87 current_instruction_(NULL), | 88 current_instruction_(NULL), |
| 88 stack_(NULL), | 89 stack_(NULL), |
| 89 stack_pointer_(NULL), | 90 stack_pointer_(NULL), |
| 90 current_character_(NULL), | 91 current_character_(NULL), |
| 91 current_position_(NULL), | 92 current_position_(NULL), |
| 92 string_param_(NULL), | 93 string_param_(NULL), |
| 93 string_param_length_(NULL), | 94 string_param_length_(NULL), |
| 94 start_index_param_(NULL), | 95 start_index_param_(NULL), |
| 95 registers_count_(0), | 96 registers_count_(0), |
| 96 saved_registers_count_((capture_count + 1) * 2), | 97 saved_registers_count_((capture_count + 1) * 2), |
| 97 stack_array_cell_(Array::ZoneHandle(zone, Array::New(1, Heap::kOld))), | 98 stack_array_cell_(Array::ZoneHandle(zone, Array::New(1, Heap::kOld))), |
| 98 // The registers array is allocated at a fixed size after assembly. | 99 // The registers array is allocated at a fixed size after assembly. |
| 99 registers_array_(TypedData::ZoneHandle(zone, TypedData::null())) { | 100 registers_array_(TypedData::ZoneHandle(zone, TypedData::null())), |
| 101 // B0 is taken by GraphEntry thus block ids must start at 1. |
| 102 block_id_(1) { |
| 100 switch (specialization_cid) { | 103 switch (specialization_cid) { |
| 101 case kOneByteStringCid: | 104 case kOneByteStringCid: |
| 102 case kExternalOneByteStringCid: | 105 case kExternalOneByteStringCid: |
| 103 mode_ = ASCII; | 106 mode_ = ASCII; |
| 104 break; | 107 break; |
| 105 case kTwoByteStringCid: | 108 case kTwoByteStringCid: |
| 106 case kExternalTwoByteStringCid: | 109 case kExternalTwoByteStringCid: |
| 107 mode_ = UC16; | 110 mode_ = UC16; |
| 108 break; | 111 break; |
| 109 default: | 112 default: |
| 110 UNREACHABLE(); | 113 UNREACHABLE(); |
| 111 } | 114 } |
| 112 | 115 |
| 113 InitializeLocals(); | 116 InitializeLocals(); |
| 114 | 117 |
| 115 // Allocate an initial stack backing of the minimum stack size. The stack | 118 // Allocate an initial stack backing of the minimum stack size. The stack |
| 116 // backing is indirectly referred to so we can reuse it on subsequent matches | 119 // backing is indirectly referred to so we can reuse it on subsequent matches |
| 117 // even in the case where the backing has been enlarged and thus reallocated. | 120 // even in the case where the backing has been enlarged and thus reallocated. |
| 118 stack_array_cell_.SetAt( | 121 stack_array_cell_.SetAt( |
| 119 0, | 122 0, |
| 120 TypedData::Handle(zone, TypedData::New(kTypedDataInt32ArrayCid, | 123 TypedData::Handle(zone, TypedData::New(kTypedDataInt32ArrayCid, |
| 121 kMinStackSize / 4, Heap::kOld))); | 124 kMinStackSize / 4, Heap::kOld))); |
| 122 | 125 |
| 123 // Create and generate all preset blocks. | 126 // Create and generate all preset blocks. |
| 124 entry_block_ = new (zone) GraphEntryInstr( | 127 entry_block_ = new (zone) GraphEntryInstr( |
| 125 *parsed_function_, | 128 *parsed_function_, |
| 126 new (zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, | 129 new (zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, |
| 127 GetNextDeoptId()), | 130 GetNextDeoptId()), |
| 128 Compiler::kNoOSRDeoptId); | 131 osr_id); |
| 129 start_block_ = new (zone) | 132 start_block_ = new (zone) |
| 130 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); | 133 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); |
| 131 success_block_ = new (zone) | 134 success_block_ = new (zone) |
| 132 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); | 135 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); |
| 133 backtrack_block_ = new (zone) | 136 backtrack_block_ = new (zone) |
| 134 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); | 137 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); |
| 135 exit_block_ = new (zone) | 138 exit_block_ = new (zone) |
| 136 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); | 139 JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); |
| 137 | 140 |
| 138 GenerateEntryBlock(); | 141 GenerateEntryBlock(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 StoreLocal(stack_pointer_, Bind(Int64Constant(-1))); | 219 StoreLocal(stack_pointer_, Bind(Int64Constant(-1))); |
| 217 | 220 |
| 218 // Jump to the start block. | 221 // Jump to the start block. |
| 219 current_instruction_->Goto(start_block_); | 222 current_instruction_->Goto(start_block_); |
| 220 } | 223 } |
| 221 | 224 |
| 222 | 225 |
| 223 void IRRegExpMacroAssembler::GenerateBacktrackBlock() { | 226 void IRRegExpMacroAssembler::GenerateBacktrackBlock() { |
| 224 set_current_instruction(backtrack_block_); | 227 set_current_instruction(backtrack_block_); |
| 225 TAG(); | 228 TAG(); |
| 226 CheckPreemption(); | 229 CheckPreemption(/*is_backtrack=*/true); |
| 227 | 230 |
| 228 const intptr_t entries_count = entry_block_->indirect_entries().length(); | 231 const intptr_t entries_count = entry_block_->indirect_entries().length(); |
| 229 | 232 |
| 230 TypedData& offsets = TypedData::ZoneHandle( | 233 TypedData& offsets = TypedData::ZoneHandle( |
| 231 Z, TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld)); | 234 Z, TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld)); |
| 232 | 235 |
| 233 PushArgumentInstr* block_offsets_push = | 236 PushArgumentInstr* block_offsets_push = |
| 234 PushArgument(Bind(new (Z) ConstantInstr(offsets))); | 237 PushArgument(Bind(new (Z) ConstantInstr(offsets))); |
| 235 PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack())); | 238 PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack())); |
| 236 | 239 |
| (...skipping 1350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1587 | 1590 |
| 1588 BindBlock(&grow_stack); | 1591 BindBlock(&grow_stack); |
| 1589 GrowStack(); | 1592 GrowStack(); |
| 1590 | 1593 |
| 1591 BindBlock(&fallthrough); | 1594 BindBlock(&fallthrough); |
| 1592 } | 1595 } |
| 1593 | 1596 |
| 1594 | 1597 |
| 1595 void IRRegExpMacroAssembler::GrowStack() { | 1598 void IRRegExpMacroAssembler::GrowStack() { |
| 1596 TAG(); | 1599 TAG(); |
| 1597 Value* cell = Bind(new (Z) ConstantInstr(stack_array_cell_)); | 1600 const Library& lib = Library::Handle(Library::InternalLibrary()); |
| 1598 StoreLocal(stack_, Bind(new (Z) GrowRegExpStackInstr(cell))); | 1601 const Function& grow_function = Function::ZoneHandle( |
| 1602 Z, lib.LookupFunctionAllowPrivate(Symbols::GrowRegExpStack())); |
| 1603 StoreLocal(stack_, Bind(StaticCall(grow_function, PushLocal(stack_)))); |
| 1604 |
| 1605 // Note: :stack and stack_array_cell content might diverge because each |
| 1606 // instance of :matcher code has its own stack_array_cell embedded into it |
| 1607 // as a constant but :stack is a local variable and its value might be |
| 1608 // comming from OSR or deoptimization. This means we should never use |
| 1609 // stack_array_cell in the body of the :matcher to reload the :stack. |
| 1610 PushArgumentInstr* stack_cell_push = |
| 1611 PushArgument(Bind(new (Z) ConstantInstr(stack_array_cell_))); |
| 1612 PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(0))); |
| 1613 PushArgumentInstr* stack_push = PushLocal(stack_); |
| 1614 Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), |
| 1615 stack_cell_push, index_push, stack_push)); |
| 1599 } | 1616 } |
| 1600 | 1617 |
| 1601 | 1618 |
| 1602 void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) { | 1619 void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) { |
| 1603 TAG(); | 1620 TAG(); |
| 1604 StoreLocal(current_position_, LoadRegister(reg)); | 1621 StoreLocal(current_position_, LoadRegister(reg)); |
| 1605 } | 1622 } |
| 1606 | 1623 |
| 1607 // Resets the tip of the stack to the value stored in reg. | 1624 // Resets the tip of the stack to the value stored in reg. |
| 1608 void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) { | 1625 void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1760 new (Z) IndirectEntryInstr(block_id_.Alloc(), indirect_id_.Alloc(), | 1777 new (Z) IndirectEntryInstr(block_id_.Alloc(), indirect_id_.Alloc(), |
| 1761 kInvalidTryIndex, GetNextDeoptId()); | 1778 kInvalidTryIndex, GetNextDeoptId()); |
| 1762 blocks_.Add(target); | 1779 blocks_.Add(target); |
| 1763 | 1780 |
| 1764 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); | 1781 target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); |
| 1765 | 1782 |
| 1766 return target; | 1783 return target; |
| 1767 } | 1784 } |
| 1768 | 1785 |
| 1769 | 1786 |
| 1770 void IRRegExpMacroAssembler::CheckPreemption() { | 1787 void IRRegExpMacroAssembler::CheckPreemption(bool is_backtrack) { |
| 1771 TAG(); | 1788 TAG(); |
| 1772 AppendInstruction(new (Z) CheckStackOverflowInstr(TokenPosition::kNoSource, 0, | 1789 |
| 1773 GetNextDeoptId())); | 1790 // We don't have the loop_depth available when compiling regexps, but |
| 1791 // we set loop_depth to a non-zero value because this instruction does |
| 1792 // not act as an OSR entry outside loops. |
| 1793 AppendInstruction(new (Z) CheckStackOverflowInstr( |
| 1794 TokenPosition::kNoSource, |
| 1795 /*loop_depth=*/1, GetNextDeoptId(), |
| 1796 is_backtrack ? CheckStackOverflowInstr::kOsrAndPreemption |
| 1797 : CheckStackOverflowInstr::kOsrOnly)); |
| 1774 } | 1798 } |
| 1775 | 1799 |
| 1776 | 1800 |
| 1777 Definition* IRRegExpMacroAssembler::Add(PushArgumentInstr* lhs, | 1801 Definition* IRRegExpMacroAssembler::Add(PushArgumentInstr* lhs, |
| 1778 PushArgumentInstr* rhs) { | 1802 PushArgumentInstr* rhs) { |
| 1779 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); | 1803 return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); |
| 1780 } | 1804 } |
| 1781 | 1805 |
| 1782 | 1806 |
| 1783 Definition* IRRegExpMacroAssembler::Sub(PushArgumentInstr* lhs, | 1807 Definition* IRRegExpMacroAssembler::Sub(PushArgumentInstr* lhs, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1852 | 1876 |
| 1853 return Bind(new (Z) LoadCodeUnitsInstr(pattern_val, index_val, characters, | 1877 return Bind(new (Z) LoadCodeUnitsInstr(pattern_val, index_val, characters, |
| 1854 specialization_cid_, | 1878 specialization_cid_, |
| 1855 TokenPosition::kNoSource)); | 1879 TokenPosition::kNoSource)); |
| 1856 } | 1880 } |
| 1857 | 1881 |
| 1858 | 1882 |
| 1859 #undef __ | 1883 #undef __ |
| 1860 | 1884 |
| 1861 } // namespace dart | 1885 } // namespace dart |
| OLD | NEW |