Chromium Code Reviews| 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, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 407 work_list.RemoveLast()->Emit(this, &new_trace); | 415 work_list.RemoveLast()->Emit(this, &new_trace); |
| 408 } | 416 } |
| 409 if (reg_exp_too_big_) return IrregexpRegExpTooBig(); | 417 if (reg_exp_too_big_) return IrregexpRegExpTooBig(); |
| 410 | 418 |
| 411 macro_assembler->GenerateBacktrackBlock(); | 419 macro_assembler->GenerateBacktrackBlock(); |
| 412 macro_assembler->FinalizeRegistersArray(); | 420 macro_assembler->FinalizeRegistersArray(); |
| 413 | 421 |
| 414 return RegExpEngine::CompilationResult(macro_assembler->backtrack_goto(), | 422 return RegExpEngine::CompilationResult(macro_assembler->backtrack_goto(), |
| 415 macro_assembler->graph_entry(), | 423 macro_assembler->graph_entry(), |
| 416 macro_assembler->num_blocks(), | 424 macro_assembler->num_blocks(), |
| 417 macro_assembler->num_stack_locals()); | 425 macro_assembler->num_stack_locals(), |
| 426 next_register_); | |
| 418 } | 427 } |
| 419 | 428 |
| 420 | 429 |
| 430 RegExpEngine::CompilationResult RegExpCompiler::Assemble( | |
| 431 BytecodeRegExpMacroAssembler* macro_assembler, | |
| 432 RegExpNode* start, | |
| 433 intptr_t capture_count, | |
| 434 const String& pattern) { | |
| 435 static const bool use_slow_safe_regexp_compiler = false; | |
| 436 | |
| 437 macro_assembler->set_slow_safe(use_slow_safe_regexp_compiler); | |
|
srdjan
2015/07/07 19:30:25
set_slow_safe(false /*use_slow_safe_regexp_compile
rmacnak
2015/07/07 21:42:53
Done.
| |
| 438 macro_assembler_ = macro_assembler; | |
| 439 | |
| 440 ZoneGrowableArray<RegExpNode*> work_list(0); | |
| 441 work_list_ = &work_list; | |
| 442 BlockLabel fail; | |
| 443 macro_assembler_->PushBacktrack(&fail); | |
| 444 Trace new_trace; | |
| 445 start->Emit(this, &new_trace); | |
| 446 macro_assembler_->BindBlock(&fail); | |
| 447 macro_assembler_->Fail(); | |
| 448 while (!work_list.is_empty()) { | |
| 449 work_list.RemoveLast()->Emit(this, &new_trace); | |
| 450 } | |
| 451 if (reg_exp_too_big_) return IrregexpRegExpTooBig(); | |
| 452 | |
| 453 TypedData& bytecode = TypedData::ZoneHandle(macro_assembler->GetBytecode()); | |
| 454 return RegExpEngine::CompilationResult(&bytecode, next_register_); | |
| 455 } | |
| 456 | |
| 457 | |
| 421 bool Trace::DeferredAction::Mentions(intptr_t that) { | 458 bool Trace::DeferredAction::Mentions(intptr_t that) { |
| 422 if (action_type() == ActionNode::CLEAR_CAPTURES) { | 459 if (action_type() == ActionNode::CLEAR_CAPTURES) { |
| 423 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); | 460 Interval range = static_cast<DeferredClearCaptures*>(this)->range(); |
| 424 return range.Contains(that); | 461 return range.Contains(that); |
| 425 } else { | 462 } else { |
| 426 return reg() == that; | 463 return reg() == that; |
| 427 } | 464 } |
| 428 } | 465 } |
| 429 | 466 |
| 430 | 467 |
| (...skipping 4538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4969 return; | 5006 return; |
| 4970 } | 5007 } |
| 4971 on_success()->FillInBMInfo(offset, | 5008 on_success()->FillInBMInfo(offset, |
| 4972 budget - 1, | 5009 budget - 1, |
| 4973 bm, | 5010 bm, |
| 4974 true); // Not at start after a text node. | 5011 true); // Not at start after a text node. |
| 4975 if (initial_offset == 0) set_bm_info(not_at_start, bm); | 5012 if (initial_offset == 0) set_bm_info(not_at_start, bm); |
| 4976 } | 5013 } |
| 4977 | 5014 |
| 4978 | 5015 |
| 4979 RegExpEngine::CompilationResult RegExpEngine::Compile( | 5016 RegExpEngine::CompilationResult RegExpEngine::CompileIR( |
| 4980 RegExpCompileData* data, | 5017 RegExpCompileData* data, |
| 4981 const ParsedFunction* parsed_function, | 5018 const ParsedFunction* parsed_function, |
| 4982 const ZoneGrowableArray<const ICData*>& ic_data_array) { | 5019 const ZoneGrowableArray<const ICData*>& ic_data_array) { |
| 5020 ASSERT(!FLAG_interpret_irregexp); | |
| 4983 Zone* zone = Thread::Current()->zone(); | 5021 Zone* zone = Thread::Current()->zone(); |
| 4984 | 5022 |
| 4985 const Function& function = parsed_function->function(); | 5023 const Function& function = parsed_function->function(); |
| 4986 const intptr_t specialization_cid = function.regexp_cid(); | 5024 const intptr_t specialization_cid = function.regexp_cid(); |
| 4987 const bool is_one_byte = (specialization_cid == kOneByteStringCid || | 5025 const bool is_one_byte = (specialization_cid == kOneByteStringCid || |
| 4988 specialization_cid == kExternalOneByteStringCid); | 5026 specialization_cid == kExternalOneByteStringCid); |
| 4989 JSRegExp& regexp = JSRegExp::Handle(zone, function.regexp()); | 5027 JSRegExp& regexp = JSRegExp::Handle(zone, function.regexp()); |
| 4990 const String& pattern = String::Handle(zone, regexp.pattern()); | 5028 const String& pattern = String::Handle(zone, regexp.pattern()); |
| 4991 | 5029 |
| 4992 ASSERT(!regexp.IsNull()); | 5030 ASSERT(!regexp.IsNull()); |
| 4993 ASSERT(!pattern.IsNull()); | 5031 ASSERT(!pattern.IsNull()); |
| 4994 | 5032 |
| 4995 const bool ignore_case = regexp.is_ignore_case(); | 5033 const bool ignore_case = regexp.is_ignore_case(); |
| 4996 const bool is_global = regexp.is_global(); | 5034 const bool is_global = regexp.is_global(); |
| 4997 | 5035 |
| 4998 RegExpCompiler compiler(data->capture_count, ignore_case, specialization_cid); | 5036 RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte); |
| 4999 | 5037 |
| 5000 // TODO(zerny): Frequency sampling is currently disabled because of several | 5038 // 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 | 5039 // 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. | 5040 // 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 | 5041 // Passing them to this function explicitly does not help, since we must |
| 5004 // generate exactly the same IR for both the unoptimizing and optimizing | 5042 // generate exactly the same IR for both the unoptimizing and optimizing |
| 5005 // pipelines (otherwise it gets confused when i.e. deopt id's differ). | 5043 // 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 | 5044 // An option would be to store sampling results in the regexp object, but |
| 5007 // I'm not sure the performance gains are relevant enough. | 5045 // I'm not sure the performance gains are relevant enough. |
| 5008 | 5046 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5091 pattern); | 5129 pattern); |
| 5092 | 5130 |
| 5093 if (FLAG_trace_irregexp) { | 5131 if (FLAG_trace_irregexp) { |
| 5094 macro_assembler->PrintBlocks(); | 5132 macro_assembler->PrintBlocks(); |
| 5095 } | 5133 } |
| 5096 | 5134 |
| 5097 return result; | 5135 return result; |
| 5098 } | 5136 } |
| 5099 | 5137 |
| 5100 | 5138 |
| 5139 RegExpEngine::CompilationResult RegExpEngine::CompileBytecode( | |
| 5140 RegExpCompileData* data, | |
| 5141 const JSRegExp& regexp, | |
| 5142 bool is_one_byte, | |
| 5143 Zone* zone) { | |
| 5144 ASSERT(FLAG_interpret_irregexp); | |
| 5145 const String& pattern = String::Handle(zone, regexp.pattern()); | |
| 5146 | |
| 5147 ASSERT(!regexp.IsNull()); | |
| 5148 ASSERT(!pattern.IsNull()); | |
| 5149 | |
| 5150 const bool ignore_case = regexp.is_ignore_case(); | |
| 5151 const bool is_global = regexp.is_global(); | |
| 5152 | |
| 5153 RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte); | |
| 5154 | |
| 5155 // TODO(zerny): Frequency sampling is currently disabled because of several | |
| 5156 // issues. We do not want to store subject strings in the regexp object since | |
| 5157 // they might be long and we should not prevent their garbage collection. | |
| 5158 // Passing them to this function explicitly does not help, since we must | |
| 5159 // generate exactly the same IR for both the unoptimizing and optimizing | |
| 5160 // pipelines (otherwise it gets confused when i.e. deopt id's differ). | |
| 5161 // An option would be to store sampling results in the regexp object, but | |
| 5162 // I'm not sure the performance gains are relevant enough. | |
| 5163 | |
| 5164 // Wrap the body of the regexp in capture #0. | |
| 5165 RegExpNode* captured_body = RegExpCapture::ToNode(data->tree, | |
| 5166 0, | |
| 5167 &compiler, | |
| 5168 compiler.accept()); | |
| 5169 | |
| 5170 RegExpNode* node = captured_body; | |
| 5171 bool is_end_anchored = data->tree->IsAnchoredAtEnd(); | |
| 5172 bool is_start_anchored = data->tree->IsAnchoredAtStart(); | |
| 5173 intptr_t max_length = data->tree->max_match(); | |
| 5174 if (!is_start_anchored) { | |
| 5175 // Add a .*? at the beginning, outside the body capture, unless | |
| 5176 // this expression is anchored at the beginning. | |
| 5177 RegExpNode* loop_node = | |
| 5178 RegExpQuantifier::ToNode(0, | |
| 5179 RegExpTree::kInfinity, | |
| 5180 false, | |
| 5181 new(zone) RegExpCharacterClass('*'), | |
| 5182 &compiler, | |
| 5183 captured_body, | |
| 5184 data->contains_anchor); | |
| 5185 | |
| 5186 if (data->contains_anchor) { | |
| 5187 // Unroll loop once, to take care of the case that might start | |
| 5188 // at the start of input. | |
| 5189 ChoiceNode* first_step_node = new(zone) ChoiceNode(2, zone); | |
| 5190 first_step_node->AddAlternative(GuardedAlternative(captured_body)); | |
| 5191 first_step_node->AddAlternative(GuardedAlternative( | |
| 5192 new(zone) TextNode( | |
| 5193 new(zone) RegExpCharacterClass('*'), loop_node))); | |
| 5194 node = first_step_node; | |
| 5195 } else { | |
| 5196 node = loop_node; | |
| 5197 } | |
| 5198 } | |
| 5199 if (is_one_byte) { | |
| 5200 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | |
| 5201 // Do it again to propagate the new nodes to places where they were not | |
| 5202 // put because they had not been calculated yet. | |
| 5203 if (node != NULL) { | |
| 5204 node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case); | |
| 5205 } | |
| 5206 } | |
| 5207 | |
| 5208 if (node == NULL) node = new(zone) EndNode(EndNode::BACKTRACK, zone); | |
| 5209 data->node = node; | |
| 5210 Analysis analysis(ignore_case, is_one_byte); | |
| 5211 analysis.EnsureAnalyzed(node); | |
| 5212 if (analysis.has_failed()) { | |
| 5213 const char* error_message = analysis.error_message(); | |
| 5214 return CompilationResult(error_message); | |
| 5215 } | |
| 5216 | |
| 5217 // Bytecode regexp implementation. | |
| 5218 | |
| 5219 ZoneGrowableArray<uint8_t> buffer(zone, 1024); | |
| 5220 BytecodeRegExpMacroAssembler* macro_assembler = | |
| 5221 new(zone) BytecodeRegExpMacroAssembler(&buffer, zone); | |
| 5222 | |
| 5223 // Inserted here, instead of in Assembler, because it depends on information | |
| 5224 // in the AST that isn't replicated in the Node structure. | |
| 5225 static const intptr_t kMaxBacksearchLimit = 1024; | |
| 5226 if (is_end_anchored && | |
| 5227 !is_start_anchored && | |
| 5228 max_length < kMaxBacksearchLimit) { | |
| 5229 macro_assembler->SetCurrentPositionFromEnd(max_length); | |
| 5230 } | |
| 5231 | |
| 5232 if (is_global) { | |
| 5233 macro_assembler->set_global_mode( | |
| 5234 (data->tree->min_match() > 0) | |
| 5235 ? RegExpMacroAssembler::GLOBAL_NO_ZERO_LENGTH_CHECK | |
| 5236 : RegExpMacroAssembler::GLOBAL); | |
| 5237 } | |
| 5238 | |
| 5239 RegExpEngine::CompilationResult result = | |
| 5240 compiler.Assemble(macro_assembler, | |
| 5241 node, | |
| 5242 data->capture_count, | |
| 5243 pattern); | |
| 5244 | |
| 5245 if (FLAG_trace_irregexp) { | |
| 5246 macro_assembler->PrintBlocks(); | |
| 5247 } | |
| 5248 | |
| 5249 return result; | |
| 5250 } | |
| 5251 | |
| 5252 | |
| 5101 static void CreateSpecializedFunction(Zone* zone, | 5253 static void CreateSpecializedFunction(Zone* zone, |
| 5102 const JSRegExp& regexp, | 5254 const JSRegExp& regexp, |
| 5103 intptr_t specialization_cid, | 5255 intptr_t specialization_cid, |
| 5104 const Object& owner) { | 5256 const Object& owner) { |
| 5105 const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; | 5257 const intptr_t kParamCount = RegExpMacroAssembler::kParamCount; |
| 5106 | 5258 |
| 5107 Function& fn = Function::Handle(zone, Function::New( | 5259 Function& fn = Function::Handle(zone, Function::New( |
| 5108 // Append the regexp pattern to the function name. | 5260 // Append the regexp pattern to the function name. |
| 5109 String::Handle(zone, Symbols::New( | 5261 String::Handle(zone, Symbols::New( |
| 5110 String::Handle(zone, String::Concat( | 5262 String::Handle(zone, String::Concat( |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5171 CreateSpecializedFunction(zone, regexp, kOneByteStringCid, owner); | 5323 CreateSpecializedFunction(zone, regexp, kOneByteStringCid, owner); |
| 5172 CreateSpecializedFunction(zone, regexp, kTwoByteStringCid, owner); | 5324 CreateSpecializedFunction(zone, regexp, kTwoByteStringCid, owner); |
| 5173 CreateSpecializedFunction(zone, regexp, kExternalOneByteStringCid, owner); | 5325 CreateSpecializedFunction(zone, regexp, kExternalOneByteStringCid, owner); |
| 5174 CreateSpecializedFunction(zone, regexp, kExternalTwoByteStringCid, owner); | 5326 CreateSpecializedFunction(zone, regexp, kExternalTwoByteStringCid, owner); |
| 5175 | 5327 |
| 5176 return regexp.raw(); | 5328 return regexp.raw(); |
| 5177 } | 5329 } |
| 5178 | 5330 |
| 5179 | 5331 |
| 5180 } // namespace dart | 5332 } // namespace dart |
| OLD | NEW |