| 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_assembler_bytecode.h" | 
|  | 10 #include "vm/regexp_assembler_ir.h" | 
| 9 #include "vm/regexp_ast.h" | 11 #include "vm/regexp_ast.h" | 
| 10 #include "vm/unibrow-inl.h" | 12 #include "vm/unibrow-inl.h" | 
| 11 #include "vm/unicode.h" | 13 #include "vm/unicode.h" | 
| 12 #include "vm/symbols.h" | 14 #include "vm/symbols.h" | 
| 13 #include "vm/thread.h" | 15 #include "vm/thread.h" | 
| 14 | 16 | 
| 15 #define Z (zone()) | 17 #define Z (zone()) | 
| 16 | 18 | 
| 17 namespace dart { | 19 namespace dart { | 
| 18 | 20 | 
| 19 DECLARE_FLAG(bool, trace_irregexp); | 21 DECLARE_FLAG(bool, trace_irregexp); | 
|  | 22 DEFINE_FLAG(bool, interpret_irregexp, false, | 
|  | 23             "Use irregexp bytecode interpreter"); | 
| 20 | 24 | 
| 21 // Default to generating optimized regexp code. | 25 // Default to generating optimized regexp code. | 
| 22 static const bool kRegexpOptimization = true; | 26 static const bool kRegexpOptimization = true; | 
| 23 | 27 | 
| 24 // More makes code generation slower, less makes V8 benchmark score lower. | 28 // More makes code generation slower, less makes V8 benchmark score lower. | 
| 25 static const intptr_t kMaxLookaheadForBoyerMoore = 8; | 29 static const intptr_t kMaxLookaheadForBoyerMoore = 8; | 
| 26 | 30 | 
| 27 ContainedInLattice AddRange(ContainedInLattice containment, | 31 ContainedInLattice AddRange(ContainedInLattice containment, | 
| 28                             const intptr_t* ranges, | 32                             const intptr_t* ranges, | 
| 29                             intptr_t ranges_length, | 33                             intptr_t ranges_length, | 
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 287  private: | 291  private: | 
| 288   CharacterFrequency frequencies_[RegExpMacroAssembler::kTableSize]; | 292   CharacterFrequency frequencies_[RegExpMacroAssembler::kTableSize]; | 
| 289   intptr_t total_samples_; | 293   intptr_t total_samples_; | 
| 290 }; | 294 }; | 
| 291 | 295 | 
| 292 | 296 | 
| 293 class RegExpCompiler : public ValueObject { | 297 class RegExpCompiler : public ValueObject { | 
| 294  public: | 298  public: | 
| 295   RegExpCompiler(intptr_t capture_count, | 299   RegExpCompiler(intptr_t capture_count, | 
| 296                  bool ignore_case, | 300                  bool ignore_case, | 
| 297                  intptr_t specialization_cid); | 301                  bool is_one_byte); | 
| 298 | 302 | 
| 299   intptr_t AllocateRegister() { | 303   intptr_t AllocateRegister() { | 
| 300     return next_register_++; | 304     return next_register_++; | 
| 301   } | 305   } | 
| 302 | 306 | 
| 303   RegExpEngine::CompilationResult Assemble(IRRegExpMacroAssembler* assembler, | 307   RegExpEngine::CompilationResult Assemble( | 
| 304                                            RegExpNode* start, | 308       IRRegExpMacroAssembler* assembler, | 
| 305                                            intptr_t capture_count, | 309       RegExpNode* start, | 
| 306                                            const String& pattern); | 310       intptr_t capture_count, | 
|  | 311       const String& pattern); | 
|  | 312 | 
|  | 313   RegExpEngine::CompilationResult Assemble( | 
|  | 314       BytecodeRegExpMacroAssembler* assembler, | 
|  | 315       RegExpNode* start, | 
|  | 316       intptr_t capture_count, | 
|  | 317       const String& pattern); | 
| 307 | 318 | 
| 308   inline void AddWork(RegExpNode* node) { work_list_->Add(node); } | 319   inline void AddWork(RegExpNode* node) { work_list_->Add(node); } | 
| 309 | 320 | 
| 310   static const intptr_t kImplementationOffset = 0; | 321   static const intptr_t kImplementationOffset = 0; | 
| 311   static const intptr_t kNumberOfRegistersOffset = 0; | 322   static const intptr_t kNumberOfRegistersOffset = 0; | 
| 312   static const intptr_t kCodeOffset = 1; | 323   static const intptr_t kCodeOffset = 1; | 
| 313 | 324 | 
| 314   IRRegExpMacroAssembler* macro_assembler() { return macro_assembler_; } | 325   RegExpMacroAssembler* macro_assembler() { return macro_assembler_; } | 
| 315   EndNode* accept() { return accept_; } | 326   EndNode* accept() { return accept_; } | 
| 316 | 327 | 
| 317   static const intptr_t kMaxRecursion = 100; | 328   static const intptr_t kMaxRecursion = 100; | 
| 318   inline intptr_t recursion_depth() { return recursion_depth_; } | 329   inline intptr_t recursion_depth() { return recursion_depth_; } | 
| 319   inline void IncrementRecursionDepth() { recursion_depth_++; } | 330   inline void IncrementRecursionDepth() { recursion_depth_++; } | 
| 320   inline void DecrementRecursionDepth() { recursion_depth_--; } | 331   inline void DecrementRecursionDepth() { recursion_depth_--; } | 
| 321 | 332 | 
| 322   void SetRegExpTooBig() { reg_exp_too_big_ = true; } | 333   void SetRegExpTooBig() { reg_exp_too_big_ = true; } | 
| 323 | 334 | 
| 324   inline bool ignore_case() { return ignore_case_; } | 335   inline bool ignore_case() { return ignore_case_; } | 
| 325   inline bool one_byte() const { | 336   inline bool one_byte() const { return is_one_byte_; } | 
| 326     return (specialization_cid_ == kOneByteStringCid || |  | 
| 327             specialization_cid_ == kExternalOneByteStringCid); |  | 
| 328   } |  | 
| 329   inline intptr_t specialization_cid() { return specialization_cid_; } |  | 
| 330   FrequencyCollator* frequency_collator() { return &frequency_collator_; } | 337   FrequencyCollator* frequency_collator() { return &frequency_collator_; } | 
| 331 | 338 | 
| 332   intptr_t current_expansion_factor() { return current_expansion_factor_; } | 339   intptr_t current_expansion_factor() { return current_expansion_factor_; } | 
| 333   void set_current_expansion_factor(intptr_t value) { | 340   void set_current_expansion_factor(intptr_t value) { | 
| 334     current_expansion_factor_ = value; | 341     current_expansion_factor_ = value; | 
| 335   } | 342   } | 
| 336 | 343 | 
| 337   Zone* zone() const { return zone_; } | 344   Zone* zone() const { return zone_; } | 
| 338 | 345 | 
| 339   static const intptr_t kNoRegister = -1; | 346   static const intptr_t kNoRegister = -1; | 
| 340 | 347 | 
| 341  private: | 348  private: | 
| 342   EndNode* accept_; | 349   EndNode* accept_; | 
| 343   intptr_t next_register_; | 350   intptr_t next_register_; | 
| 344   ZoneGrowableArray<RegExpNode*>* work_list_; | 351   ZoneGrowableArray<RegExpNode*>* work_list_; | 
| 345   intptr_t recursion_depth_; | 352   intptr_t recursion_depth_; | 
| 346   IRRegExpMacroAssembler* macro_assembler_; | 353   RegExpMacroAssembler* macro_assembler_; | 
| 347   bool ignore_case_; | 354   bool ignore_case_; | 
| 348   intptr_t specialization_cid_; | 355   bool is_one_byte_; | 
| 349   bool reg_exp_too_big_; | 356   bool reg_exp_too_big_; | 
| 350   intptr_t current_expansion_factor_; | 357   intptr_t current_expansion_factor_; | 
| 351   FrequencyCollator frequency_collator_; | 358   FrequencyCollator frequency_collator_; | 
| 352   Zone* zone_; | 359   Zone* zone_; | 
| 353 }; | 360 }; | 
| 354 | 361 | 
| 355 | 362 | 
| 356 class RecursionCheck : public ValueObject { | 363 class RecursionCheck : public ValueObject { | 
| 357  public: | 364  public: | 
| 358   explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { | 365   explicit RecursionCheck(RegExpCompiler* compiler) : compiler_(compiler) { | 
| 359     compiler->IncrementRecursionDepth(); | 366     compiler->IncrementRecursionDepth(); | 
| 360   } | 367   } | 
| 361   ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } | 368   ~RecursionCheck() { compiler_->DecrementRecursionDepth(); } | 
| 362  private: | 369  private: | 
| 363   RegExpCompiler* compiler_; | 370   RegExpCompiler* compiler_; | 
| 364 }; | 371 }; | 
| 365 | 372 | 
| 366 | 373 | 
| 367 static RegExpEngine::CompilationResult IrregexpRegExpTooBig() { | 374 static RegExpEngine::CompilationResult IrregexpRegExpTooBig() { | 
| 368   return RegExpEngine::CompilationResult("RegExp too big"); | 375   return RegExpEngine::CompilationResult("RegExp too big"); | 
| 369 } | 376 } | 
| 370 | 377 | 
| 371 | 378 | 
| 372 // Attempts to compile the regexp using an Irregexp code generator.  Returns | 379 // Attempts to compile the regexp using an Irregexp code generator.  Returns | 
| 373 // a fixed array or a null handle depending on whether it succeeded. | 380 // a fixed array or a null handle depending on whether it succeeded. | 
| 374 RegExpCompiler::RegExpCompiler(intptr_t capture_count, bool ignore_case, | 381 RegExpCompiler::RegExpCompiler(intptr_t capture_count, | 
| 375                                intptr_t specialization_cid) | 382                                bool ignore_case, | 
|  | 383                                bool is_one_byte) | 
| 376     : next_register_(2 * (capture_count + 1)), | 384     : next_register_(2 * (capture_count + 1)), | 
| 377       work_list_(NULL), | 385       work_list_(NULL), | 
| 378       recursion_depth_(0), | 386       recursion_depth_(0), | 
| 379       ignore_case_(ignore_case), | 387       ignore_case_(ignore_case), | 
| 380       specialization_cid_(specialization_cid), | 388       is_one_byte_(is_one_byte), | 
| 381       reg_exp_too_big_(false), | 389       reg_exp_too_big_(false), | 
| 382       current_expansion_factor_(1), | 390       current_expansion_factor_(1), | 
| 383       zone_(Thread::Current()->zone()) { | 391       zone_(Thread::Current()->zone()) { | 
| 384   accept_ = new(Z) EndNode(EndNode::ACCEPT, Z); | 392   accept_ = new(Z) EndNode(EndNode::ACCEPT, Z); | 
| 385 } | 393 } | 
| 386 | 394 | 
| 387 | 395 | 
| 388 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | 396 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | 
| 389     IRRegExpMacroAssembler* macro_assembler, | 397     IRRegExpMacroAssembler* macro_assembler, | 
| 390     RegExpNode* start, | 398     RegExpNode* start, | 
| 391     intptr_t capture_count, | 399     intptr_t capture_count, | 
| 392     const String& pattern) { | 400     const String& pattern) { | 
| 393   static const bool use_slow_safe_regexp_compiler = false; | 401   macro_assembler->set_slow_safe(false /* use_slow_safe_regexp_compiler */); | 
| 394 |  | 
| 395   macro_assembler->set_slow_safe(use_slow_safe_regexp_compiler); |  | 
| 396   macro_assembler_ = macro_assembler; | 402   macro_assembler_ = macro_assembler; | 
| 397 | 403 | 
| 398   ZoneGrowableArray<RegExpNode*> work_list(0); | 404   ZoneGrowableArray<RegExpNode*> work_list(0); | 
| 399   work_list_ = &work_list; | 405   work_list_ = &work_list; | 
| 400   BlockLabel fail; | 406   BlockLabel fail; | 
| 401   macro_assembler_->PushBacktrack(&fail); | 407   macro_assembler_->PushBacktrack(&fail); | 
| 402   Trace new_trace; | 408   Trace new_trace; | 
| 403   start->Emit(this, &new_trace); | 409   start->Emit(this, &new_trace); | 
| 404   macro_assembler_->BindBlock(&fail); | 410   macro_assembler_->BindBlock(&fail); | 
| 405   macro_assembler_->Fail(); | 411   macro_assembler_->Fail(); | 
| 406   while (!work_list.is_empty()) { | 412   while (!work_list.is_empty()) { | 
| 407     work_list.RemoveLast()->Emit(this, &new_trace); | 413     work_list.RemoveLast()->Emit(this, &new_trace); | 
| 408   } | 414   } | 
| 409   if (reg_exp_too_big_) return IrregexpRegExpTooBig(); | 415   if (reg_exp_too_big_) return IrregexpRegExpTooBig(); | 
| 410 | 416 | 
| 411   macro_assembler->GenerateBacktrackBlock(); | 417   macro_assembler->GenerateBacktrackBlock(); | 
| 412   macro_assembler->FinalizeRegistersArray(); | 418   macro_assembler->FinalizeRegistersArray(); | 
| 413 | 419 | 
| 414   return RegExpEngine::CompilationResult(macro_assembler->backtrack_goto(), | 420   return RegExpEngine::CompilationResult(macro_assembler->backtrack_goto(), | 
| 415                                          macro_assembler->graph_entry(), | 421                                          macro_assembler->graph_entry(), | 
| 416                                          macro_assembler->num_blocks(), | 422                                          macro_assembler->num_blocks(), | 
| 417                                          macro_assembler->num_stack_locals()); | 423                                          macro_assembler->num_stack_locals(), | 
|  | 424                                          next_register_); | 
| 418 } | 425 } | 
| 419 | 426 | 
| 420 | 427 | 
|  | 428 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | 
|  | 429     BytecodeRegExpMacroAssembler* macro_assembler, | 
|  | 430     RegExpNode* start, | 
|  | 431     intptr_t capture_count, | 
|  | 432     const String& pattern) { | 
|  | 433   macro_assembler->set_slow_safe(false /* use_slow_safe_regexp_compiler */); | 
|  | 434   macro_assembler_ = macro_assembler; | 
|  | 435 | 
|  | 436   ZoneGrowableArray<RegExpNode*> work_list(0); | 
|  | 437   work_list_ = &work_list; | 
|  | 438   BlockLabel fail; | 
|  | 439   macro_assembler_->PushBacktrack(&fail); | 
|  | 440   Trace new_trace; | 
|  | 441   start->Emit(this, &new_trace); | 
|  | 442   macro_assembler_->BindBlock(&fail); | 
|  | 443   macro_assembler_->Fail(); | 
|  | 444   while (!work_list.is_empty()) { | 
|  | 445     work_list.RemoveLast()->Emit(this, &new_trace); | 
|  | 446   } | 
|  | 447   if (reg_exp_too_big_) return IrregexpRegExpTooBig(); | 
|  | 448 | 
|  | 449   TypedData& bytecode = TypedData::ZoneHandle(macro_assembler->GetBytecode()); | 
|  | 450   return RegExpEngine::CompilationResult(&bytecode, next_register_); | 
|  | 451 } | 
|  | 452 | 
|  | 453 | 
| 421 bool Trace::DeferredAction::Mentions(intptr_t that) { | 454 bool Trace::DeferredAction::Mentions(intptr_t that) { | 
| 422   if (action_type() == ActionNode::CLEAR_CAPTURES) { | 455   if (action_type() == ActionNode::CLEAR_CAPTURES) { | 
| 423     Interval range = static_cast<DeferredClearCaptures*>(this)->range(); | 456     Interval range = static_cast<DeferredClearCaptures*>(this)->range(); | 
| 424     return range.Contains(that); | 457     return range.Contains(that); | 
| 425   } else { | 458   } else { | 
| 426     return reg() == that; | 459     return reg() == that; | 
| 427   } | 460   } | 
| 428 } | 461 } | 
| 429 | 462 | 
| 430 | 463 | 
| (...skipping 4538 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 4969     return; | 5002     return; | 
| 4970   } | 5003   } | 
| 4971   on_success()->FillInBMInfo(offset, | 5004   on_success()->FillInBMInfo(offset, | 
| 4972                              budget - 1, | 5005                              budget - 1, | 
| 4973                              bm, | 5006                              bm, | 
| 4974                              true);  // Not at start after a text node. | 5007                              true);  // Not at start after a text node. | 
| 4975   if (initial_offset == 0) set_bm_info(not_at_start, bm); | 5008   if (initial_offset == 0) set_bm_info(not_at_start, bm); | 
| 4976 } | 5009 } | 
| 4977 | 5010 | 
| 4978 | 5011 | 
| 4979 RegExpEngine::CompilationResult RegExpEngine::Compile( | 5012 RegExpEngine::CompilationResult RegExpEngine::CompileIR( | 
| 4980     RegExpCompileData* data, | 5013     RegExpCompileData* data, | 
| 4981     const ParsedFunction* parsed_function, | 5014     const ParsedFunction* parsed_function, | 
| 4982     const ZoneGrowableArray<const ICData*>& ic_data_array) { | 5015     const ZoneGrowableArray<const ICData*>& ic_data_array) { | 
|  | 5016   ASSERT(!FLAG_interpret_irregexp); | 
| 4983   Zone* zone = Thread::Current()->zone(); | 5017   Zone* zone = Thread::Current()->zone(); | 
| 4984 | 5018 | 
| 4985   const Function& function = parsed_function->function(); | 5019   const Function& function = parsed_function->function(); | 
| 4986   const intptr_t specialization_cid = function.regexp_cid(); | 5020   const intptr_t specialization_cid = function.regexp_cid(); | 
| 4987   const bool is_one_byte = (specialization_cid == kOneByteStringCid || | 5021   const bool is_one_byte = (specialization_cid == kOneByteStringCid || | 
| 4988                             specialization_cid == kExternalOneByteStringCid); | 5022                             specialization_cid == kExternalOneByteStringCid); | 
| 4989   JSRegExp& regexp = JSRegExp::Handle(zone, function.regexp()); | 5023   JSRegExp& regexp = JSRegExp::Handle(zone, function.regexp()); | 
| 4990   const String& pattern = String::Handle(zone, regexp.pattern()); | 5024   const String& pattern = String::Handle(zone, regexp.pattern()); | 
| 4991 | 5025 | 
| 4992   ASSERT(!regexp.IsNull()); | 5026   ASSERT(!regexp.IsNull()); | 
| 4993   ASSERT(!pattern.IsNull()); | 5027   ASSERT(!pattern.IsNull()); | 
| 4994 | 5028 | 
| 4995   const bool ignore_case = regexp.is_ignore_case(); | 5029   const bool ignore_case = regexp.is_ignore_case(); | 
| 4996   const bool is_global = regexp.is_global(); | 5030   const bool is_global = regexp.is_global(); | 
| 4997 | 5031 | 
| 4998   RegExpCompiler compiler(data->capture_count, ignore_case, specialization_cid); | 5032   RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte); | 
| 4999 | 5033 | 
| 5000   // TODO(zerny): Frequency sampling is currently disabled because of several | 5034   // TODO(zerny): Frequency sampling is currently disabled because of several | 
| 5001   // issues. We do not want to store subject strings in the regexp object since | 5035   // issues. We do not want to store subject strings in the regexp object since | 
| 5002   // they might be long and we should not prevent their garbage collection. | 5036   // they might be long and we should not prevent their garbage collection. | 
| 5003   // Passing them to this function explicitly does not help, since we must | 5037   // Passing them to this function explicitly does not help, since we must | 
| 5004   // generate exactly the same IR for both the unoptimizing and optimizing | 5038   // generate exactly the same IR for both the unoptimizing and optimizing | 
| 5005   // pipelines (otherwise it gets confused when i.e. deopt id's differ). | 5039   // pipelines (otherwise it gets confused when i.e. deopt id's differ). | 
| 5006   // An option would be to store sampling results in the regexp object, but | 5040   // An option would be to store sampling results in the regexp object, but | 
| 5007   // I'm not sure the performance gains are relevant enough. | 5041   // I'm not sure the performance gains are relevant enough. | 
| 5008 | 5042 | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 5091                         pattern); | 5125                         pattern); | 
| 5092 | 5126 | 
| 5093   if (FLAG_trace_irregexp) { | 5127   if (FLAG_trace_irregexp) { | 
| 5094     macro_assembler->PrintBlocks(); | 5128     macro_assembler->PrintBlocks(); | 
| 5095   } | 5129   } | 
| 5096 | 5130 | 
| 5097   return result; | 5131   return result; | 
| 5098 } | 5132 } | 
| 5099 | 5133 | 
| 5100 | 5134 | 
|  | 5135 RegExpEngine::CompilationResult RegExpEngine::CompileBytecode( | 
|  | 5136     RegExpCompileData* data, | 
|  | 5137     const JSRegExp& regexp, | 
|  | 5138     bool is_one_byte, | 
|  | 5139     Zone* zone) { | 
|  | 5140   ASSERT(FLAG_interpret_irregexp); | 
|  | 5141   const String& pattern = String::Handle(zone, regexp.pattern()); | 
|  | 5142 | 
|  | 5143   ASSERT(!regexp.IsNull()); | 
|  | 5144   ASSERT(!pattern.IsNull()); | 
|  | 5145 | 
|  | 5146   const bool ignore_case = regexp.is_ignore_case(); | 
|  | 5147   const bool is_global = regexp.is_global(); | 
|  | 5148 | 
|  | 5149   RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte); | 
|  | 5150 | 
|  | 5151   // TODO(zerny): Frequency sampling is currently disabled because of several | 
|  | 5152   // issues. We do not want to store subject strings in the regexp object since | 
|  | 5153   // they might be long and we should not prevent their garbage collection. | 
|  | 5154   // Passing them to this function explicitly does not help, since we must | 
|  | 5155   // generate exactly the same IR for both the unoptimizing and optimizing | 
|  | 5156   // pipelines (otherwise it gets confused when i.e. deopt id's differ). | 
|  | 5157   // An option would be to store sampling results in the regexp object, but | 
|  | 5158   // I'm not sure the performance gains are relevant enough. | 
|  | 5159 | 
|  | 5160   // Wrap the body of the regexp in capture #0. | 
|  | 5161   RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, | 
|  | 5162                                                     0, | 
|  | 5163                                                     &compiler, | 
|  | 5164                                                     compiler.accept()); | 
|  | 5165 | 
|  | 5166   RegExpNode* node = captured_body; | 
|  | 5167   bool is_end_anchored = data->tree->IsAnchoredAtEnd(); | 
|  | 5168   bool is_start_anchored = data->tree->IsAnchoredAtStart(); | 
|  | 5169   intptr_t max_length = data->tree->max_match(); | 
|  | 5170   if (!is_start_anchored) { | 
|  | 5171     // Add a .*? at the beginning, outside the body capture, unless | 
|  | 5172     // this expression is anchored at the beginning. | 
|  | 5173     RegExpNode* loop_node = | 
|  | 5174         RegExpQuantifier::ToNode(0, | 
|  | 5175                                  RegExpTree::kInfinity, | 
|  | 5176                                  false, | 
|  | 5177                                  new(zone) RegExpCharacterClass('*'), | 
|  | 5178                                  &compiler, | 
|  | 5179                                  captured_body, | 
|  | 5180                                  data->contains_anchor); | 
|  | 5181 | 
|  | 5182     if (data->contains_anchor) { | 
|  | 5183       // Unroll loop once, to take care of the case that might start | 
|  | 5184       // at the start of input. | 
|  | 5185       ChoiceNode* first_step_node = new(zone) ChoiceNode(2, zone); | 
|  | 5186       first_step_node->AddAlternative(GuardedAlternative(captured_body)); | 
|  | 5187       first_step_node->AddAlternative(GuardedAlternative( | 
|  | 5188           new(zone) TextNode( | 
|  | 5189               new(zone) RegExpCharacterClass('*'), loop_node))); | 
|  | 5190       node = first_step_node; | 
|  | 5191     } else { | 
|  | 5192       node = loop_node; | 
|  | 5193     } | 
|  | 5194   } | 
|  | 5195   if (is_one_byte) { | 
|  | 5196     node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | 
|  | 5197     // Do it again to propagate the new nodes to places where they were not | 
|  | 5198     // put because they had not been calculated yet. | 
|  | 5199     if (node != NULL) { | 
|  | 5200       node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | 
|  | 5201     } | 
|  | 5202   } | 
|  | 5203 | 
|  | 5204   if (node == NULL) node = new(zone) EndNode(EndNode::BACKTRACK, zone); | 
|  | 5205   data->node = node; | 
|  | 5206   Analysis analysis(ignore_case, is_one_byte); | 
|  | 5207   analysis.EnsureAnalyzed(node); | 
|  | 5208   if (analysis.has_failed()) { | 
|  | 5209     const char* error_message = analysis.error_message(); | 
|  | 5210     return CompilationResult(error_message); | 
|  | 5211   } | 
|  | 5212 | 
|  | 5213   // Bytecode regexp implementation. | 
|  | 5214 | 
|  | 5215   ZoneGrowableArray<uint8_t> buffer(zone, 1024); | 
|  | 5216   BytecodeRegExpMacroAssembler* macro_assembler = | 
|  | 5217       new(zone) BytecodeRegExpMacroAssembler(&buffer, zone); | 
|  | 5218 | 
|  | 5219   // Inserted here, instead of in Assembler, because it depends on information | 
|  | 5220   // in the AST that isn't replicated in the Node structure. | 
|  | 5221   static const intptr_t kMaxBacksearchLimit = 1024; | 
|  | 5222   if (is_end_anchored && | 
|  | 5223       !is_start_anchored && | 
|  | 5224       max_length < kMaxBacksearchLimit) { | 
|  | 5225     macro_assembler->SetCurrentPositionFromEnd(max_length); | 
|  | 5226   } | 
|  | 5227 | 
|  | 5228   if (is_global) { | 
|  | 5229     macro_assembler->set_global_mode( | 
|  | 5230         (data->tree->min_match() > 0) | 
|  | 5231             ? RegExpMacroAssembler::GLOBAL_NO_ZERO_LENGTH_CHECK | 
|  | 5232             : RegExpMacroAssembler::GLOBAL); | 
|  | 5233   } | 
|  | 5234 | 
|  | 5235   RegExpEngine::CompilationResult result = | 
|  | 5236       compiler.Assemble(macro_assembler, | 
|  | 5237                         node, | 
|  | 5238                         data->capture_count, | 
|  | 5239                         pattern); | 
|  | 5240 | 
|  | 5241   if (FLAG_trace_irregexp) { | 
|  | 5242     macro_assembler->PrintBlocks(); | 
|  | 5243   } | 
|  | 5244 | 
|  | 5245   return result; | 
|  | 5246 } | 
|  | 5247 | 
|  | 5248 | 
| 5101 static void CreateSpecializedFunction(Zone* zone, | 5249 static void CreateSpecializedFunction(Zone* zone, | 
| 5102                                       const JSRegExp& regexp, | 5250                                       const JSRegExp& regexp, | 
| 5103                                       intptr_t specialization_cid, | 5251                                       intptr_t specialization_cid, | 
| 5104                                       const Object& owner) { | 5252                                       const Object& owner) { | 
| 5105   const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; | 5253   const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; | 
| 5106 | 5254 | 
| 5107   Function& fn = Function::Handle(zone, Function::New( | 5255   Function& fn = Function::Handle(zone, Function::New( | 
| 5108       // Append the regexp pattern to the function name. | 5256       // Append the regexp pattern to the function name. | 
| 5109       String::Handle(zone, Symbols::New( | 5257       String::Handle(zone, Symbols::New( | 
| 5110           String::Handle(zone, String::Concat( | 5258           String::Handle(zone, String::Concat( | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 5171   CreateSpecializedFunction(zone, regexp, kOneByteStringCid, owner); | 5319   CreateSpecializedFunction(zone, regexp, kOneByteStringCid, owner); | 
| 5172   CreateSpecializedFunction(zone, regexp, kTwoByteStringCid, owner); | 5320   CreateSpecializedFunction(zone, regexp, kTwoByteStringCid, owner); | 
| 5173   CreateSpecializedFunction(zone, regexp, kExternalOneByteStringCid, owner); | 5321   CreateSpecializedFunction(zone, regexp, kExternalOneByteStringCid, owner); | 
| 5174   CreateSpecializedFunction(zone, regexp, kExternalTwoByteStringCid, owner); | 5322   CreateSpecializedFunction(zone, regexp, kExternalTwoByteStringCid, owner); | 
| 5175 | 5323 | 
| 5176   return regexp.raw(); | 5324   return regexp.raw(); | 
| 5177 } | 5325 } | 
| 5178 | 5326 | 
| 5179 | 5327 | 
| 5180 }  // namespace dart | 5328 }  // namespace dart | 
| OLD | NEW | 
|---|