OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #ifndef VM_REGEXP_ASSEMBLER_H_ | |
6 #define VM_REGEXP_ASSEMBLER_H_ | |
7 | |
8 #include "vm/assembler.h" | |
9 #include "vm/intermediate_language.h" | |
10 #include "vm/object.h" | |
11 | |
12 namespace dart { | |
13 | |
14 /// Convenience wrapper around a BlockEntryInstr pointer. | |
15 class BlockLabel : public ValueObject { | |
16 public: | |
17 BlockLabel() | |
18 : block_(new JoinEntryInstr(-1, -1)), | |
19 is_bound_(false), | |
20 is_linked_(false) { } | |
21 | |
22 BlockLabel(const BlockLabel& that) | |
23 : ValueObject(), | |
24 block_(that.block_), | |
25 is_bound_(that.is_bound_), | |
26 is_linked_(that.is_linked_) { } | |
27 | |
28 BlockLabel& operator=(const BlockLabel& that) { | |
29 block_ = that.block_; | |
30 is_bound_ = that.is_bound_; | |
31 is_linked_ = that.is_linked_; | |
32 return *this; | |
33 } | |
34 | |
35 JoinEntryInstr* block() const { return block_; } | |
36 | |
37 bool IsBound() const { return is_bound_; } | |
38 void SetBound(intptr_t block_id) { | |
39 ASSERT(!is_bound_); | |
40 block_->set_block_id(block_id); | |
41 is_bound_ = true; | |
42 } | |
43 | |
44 bool IsLinked() const { return !is_bound_ && is_linked_; } | |
45 void SetLinked() { | |
46 is_linked_ = true; | |
47 } | |
48 | |
49 intptr_t Position() const { | |
50 ASSERT(IsBound()); | |
51 return block_->block_id(); | |
52 } | |
53 | |
54 private: | |
55 JoinEntryInstr* block_; | |
56 | |
57 bool is_bound_; | |
58 bool is_linked_; | |
59 }; | |
60 | |
61 | |
62 class RegExpMacroAssembler { | |
srdjan
2014/09/22 22:34:07
Is this object allocated in the C-heap?
jgruber1
2014/09/23 10:58:47
Changed inheritance hierarchy to:
ZoneAllocated <
| |
63 public: | |
64 // The implementation must be able to handle at least: | |
65 static const intptr_t kMaxRegister = (1 << 16) - 1; | |
66 static const intptr_t kMaxCPOffset = (1 << 15) - 1; | |
67 static const intptr_t kMinCPOffset = -(1 << 15); | |
68 | |
69 static const intptr_t kTableSizeBits = 7; | |
70 static const intptr_t kTableSize = 1 << kTableSizeBits; | |
71 static const intptr_t kTableMask = kTableSize - 1; | |
72 | |
73 enum { | |
74 kParamStringIndex = 0, | |
75 kParamStartOffsetIndex, | |
76 kParamCount = 2 | |
77 }; | |
78 | |
79 enum IrregexpImplementation { | |
80 kIRImplementation | |
81 }; | |
82 | |
83 enum StackCheckFlag { | |
84 kNoStackLimitCheck = false, | |
85 kCheckStackLimit = true | |
86 }; | |
87 | |
88 explicit RegExpMacroAssembler(Isolate* isolate); | |
89 virtual ~RegExpMacroAssembler(); | |
90 // The maximal number of pushes between stack checks. Users must supply | |
91 // kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck) | |
92 // at least once for every stack_limit() pushes that are executed. | |
93 virtual intptr_t stack_limit_slack() = 0; | |
94 virtual bool CanReadUnaligned() = 0; | |
95 virtual void AdvanceCurrentPosition(intptr_t by) = 0; // Signed cp change. | |
96 virtual void AdvanceRegister(intptr_t reg, intptr_t by) = 0; // r[reg] += by. | |
97 // Continues execution from the position pushed on the top of the backtrack | |
98 // stack by an earlier PushBacktrack(BlockLabel*). | |
99 virtual void Backtrack() = 0; | |
100 virtual void BindBlock(BlockLabel* label) = 0; | |
101 virtual void CheckAtStart(BlockLabel* on_at_start) = 0; | |
102 // Dispatch after looking the current character up in a 2-bits-per-entry | |
103 // map. The destinations vector has up to 4 labels. | |
104 virtual void CheckCharacter(unsigned c, BlockLabel* on_equal) = 0; | |
105 // Bitwise and the current character with the given constant and then | |
106 // check for a match with c. | |
107 virtual void CheckCharacterAfterAnd(unsigned c, | |
108 unsigned and_with, | |
109 BlockLabel* on_equal) = 0; | |
110 virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater) = 0; | |
111 virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less) = 0; | |
112 virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position) = 0; | |
113 virtual void CheckNotAtStart(BlockLabel* on_not_at_start) = 0; | |
114 virtual void CheckNotBackReference( | |
115 intptr_t start_reg, BlockLabel* on_no_match) = 0; | |
116 virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg, | |
117 BlockLabel* on_no_match) = 0; | |
118 // Check the current character for a match with a literal character. If we | |
119 // fail to match then goto the on_failure label. End of input always | |
120 // matches. If the label is NULL then we should pop a backtrack address off | |
121 // the stack and go to that. | |
122 virtual void CheckNotCharacter(unsigned c, BlockLabel* on_not_equal) = 0; | |
123 virtual void CheckNotCharacterAfterAnd(unsigned c, | |
124 unsigned and_with, | |
125 BlockLabel* on_not_equal) = 0; | |
126 // Subtract a constant from the current character, then and with the given | |
127 // constant and then check for a match with c. | |
128 virtual void CheckNotCharacterAfterMinusAnd(uint16_t c, | |
129 uint16_t minus, | |
130 uint16_t and_with, | |
131 BlockLabel* on_not_equal) = 0; | |
132 virtual void CheckCharacterInRange(uint16_t from, | |
133 uint16_t to, // Both inclusive. | |
134 BlockLabel* on_in_range) = 0; | |
135 virtual void CheckCharacterNotInRange(uint16_t from, | |
136 uint16_t to, // Both inclusive. | |
137 BlockLabel* on_not_in_range) = 0; | |
138 | |
139 // The current character (modulus the kTableSize) is looked up in the byte | |
140 // array, and if the found byte is non-zero, we jump to the on_bit_set label. | |
141 virtual void CheckBitInTable(const TypedData& table, | |
142 BlockLabel* on_bit_set) = 0; | |
143 | |
144 // Checks whether the given offset from the current position is before | |
145 // the end of the string. May overwrite the current character. | |
146 virtual void CheckPosition(intptr_t cp_offset, BlockLabel* on_outside_input) { | |
147 LoadCurrentCharacter(cp_offset, on_outside_input, true); | |
148 } | |
149 // Check whether a standard/default character class matches the current | |
150 // character. Returns false if the type of special character class does | |
151 // not have custom support. | |
152 // May clobber the current loaded character. | |
153 virtual bool CheckSpecialCharacterClass(uint16_t type, | |
154 BlockLabel* on_no_match) { | |
155 return false; | |
156 } | |
157 virtual void Fail() = 0; | |
158 // Jump to the target label, and continue emission there. | |
159 virtual void GoTo(BlockLabel* to) = 0; | |
160 // Check whether a register is >= a given constant and go to a label if it | |
161 // is. Backtracks instead if the label is NULL. | |
162 virtual void IfRegisterGE( | |
163 intptr_t reg, intptr_t comparand, BlockLabel* if_ge) = 0; | |
164 // Check whether a register is < a given constant and go to a label if it is. | |
165 // Backtracks instead if the label is NULL. | |
166 virtual void IfRegisterLT( | |
167 intptr_t reg, intptr_t comparand, BlockLabel* if_lt) = 0; | |
168 // Check whether a register is == to the current position and go to a | |
169 // label if it is. | |
170 virtual void IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq) = 0; | |
171 virtual IrregexpImplementation Implementation() = 0; | |
172 // The assembler is closed, iff there is no current instruction assigned. | |
173 virtual bool IsClosed() const = 0; | |
174 // Jump to the target label without setting it as the current instruction. | |
175 virtual void Jump(BlockLabel* to) = 0; | |
176 virtual void LoadCurrentCharacter(intptr_t cp_offset, | |
177 BlockLabel* on_end_of_input, | |
178 bool check_bounds = true, | |
179 intptr_t characters = 1) = 0; | |
180 virtual void PopCurrentPosition() = 0; | |
181 virtual void PopRegister(intptr_t register_index) = 0; | |
182 // Prints string within the generated code. Used for debugging. | |
183 virtual void Print(const char* str) = 0; | |
184 // Prints all emitted blocks. | |
185 virtual void PrintBlocks() = 0; | |
186 // Pushes the label on the backtrack stack, so that a following Backtrack | |
187 // will go to this label. Always checks the backtrack stack limit. | |
188 virtual void PushBacktrack(BlockLabel* label) = 0; | |
189 virtual void PushCurrentPosition() = 0; | |
190 virtual void PushRegister(intptr_t register_index, | |
191 StackCheckFlag check_stack_limit) = 0; | |
192 virtual void ReadCurrentPositionFromRegister(intptr_t reg) = 0; | |
193 virtual void ReadStackPointerFromRegister(intptr_t reg) = 0; | |
194 virtual void SetCurrentPositionFromEnd(intptr_t by) = 0; | |
195 virtual void SetRegister(intptr_t register_index, intptr_t to) = 0; | |
196 // Return whether the matching (with a global regexp) will be restarted. | |
197 virtual bool Succeed() = 0; | |
198 virtual void WriteCurrentPositionToRegister( | |
199 intptr_t reg, intptr_t cp_offset) = 0; | |
200 virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to) = 0; | |
201 virtual void WriteStackPointerToRegister(intptr_t reg) = 0; | |
202 | |
203 // Controls the generation of large inlined constants in the code. | |
204 void set_slow_safe(bool ssc) { slow_safe_compiler_ = ssc; } | |
205 bool slow_safe() { return slow_safe_compiler_; } | |
206 | |
207 enum GlobalMode { NOT_GLOBAL, GLOBAL, GLOBAL_NO_ZERO_LENGTH_CHECK }; | |
208 // Set whether the regular expression has the global flag. Exiting due to | |
209 // a failure in a global regexp may still mean success overall. | |
210 inline void set_global_mode(GlobalMode mode) { global_mode_ = mode; } | |
211 inline bool global() { return global_mode_ != NOT_GLOBAL; } | |
212 inline bool global_with_zero_length_check() { | |
213 return global_mode_ == GLOBAL; | |
214 } | |
215 | |
216 Isolate* isolate() const { return isolate_; } | |
217 | |
218 private: | |
219 bool slow_safe_compiler_; | |
220 bool global_mode_; | |
221 Isolate* isolate_; | |
222 }; | |
223 | |
224 | |
225 class IRRegExpMacroAssembler: public RegExpMacroAssembler, | |
226 public ZoneAllocated { | |
227 public: | |
228 // Type of input string to generate code for. | |
229 enum Mode { ASCII = 1, UC16 = 2 }; | |
230 | |
231 // Result of calling generated native RegExp code. | |
232 // RETRY: Something significant changed during execution, and the matching | |
233 // should be retried from scratch. | |
234 // EXCEPTION: Something failed during execution. If no exception has been | |
235 // thrown, it's an internal out-of-memory, and the caller should | |
236 // throw the exception. | |
237 // FAILURE: Matching failed. | |
238 // SUCCESS: Matching succeeded, and the output array has been filled with | |
239 // capture positions. | |
240 enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 }; | |
241 | |
242 IRRegExpMacroAssembler(intptr_t specialization_cid, | |
243 intptr_t capture_count, | |
244 const ParsedFunction* parsed_function, | |
245 ZoneGrowableArray<const ICData*>* ic_data_array, | |
246 Isolate* isolate); | |
247 virtual ~IRRegExpMacroAssembler(); | |
248 | |
249 virtual bool CanReadUnaligned(); | |
250 | |
251 // Compares two-byte strings case insensitively. | |
252 // Called from generated RegExp code. | |
253 static RawBool* CaseInsensitiveCompareUC16( | |
254 RawString* str_raw, | |
255 RawSmi* lhs_index_raw, | |
256 RawSmi* rhs_index_raw, | |
257 RawSmi* length_raw); | |
258 | |
259 static RawArray* Execute(const Function& function, | |
260 const String& input, | |
261 const Smi& start_offset, | |
262 Isolate* isolate); | |
263 | |
264 virtual bool IsClosed() const { return (current_instruction_ == NULL); } | |
265 | |
266 virtual intptr_t stack_limit_slack(); | |
267 virtual void AdvanceCurrentPosition(intptr_t by); | |
268 virtual void AdvanceRegister(intptr_t reg, intptr_t by); | |
269 virtual void Backtrack(); | |
270 virtual void BindBlock(BlockLabel* label); | |
271 virtual void CheckAtStart(BlockLabel* on_at_start); | |
272 virtual void CheckCharacter(uint32_t c, BlockLabel* on_equal); | |
273 virtual void CheckCharacterAfterAnd(uint32_t c, | |
274 uint32_t mask, | |
275 BlockLabel* on_equal); | |
276 virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater); | |
277 virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less); | |
278 // A "greedy loop" is a loop that is both greedy and with a simple | |
279 // body. It has a particularly simple implementation. | |
280 virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position); | |
281 virtual void CheckNotAtStart(BlockLabel* on_not_at_start); | |
282 virtual void CheckNotBackReference(intptr_t start_reg, | |
283 BlockLabel* on_no_match); | |
284 virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg, | |
285 BlockLabel* on_no_match); | |
286 virtual void CheckNotCharacter(uint32_t c, BlockLabel* on_not_equal); | |
287 virtual void CheckNotCharacterAfterAnd(uint32_t c, | |
288 uint32_t mask, | |
289 BlockLabel* on_not_equal); | |
290 virtual void CheckNotCharacterAfterMinusAnd(uint16_t c, | |
291 uint16_t minus, | |
292 uint16_t mask, | |
293 BlockLabel* on_not_equal); | |
294 virtual void CheckCharacterInRange(uint16_t from, | |
295 uint16_t to, | |
296 BlockLabel* on_in_range); | |
297 virtual void CheckCharacterNotInRange(uint16_t from, | |
298 uint16_t to, | |
299 BlockLabel* on_not_in_range); | |
300 virtual void CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set); | |
301 | |
302 // Checks whether the given offset from the current position is before | |
303 // the end of the string. | |
304 virtual void CheckPosition(intptr_t cp_offset, BlockLabel* on_outside_input); | |
305 virtual bool CheckSpecialCharacterClass( | |
306 uint16_t type, BlockLabel* on_no_match); | |
307 virtual void Fail(); | |
308 virtual void GoTo(BlockLabel* to); | |
309 virtual void IfRegisterGE(intptr_t reg, | |
310 intptr_t comparand, BlockLabel* if_ge); | |
311 virtual void IfRegisterLT(intptr_t reg, | |
312 intptr_t comparand, BlockLabel* if_lt); | |
313 virtual void IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq); | |
314 virtual IrregexpImplementation Implementation(); | |
315 virtual void Jump(BlockLabel* to); | |
316 virtual void LoadCurrentCharacter(intptr_t cp_offset, | |
317 BlockLabel* on_end_of_input, | |
318 bool check_bounds = true, | |
319 intptr_t characters = 1); | |
320 virtual void PopCurrentPosition(); | |
321 virtual void PopRegister(intptr_t register_index); | |
322 virtual void Print(const char* str); | |
323 virtual void PushBacktrack(BlockLabel* label); | |
324 virtual void PushCurrentPosition(); | |
325 virtual void PushRegister(intptr_t register_index, | |
326 StackCheckFlag check_stack_limit); | |
327 virtual void ReadCurrentPositionFromRegister(intptr_t reg); | |
328 virtual void ReadStackPointerFromRegister(intptr_t reg); | |
329 virtual void SetCurrentPositionFromEnd(intptr_t by); | |
330 virtual void SetRegister(intptr_t register_index, intptr_t to); | |
331 virtual bool Succeed(); | |
332 virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset); | |
333 virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to); | |
334 virtual void WriteStackPointerToRegister(intptr_t reg); | |
335 | |
336 virtual void PrintBlocks(); | |
337 | |
338 GraphEntryInstr* graph_entry() const { return entry_block_; } | |
339 | |
340 intptr_t num_stack_locals() const { return local_id.Count(); } | |
341 intptr_t num_blocks() const { return block_id.Count(); } | |
342 | |
343 // A table mapping block ids to block offsets, used to look up offsets | |
344 // for indirect goto instructions. | |
345 void FinalizeBlockOffsetTable(); | |
346 | |
347 // Fill in indirect goto successors. | |
348 void FinalizeIndirectGotos(); | |
349 | |
350 private: | |
351 // Generate the contents of preset blocks. The entry block is the entry point | |
352 // of the generated code. | |
353 void GenerateEntryBlock(); | |
354 // Performs backtracking, i.e. popping an offset from the stack and doing | |
355 // an indirect goto. | |
356 void GenerateBacktrackBlock(); | |
357 // Copies capture indices into the result area and returns true. | |
358 void GenerateSuccessBlock(); | |
359 // Returns false. | |
360 void GenerateExitBlock(); | |
361 | |
362 enum ComparisonKind { | |
363 kEQ, | |
364 kNE, | |
365 kLT, | |
366 kGT, | |
367 kLTE, | |
368 kGTE, | |
369 }; | |
370 | |
371 struct InstanceCallDescriptor : public ValueObject { | |
372 // Standard (i.e. most non-Smi) functions. | |
373 explicit InstanceCallDescriptor(const String& name) | |
374 : name(&name), | |
375 token_kind(Token::kILLEGAL), | |
376 checked_argument_count(1) { } | |
377 | |
378 // Special cases for Smi and indexing functions. | |
379 explicit InstanceCallDescriptor(Token::Kind token_kind) | |
380 : token_kind(token_kind) { | |
381 switch (token_kind) { | |
382 case Token::kEQ: | |
383 name = &Symbols::EqualOperator(); | |
384 checked_argument_count = 2; | |
385 break; | |
386 case Token::kADD: | |
387 name = &Symbols::Plus(); | |
388 checked_argument_count = 2; | |
389 break; | |
390 case Token::kSUB: | |
391 name = &Symbols::Minus(); | |
392 checked_argument_count = 2; | |
393 break; | |
394 case Token::kBIT_OR: | |
395 name = &Symbols::BitOr(); | |
396 checked_argument_count = 2; | |
397 break; | |
398 case Token::kBIT_AND: | |
399 name = &Symbols::BitAnd(); | |
400 checked_argument_count = 2; | |
401 break; | |
402 case Token::kLT: | |
403 name = &Symbols::LAngleBracket(); | |
404 checked_argument_count = 2; | |
405 break; | |
406 case Token::kLTE: | |
407 name = &Symbols::LessEqualOperator(); | |
408 checked_argument_count = 2; | |
409 break; | |
410 case Token::kGT: | |
411 name = &Symbols::RAngleBracket(); | |
412 checked_argument_count = 2; | |
413 break; | |
414 case Token::kGTE: | |
415 name = &Symbols::GreaterEqualOperator(); | |
416 checked_argument_count = 2; | |
417 break; | |
418 case Token::kNEGATE: | |
419 name = &Symbols::UnaryMinus(); | |
420 checked_argument_count = 1; | |
421 break; | |
422 case Token::kINDEX: | |
423 name = &Symbols::IndexToken(); | |
424 checked_argument_count = 2; | |
425 break; | |
426 case Token::kASSIGN_INDEX: | |
427 name = &Symbols::AssignIndexToken(); | |
428 checked_argument_count = 3; | |
429 break; | |
430 default: | |
431 UNREACHABLE(); | |
432 } | |
433 } | |
434 | |
435 InstanceCallDescriptor(const InstanceCallDescriptor& that) | |
436 : ValueObject(), | |
437 name(that.name), | |
438 token_kind(that.token_kind), | |
439 checked_argument_count(that.checked_argument_count) { } | |
440 | |
441 const String* name; | |
442 Token::Kind token_kind; | |
443 intptr_t checked_argument_count; | |
444 }; | |
445 | |
446 LocalVariable* Local(const String& name); | |
447 LocalVariable* Parameter(const String& name, intptr_t index) const; | |
448 | |
449 ConstantInstr* Int64Constant(int64_t value) const; | |
450 ConstantInstr* Uint64Constant(uint64_t value) const; | |
451 ConstantInstr* BoolConstant(bool value) const; | |
452 ConstantInstr* StringConstant(const char* value) const; | |
453 | |
454 // The word character map static member of the RegExp class. | |
455 // Byte map of one byte characters with a 0xff if the character is a word | |
456 // character (digit, letter or underscore) and 0x00 otherwise. | |
457 // Used by generated RegExp code. | |
458 ConstantInstr* WordCharacterMapConstant() const; | |
459 | |
460 ComparisonInstr* Comparison(ComparisonKind kind, | |
461 Definition* lhs, Definition* rhs); | |
462 | |
463 InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, | |
464 PushArgumentInstr* arg1) const; | |
465 InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, | |
466 PushArgumentInstr* arg1, | |
467 PushArgumentInstr* arg2) const; | |
468 InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, | |
469 PushArgumentInstr* arg1, | |
470 PushArgumentInstr* arg2, | |
471 PushArgumentInstr* arg3) const; | |
472 InstanceCallInstr* InstanceCall( | |
473 const InstanceCallDescriptor& desc, | |
474 ZoneGrowableArray<PushArgumentInstr*>* arguments) const; | |
475 | |
476 StaticCallInstr* StaticCall(const Function& function) const; | |
477 StaticCallInstr* StaticCall(const Function& function, | |
478 PushArgumentInstr* arg1) const; | |
479 StaticCallInstr* StaticCall(const Function& function, | |
480 PushArgumentInstr* arg1, | |
481 PushArgumentInstr* arg2) const; | |
482 StaticCallInstr* StaticCall( | |
483 const Function& function, | |
484 ZoneGrowableArray<PushArgumentInstr*>* arguments) const; | |
485 | |
486 // Creates a new block consisting simply of a goto to dst. | |
487 TargetEntryInstr* TargetWithJoinGoto(JoinEntryInstr* dst); | |
488 IndirectEntryInstr* IndirectWithJoinGoto(JoinEntryInstr* dst); | |
489 | |
490 // Adds, respectively subtracts lhs and rhs and returns the result. | |
491 Value* Add(PushArgumentInstr* lhs, PushArgumentInstr* rhs); | |
492 Value* Sub(PushArgumentInstr* lhs, PushArgumentInstr* rhs); | |
493 | |
494 LoadLocalInstr* LoadLocal(LocalVariable* local) const; | |
495 void StoreLocal(LocalVariable* local, Value* value); | |
496 | |
497 PushArgumentInstr* PushArgument(Value* value); | |
498 | |
499 // Returns the character within the passed string at the specified index. | |
500 Value* CharacterAt(Definition* index); | |
501 | |
502 // Load a number of characters at the given offset from the | |
503 // current position, into the current-character register. | |
504 void LoadCurrentCharacterUnchecked(intptr_t cp_offset, | |
505 intptr_t character_count); | |
506 | |
507 // Check whether preemption has been requested. | |
508 void CheckPreemption(); | |
509 | |
510 // Byte size of chars in the string to match (decided by the Mode argument) | |
511 inline intptr_t char_size() { return static_cast<int>(mode_); } | |
512 | |
513 // Equivalent to a conditional branch to the label, unless the label | |
514 // is NULL, in which case it is a conditional Backtrack. | |
515 void BranchOrBacktrack(ComparisonInstr* comparison, | |
516 BlockLabel* true_successor); | |
517 | |
518 // Set up all local variables and parameters. | |
519 void InitializeLocals(); | |
520 | |
521 // Allocates a new local, and returns the appropriate id for placing it | |
522 // on the stack. | |
523 intptr_t GetNextLocalIndex(); | |
524 | |
525 // We never have any copied parameters. | |
526 intptr_t num_copied_params() const { | |
527 return 0; | |
528 } | |
529 | |
530 // Return the position register at the specified index, creating it if | |
531 // necessary. Note that the number of such registers can exceed the amount | |
532 // required by the number of output captures. | |
533 LocalVariable* position_register(intptr_t index); | |
534 | |
535 void set_current_instruction(Instruction* instruction); | |
536 | |
537 // The following functions are responsible for appending instructions | |
538 // to the current instruction in various ways. The most simple one | |
539 // is AppendInstruction, which simply appends an instruction and performs | |
540 // bookkeeping. | |
541 void AppendInstruction(Instruction* instruction); | |
542 // Similar to AppendInstruction, but closes the current block by | |
543 // setting current_instruction_ to NULL. | |
544 void CloseBlockWith(Instruction* instruction); | |
545 // Appends definition and allocates a temp index for the result. | |
546 Value* Bind(Definition* definition); | |
547 // Appends the definition. | |
548 void Do(Definition* definition); | |
549 // Closes the current block with a jump to the specified block. | |
550 void Jump(JoinEntryInstr* to); | |
551 | |
552 // Accessors for our local stack_. | |
553 void PushStack(Definition* definition); | |
554 Value* PopStack(); | |
555 | |
556 // Prints the specified argument. Used for debugging. | |
557 void Print(PushArgumentInstr* argument); | |
558 | |
559 // A utility class tracking ids of various objects such as blocks, temps, etc. | |
560 class IdAllocator : public ValueObject { | |
561 public: | |
562 IdAllocator() : next_id(0) { } | |
563 | |
564 intptr_t Count() const { return next_id; } | |
565 intptr_t Alloc(intptr_t count = 1) { | |
566 ASSERT(count >= 0); | |
567 intptr_t current_id = next_id; | |
568 next_id += count; | |
569 return current_id; | |
570 } | |
571 void Dealloc(intptr_t count = 1) { | |
572 ASSERT(count <= next_id); | |
573 next_id -= count; | |
574 } | |
575 | |
576 private: | |
577 intptr_t next_id; | |
578 }; | |
579 | |
580 // Which mode to generate code for (ASCII or UC16). | |
581 Mode mode_; | |
582 | |
583 // Which specific string class to generate code for. | |
584 intptr_t specialization_cid_; | |
585 | |
586 // Block entries used internally. | |
587 GraphEntryInstr* entry_block_; | |
588 JoinEntryInstr* start_block_; | |
589 JoinEntryInstr* success_block_; | |
590 JoinEntryInstr* backtrack_block_; | |
591 JoinEntryInstr* exit_block_; | |
592 | |
593 const ParsedFunction* parsed_function_; | |
594 ZoneGrowableArray<const ICData*>* ic_data_array_; | |
595 | |
596 // All created blocks are contained within this set. Used for printing | |
597 // the generated code. | |
598 GrowableArray<BlockEntryInstr*> blocks_; | |
599 | |
600 // The current instruction to link to when new code is emitted. | |
601 Instruction* current_instruction_; | |
602 | |
603 // A list, acting as the runtime stack for both backtrack locations and | |
604 // stored positions within the string. | |
605 LocalVariable* stack_; | |
606 | |
607 // Stores the current character within the string. | |
608 LocalVariable* current_character_; | |
609 | |
610 // Stores the current location within the string as a negative offset | |
611 // from the end of the string. | |
612 LocalVariable* current_position_; | |
613 | |
614 // The string being processed, passed as a function parameter. | |
615 LocalVariable* string_param_; | |
616 | |
617 // Stores the length of string_param_. | |
618 LocalVariable* string_param_length_; | |
619 | |
620 // The start index within the string, passed as a function parameter. | |
621 LocalVariable* start_index_param_; | |
622 | |
623 // An assortment of utility variables. | |
624 LocalVariable* capture_length_; | |
625 LocalVariable* match_start_index_; | |
626 LocalVariable* capture_start_index_; | |
627 LocalVariable* match_end_index_; | |
628 LocalVariable* char_in_capture_; | |
629 LocalVariable* char_in_match_; | |
630 | |
631 LocalVariable* result_; | |
632 | |
633 // Stored positions containing group bounds. Generated as needed. | |
634 const intptr_t position_registers_count_; | |
635 GrowableArray<LocalVariable*> position_registers_; | |
636 | |
637 // The actual array object used as the stack. | |
638 GrowableObjectArray& stack_array_; | |
639 | |
640 GrowableArray<IndirectGotoInstr*> igotos_; | |
641 | |
642 IdAllocator block_id; | |
643 IdAllocator temp_id; | |
644 IdAllocator arg_id; | |
645 IdAllocator local_id; | |
646 }; | |
647 | |
648 } // namespace dart | |
649 | |
650 #endif // VM_REGEXP_ASSEMBLER_H_ | |
OLD | NEW |