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 |