V8 Project
v8::internal::ChoiceNode Class Reference

#include <jsregexp.h>

+ Inheritance diagram for v8::internal::ChoiceNode:
+ Collaboration diagram for v8::internal::ChoiceNode:

Public Member Functions

 ChoiceNode (int expected_size, Zone *zone)
 
virtual void Accept (NodeVisitor *visitor)
 
void AddAlternative (GuardedAlternative node)
 
ZoneList< GuardedAlternative > * alternatives ()
 
DispatchTableGetTable (bool ignore_case)
 
virtual void Emit (RegExpCompiler *compiler, Trace *trace)
 
virtual int EatsAtLeast (int still_to_find, int budget, bool not_at_start)
 
int EatsAtLeastHelper (int still_to_find, int budget, RegExpNode *ignore_this_node, bool not_at_start)
 
virtual void GetQuickCheckDetails (QuickCheckDetails *details, RegExpCompiler *compiler, int characters_filled_in, bool not_at_start)
 
virtual void FillInBMInfo (int offset, int budget, BoyerMooreLookahead *bm, bool not_at_start)
 
bool being_calculated ()
 
bool not_at_start ()
 
void set_not_at_start ()
 
void set_being_calculated (bool b)
 
virtual bool try_to_emit_quick_check_for_alternative (bool is_first)
 
virtual RegExpNodeFilterOneByte (int depth, bool ignore_case)
 
- Public Member Functions inherited from v8::internal::RegExpNode
 RegExpNode (Zone *zone)
 
virtual ~RegExpNode ()
 
bool EmitQuickCheck (RegExpCompiler *compiler, Trace *bounds_check_trace, Trace *trace, bool preload_has_checked_bounds, Label *on_possible_success, QuickCheckDetails *details_return, bool fall_through_on_failure)
 
virtual int GreedyLoopTextLength ()
 
virtual RegExpNodeGetSuccessorOfOmnivorousTextNode (RegExpCompiler *compiler)
 
RegExpNodereplacement ()
 
RegExpNodeset_replacement (RegExpNode *replacement)
 
void SaveBMInfo (BoyerMooreLookahead *bm, bool not_at_start, int offset)
 
Label * label ()
 
NodeInfoinfo ()
 
BoyerMooreLookaheadbm_info (bool not_at_start)
 
Zonezone () const
 
- Public Member Functions inherited from v8::internal::ZoneObject
 INLINE (void *operator new(size_t size, Zone *zone))
 
void operator delete (void *, size_t)
 
void operator delete (void *pointer, Zone *zone)
 

Protected Member Functions

int GreedyLoopTextLengthForAlternative (GuardedAlternative *alternative)
 
- Protected Member Functions inherited from v8::internal::RegExpNode
LimitResult LimitVersions (RegExpCompiler *compiler, Trace *trace)
 
void set_bm_info (bool not_at_start, BoyerMooreLookahead *bm)
 

Protected Attributes

ZoneList< GuardedAlternative > * alternatives_
 
- Protected Attributes inherited from v8::internal::RegExpNode
RegExpNodereplacement_
 

Private Member Functions

void GenerateGuard (RegExpMacroAssembler *macro_assembler, Guard *guard, Trace *trace)
 
int CalculatePreloadCharacters (RegExpCompiler *compiler, int eats_at_least)
 
void EmitOutOfLineContinuation (RegExpCompiler *compiler, Trace *trace, GuardedAlternative alternative, AlternativeGeneration *alt_gen, int preload_characters, bool next_expects_preload)
 
void SetUpPreLoad (RegExpCompiler *compiler, Trace *current_trace, PreloadState *preloads)
 
void AssertGuardsMentionRegisters (Trace *trace)
 
int EmitOptimizedUnanchoredSearch (RegExpCompiler *compiler, Trace *trace)
 
TraceEmitGreedyLoop (RegExpCompiler *compiler, Trace *trace, AlternativeGenerationList *alt_gens, PreloadState *preloads, GreedyLoopState *greedy_loop_state, int text_length)
 
void EmitChoices (RegExpCompiler *compiler, AlternativeGenerationList *alt_gens, int first_choice, Trace *trace, PreloadState *preloads)
 

Private Attributes

DispatchTabletable_
 
bool not_at_start_
 
bool being_calculated_
 

Friends

class DispatchTableConstructor
 
class Analysis
 

Additional Inherited Members

- Static Public Attributes inherited from v8::internal::RegExpNode
static const int kNodeIsTooComplexForGreedyLoops = -1
 
static const int kRecursionBudget = 200
 
static const int kMaxCopiesCodeGenerated = 10
 
- Protected Types inherited from v8::internal::RegExpNode
enum  LimitResult { DONE , CONTINUE }
 

Detailed Description

Definition at line 1051 of file jsregexp.h.

Constructor & Destructor Documentation

◆ ChoiceNode()

v8::internal::ChoiceNode::ChoiceNode ( int  expected_size,
Zone zone 
)
inlineexplicit

Definition at line 1053 of file jsregexp.h.

1054  : RegExpNode(zone),
1055  alternatives_(new(zone)
1056  ZoneList<GuardedAlternative>(expected_size, zone)),
1057  table_(NULL),
1058  not_at_start_(false),
1059  being_calculated_(false) { }
ZoneList< GuardedAlternative > * alternatives_
Definition: jsregexp.h:1092
DispatchTable * table_
Definition: jsregexp.h:1123
Zone * zone() const
Definition: jsregexp.h:668
RegExpNode(Zone *zone)
Definition: jsregexp.h:573
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL

Member Function Documentation

◆ Accept()

virtual void v8::internal::ChoiceNode::Accept ( NodeVisitor visitor)
virtual

◆ AddAlternative()

void v8::internal::ChoiceNode::AddAlternative ( GuardedAlternative  node)
inline

Definition at line 1061 of file jsregexp.h.

1061  {
1062  alternatives()->Add(node, zone());
1063  }
ZoneList< GuardedAlternative > * alternatives()
Definition: jsregexp.h:1064

References alternatives(), and v8::internal::RegExpNode::zone().

Referenced by v8::internal::LoopChoiceNode::AddAlternative(), v8::internal::RegExpEngine::Compile(), and v8::internal::NegativeLookaheadChoiceNode::NegativeLookaheadChoiceNode().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alternatives()

ZoneList<GuardedAlternative>* v8::internal::ChoiceNode::alternatives ( )
inline

Definition at line 1064 of file jsregexp.h.

1064 { return alternatives_; }

References alternatives_.

Referenced by AddAlternative(), v8::internal::DispatchTableConstructor::BuildTable(), FillInBMInfo(), and v8::internal::Analysis::VisitLoopChoice().

+ Here is the caller graph for this function:

◆ AssertGuardsMentionRegisters()

void v8::internal::ChoiceNode::AssertGuardsMentionRegisters ( Trace trace)
private

Definition at line 3900 of file jsregexp.cc.

3900  {
3901 #ifdef DEBUG
3902  int choice_count = alternatives_->length();
3903  for (int i = 0; i < choice_count - 1; i++) {
3904  GuardedAlternative alternative = alternatives_->at(i);
3905  ZoneList<Guard*>* guards = alternative.guards();
3906  int guard_count = (guards == NULL) ? 0 : guards->length();
3907  for (int j = 0; j < guard_count; j++) {
3908  DCHECK(!trace->mentions_reg(guards->at(j)->reg()));
3909  }
3910  }
3911 #endif
3912 }
#define DCHECK(condition)
Definition: logging.h:205

References alternatives_, v8::internal::List< T, AllocationPolicy >::at(), DCHECK, v8::internal::GuardedAlternative::guards(), v8::internal::Trace::mentions_reg(), and NULL.

Referenced by Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ being_calculated()

bool v8::internal::ChoiceNode::being_calculated ( )
inline

Definition at line 1081 of file jsregexp.h.

1081 { return being_calculated_; }

References being_calculated_.

◆ CalculatePreloadCharacters()

int v8::internal::ChoiceNode::CalculatePreloadCharacters ( RegExpCompiler compiler,
int  eats_at_least 
)
private

Definition at line 3506 of file jsregexp.cc.

3507  {
3508  int preload_characters = Min(4, eats_at_least);
3509  if (compiler->macro_assembler()->CanReadUnaligned()) {
3510  bool one_byte = compiler->one_byte();
3511  if (one_byte) {
3512  if (preload_characters > 4) preload_characters = 4;
3513  // We can't preload 3 characters because there is no machine instruction
3514  // to do that. We can't just load 4 because we could be reading
3515  // beyond the end of the string, which could cause a memory fault.
3516  if (preload_characters == 3) preload_characters = 2;
3517  } else {
3518  if (preload_characters > 2) preload_characters = 2;
3519  }
3520  } else {
3521  if (preload_characters > 1) preload_characters = 1;
3522  }
3523  return preload_characters;
3524 }
static LifetimePosition Min(LifetimePosition a, LifetimePosition b)

References v8::internal::RegExpMacroAssembler::CanReadUnaligned(), v8::internal::RegExpCompiler::macro_assembler(), v8::internal::Min(), and v8::internal::RegExpCompiler::one_byte().

Referenced by SetUpPreLoad().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ EatsAtLeast()

int v8::internal::ChoiceNode::EatsAtLeast ( int  still_to_find,
int  budget,
bool  not_at_start 
)
virtual

Implements v8::internal::RegExpNode.

Reimplemented in v8::internal::LoopChoiceNode, and v8::internal::NegativeLookaheadChoiceNode.

Definition at line 2400 of file jsregexp.cc.

2402  {
2403  return EatsAtLeastHelper(still_to_find,
2404  budget,
2405  NULL,
2406  not_at_start);
2407 }
int EatsAtLeastHelper(int still_to_find, int budget, RegExpNode *ignore_this_node, bool not_at_start)
Definition: jsregexp.cc:2370

References NULL.

Referenced by EmitOptimizedUnanchoredSearch(), and SetUpPreLoad().

+ Here is the caller graph for this function:

◆ EatsAtLeastHelper()

int v8::internal::ChoiceNode::EatsAtLeastHelper ( int  still_to_find,
int  budget,
RegExpNode ignore_this_node,
bool  not_at_start 
)

Definition at line 2370 of file jsregexp.cc.

2373  {
2374  if (budget <= 0) return 0;
2375  int min = 100;
2376  int choice_count = alternatives_->length();
2377  budget = (budget - 1) / choice_count;
2378  for (int i = 0; i < choice_count; i++) {
2379  RegExpNode* node = alternatives_->at(i).node();
2380  if (node == ignore_this_node) continue;
2381  int node_eats_at_least =
2382  node->EatsAtLeast(still_to_find, budget, not_at_start);
2383  if (node_eats_at_least < min) min = node_eats_at_least;
2384  if (min == 0) return 0;
2385  }
2386  return min;
2387 }
static int min(int a, int b)
Definition: liveedit.cc:273

References v8::internal::RegExpNode::EatsAtLeast(), and v8::internal::min().

+ Here is the call graph for this function:

◆ Emit()

void v8::internal::ChoiceNode::Emit ( RegExpCompiler compiler,
Trace trace 
)
virtual

Implements v8::internal::RegExpNode.

Reimplemented in v8::internal::LoopChoiceNode.

Definition at line 3933 of file jsregexp.cc.

3933  {
3934  int choice_count = alternatives_->length();
3935 
3937 
3938  LimitResult limit_result = LimitVersions(compiler, trace);
3939  if (limit_result == DONE) return;
3940  DCHECK(limit_result == CONTINUE);
3941 
3942  // For loop nodes we already flushed (see LoopChoiceNode::Emit), but for
3943  // other choice nodes we only flush if we are out of code size budget.
3944  if (trace->flush_budget() == 0 && trace->actions() != NULL) {
3945  trace->Flush(compiler, this);
3946  return;
3947  }
3948 
3949  RecursionCheck rc(compiler);
3950 
3951  PreloadState preload;
3952  preload.init();
3953  GreedyLoopState greedy_loop_state(not_at_start());
3954 
3955  int text_length = GreedyLoopTextLengthForAlternative(&alternatives_->at(0));
3956  AlternativeGenerationList alt_gens(choice_count, zone());
3957 
3958  if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
3959  trace = EmitGreedyLoop(compiler,
3960  trace,
3961  &alt_gens,
3962  &preload,
3963  &greedy_loop_state,
3964  text_length);
3965  } else {
3966  // TODO(erikcorry): Delete this. We don't need this label, but it makes us
3967  // match the traces produced pre-cleanup.
3968  Label second_choice;
3969  compiler->macro_assembler()->Bind(&second_choice);
3970 
3971  preload.eats_at_least_ = EmitOptimizedUnanchoredSearch(compiler, trace);
3972 
3973  EmitChoices(compiler,
3974  &alt_gens,
3975  0,
3976  trace,
3977  &preload);
3978  }
3979 
3980  // At this point we need to generate slow checks for the alternatives where
3981  // the quick check was inlined. We can recognize these because the associated
3982  // label was bound.
3983  int new_flush_budget = trace->flush_budget() / choice_count;
3984  for (int i = 0; i < choice_count; i++) {
3985  AlternativeGeneration* alt_gen = alt_gens.at(i);
3986  Trace new_trace(*trace);
3987  // If there are actions to be flushed we have to limit how many times
3988  // they are flushed. Take the budget of the parent trace and distribute
3989  // it fairly amongst the children.
3990  if (new_trace.actions() != NULL) {
3991  new_trace.set_flush_budget(new_flush_budget);
3992  }
3993  bool next_expects_preload =
3994  i == choice_count - 1 ? false : alt_gens.at(i + 1)->expects_preload;
3995  EmitOutOfLineContinuation(compiler,
3996  &new_trace,
3997  alternatives_->at(i),
3998  alt_gen,
3999  preload.preload_characters_,
4000  next_expects_preload);
4001  }
4002 }
int EmitOptimizedUnanchoredSearch(RegExpCompiler *compiler, Trace *trace)
Definition: jsregexp.cc:4052
int GreedyLoopTextLengthForAlternative(GuardedAlternative *alternative)
Definition: jsregexp.cc:3446
Trace * EmitGreedyLoop(RegExpCompiler *compiler, Trace *trace, AlternativeGenerationList *alt_gens, PreloadState *preloads, GreedyLoopState *greedy_loop_state, int text_length)
Definition: jsregexp.cc:4005
void EmitChoices(RegExpCompiler *compiler, AlternativeGenerationList *alt_gens, int first_choice, Trace *trace, PreloadState *preloads)
Definition: jsregexp.cc:4103
void EmitOutOfLineContinuation(RegExpCompiler *compiler, Trace *trace, GuardedAlternative alternative, AlternativeGeneration *alt_gen, int preload_characters, bool next_expects_preload)
Definition: jsregexp.cc:4192
void AssertGuardsMentionRegisters(Trace *trace)
Definition: jsregexp.cc:3900
LimitResult LimitVersions(RegExpCompiler *compiler, Trace *trace)
Definition: jsregexp.cc:2229
static const int kNodeIsTooComplexForGreedyLoops
Definition: jsregexp.h:607
static void Trace(const char *msg,...)
Definition: scheduler.cc:21

References v8::internal::Trace::actions(), alternatives_, AssertGuardsMentionRegisters(), v8::internal::AlternativeGenerationList::at(), v8::internal::RegExpMacroAssembler::Bind(), v8::internal::RegExpNode::CONTINUE, DCHECK, v8::internal::RegExpNode::DONE, v8::internal::PreloadState::eats_at_least_, EmitChoices(), EmitGreedyLoop(), EmitOptimizedUnanchoredSearch(), EmitOutOfLineContinuation(), v8::internal::AlternativeGeneration::expects_preload, false, v8::internal::Trace::Flush(), v8::internal::Trace::flush_budget(), GreedyLoopTextLengthForAlternative(), v8::internal::PreloadState::init(), v8::internal::RegExpNode::kNodeIsTooComplexForGreedyLoops, v8::internal::RegExpNode::LimitVersions(), v8::internal::RegExpCompiler::macro_assembler(), not_at_start(), NULL, v8::internal::PreloadState::preload_characters_, v8::internal::Trace::set_flush_budget(), and v8::internal::RegExpNode::zone().

Referenced by v8::internal::LoopChoiceNode::Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ EmitChoices()

void v8::internal::ChoiceNode::EmitChoices ( RegExpCompiler compiler,
AlternativeGenerationList alt_gens,
int  first_choice,
Trace trace,
PreloadState preloads 
)
private

Definition at line 4103 of file jsregexp.cc.

4107  {
4108  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4109  SetUpPreLoad(compiler, trace, preload);
4110 
4111  // For now we just call all choices one after the other. The idea ultimately
4112  // is to use the Dispatch table to try only the relevant ones.
4113  int choice_count = alternatives_->length();
4114 
4115  int new_flush_budget = trace->flush_budget() / choice_count;
4116 
4117  for (int i = first_choice; i < choice_count; i++) {
4118  bool is_last = i == choice_count - 1;
4119  bool fall_through_on_failure = !is_last;
4120  GuardedAlternative alternative = alternatives_->at(i);
4121  AlternativeGeneration* alt_gen = alt_gens->at(i);
4122  alt_gen->quick_check_details.set_characters(preload->preload_characters_);
4123  ZoneList<Guard*>* guards = alternative.guards();
4124  int guard_count = (guards == NULL) ? 0 : guards->length();
4125  Trace new_trace(*trace);
4126  new_trace.set_characters_preloaded(preload->preload_is_current_ ?
4127  preload->preload_characters_ :
4128  0);
4129  if (preload->preload_has_checked_bounds_) {
4130  new_trace.set_bound_checked_up_to(preload->preload_characters_);
4131  }
4132  new_trace.quick_check_performed()->Clear();
4133  if (not_at_start_) new_trace.set_at_start(Trace::FALSE_VALUE);
4134  if (!is_last) {
4135  new_trace.set_backtrack(&alt_gen->after);
4136  }
4137  alt_gen->expects_preload = preload->preload_is_current_;
4138  bool generate_full_check_inline = false;
4139  if (FLAG_regexp_optimization &&
4141  alternative.node()->EmitQuickCheck(compiler,
4142  trace,
4143  &new_trace,
4144  preload->preload_has_checked_bounds_,
4145  &alt_gen->possible_success,
4146  &alt_gen->quick_check_details,
4147  fall_through_on_failure)) {
4148  // Quick check was generated for this choice.
4149  preload->preload_is_current_ = true;
4150  preload->preload_has_checked_bounds_ = true;
4151  // If we generated the quick check to fall through on possible success,
4152  // we now need to generate the full check inline.
4153  if (!fall_through_on_failure) {
4154  macro_assembler->Bind(&alt_gen->possible_success);
4155  new_trace.set_quick_check_performed(&alt_gen->quick_check_details);
4156  new_trace.set_characters_preloaded(preload->preload_characters_);
4157  new_trace.set_bound_checked_up_to(preload->preload_characters_);
4158  generate_full_check_inline = true;
4159  }
4160  } else if (alt_gen->quick_check_details.cannot_match()) {
4161  if (!fall_through_on_failure) {
4162  macro_assembler->GoTo(trace->backtrack());
4163  }
4164  continue;
4165  } else {
4166  // No quick check was generated. Put the full code here.
4167  // If this is not the first choice then there could be slow checks from
4168  // previous cases that go here when they fail. There's no reason to
4169  // insist that they preload characters since the slow check we are about
4170  // to generate probably can't use it.
4171  if (i != first_choice) {
4172  alt_gen->expects_preload = false;
4173  new_trace.InvalidateCurrentCharacter();
4174  }
4175  generate_full_check_inline = true;
4176  }
4177  if (generate_full_check_inline) {
4178  if (new_trace.actions() != NULL) {
4179  new_trace.set_flush_budget(new_flush_budget);
4180  }
4181  for (int j = 0; j < guard_count; j++) {
4182  GenerateGuard(macro_assembler, guards->at(j), &new_trace);
4183  }
4184  alternative.node()->Emit(compiler, &new_trace);
4185  preload->preload_is_current_ = false;
4186  }
4187  macro_assembler->Bind(&alt_gen->after);
4188  }
4189 }
virtual bool try_to_emit_quick_check_for_alternative(bool is_first)
Definition: jsregexp.h:1085
void SetUpPreLoad(RegExpCompiler *compiler, Trace *current_trace, PreloadState *preloads)
Definition: jsregexp.cc:3915
void GenerateGuard(RegExpMacroAssembler *macro_assembler, Guard *guard, Trace *trace)
Definition: jsregexp.cc:1568

References v8::internal::Trace::actions(), v8::internal::AlternativeGeneration::after, alternatives_, v8::internal::AlternativeGenerationList::at(), v8::internal::List< T, AllocationPolicy >::at(), v8::internal::Trace::backtrack(), v8::internal::RegExpMacroAssembler::Bind(), v8::internal::QuickCheckDetails::cannot_match(), v8::internal::QuickCheckDetails::Clear(), v8::internal::RegExpNode::Emit(), v8::internal::RegExpNode::EmitQuickCheck(), v8::internal::AlternativeGeneration::expects_preload, v8::internal::Trace::FALSE_VALUE, v8::internal::Trace::flush_budget(), GenerateGuard(), v8::internal::RegExpMacroAssembler::GoTo(), v8::internal::GuardedAlternative::guards(), v8::internal::Trace::InvalidateCurrentCharacter(), v8::internal::RegExpCompiler::macro_assembler(), v8::internal::GuardedAlternative::node(), not_at_start_, NULL, v8::internal::AlternativeGeneration::possible_success, v8::internal::PreloadState::preload_characters_, v8::internal::PreloadState::preload_has_checked_bounds_, v8::internal::PreloadState::preload_is_current_, v8::internal::AlternativeGeneration::quick_check_details, v8::internal::Trace::quick_check_performed(), v8::internal::Trace::set_at_start(), v8::internal::Trace::set_backtrack(), v8::internal::Trace::set_bound_checked_up_to(), v8::internal::QuickCheckDetails::set_characters(), v8::internal::Trace::set_characters_preloaded(), v8::internal::Trace::set_flush_budget(), v8::internal::Trace::set_quick_check_performed(), SetUpPreLoad(), and try_to_emit_quick_check_for_alternative().

Referenced by Emit(), and EmitGreedyLoop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ EmitGreedyLoop()

Trace * v8::internal::ChoiceNode::EmitGreedyLoop ( RegExpCompiler compiler,
Trace trace,
AlternativeGenerationList alt_gens,
PreloadState preloads,
GreedyLoopState greedy_loop_state,
int  text_length 
)
private

Definition at line 4005 of file jsregexp.cc.

4010  {
4011  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4012  // Here we have special handling for greedy loops containing only text nodes
4013  // and other simple nodes. These are handled by pushing the current
4014  // position on the stack and then incrementing the current position each
4015  // time around the switch. On backtrack we decrement the current position
4016  // and check it against the pushed value. This avoids pushing backtrack
4017  // information for each iteration of the loop, which could take up a lot of
4018  // space.
4019  DCHECK(trace->stop_node() == NULL);
4020  macro_assembler->PushCurrentPosition();
4021  Label greedy_match_failed;
4022  Trace greedy_match_trace;
4023  if (not_at_start()) greedy_match_trace.set_at_start(false);
4024  greedy_match_trace.set_backtrack(&greedy_match_failed);
4025  Label loop_label;
4026  macro_assembler->Bind(&loop_label);
4027  greedy_match_trace.set_stop_node(this);
4028  greedy_match_trace.set_loop_label(&loop_label);
4029  alternatives_->at(0).node()->Emit(compiler, &greedy_match_trace);
4030  macro_assembler->Bind(&greedy_match_failed);
4031 
4032  Label second_choice; // For use in greedy matches.
4033  macro_assembler->Bind(&second_choice);
4034 
4035  Trace* new_trace = greedy_loop_state->counter_backtrack_trace();
4036 
4037  EmitChoices(compiler,
4038  alt_gens,
4039  1,
4040  new_trace,
4041  preload);
4042 
4043  macro_assembler->Bind(greedy_loop_state->label());
4044  // If we have unwound to the bottom then backtrack.
4045  macro_assembler->CheckGreedyLoop(trace->backtrack());
4046  // Otherwise try the second priority at an earlier position.
4047  macro_assembler->AdvanceCurrentPosition(-text_length);
4048  macro_assembler->GoTo(&second_choice);
4049  return new_trace;
4050 }

References v8::internal::RegExpMacroAssembler::AdvanceCurrentPosition(), alternatives_, v8::internal::Trace::backtrack(), v8::internal::RegExpMacroAssembler::Bind(), v8::internal::RegExpMacroAssembler::CheckGreedyLoop(), v8::internal::GreedyLoopState::counter_backtrack_trace(), DCHECK, EmitChoices(), v8::internal::RegExpMacroAssembler::GoTo(), v8::internal::GreedyLoopState::label(), v8::internal::RegExpCompiler::macro_assembler(), not_at_start(), NULL, v8::internal::RegExpMacroAssembler::PushCurrentPosition(), v8::internal::Trace::set_at_start(), v8::internal::Trace::set_backtrack(), v8::internal::Trace::set_loop_label(), v8::internal::Trace::set_stop_node(), and v8::internal::Trace::stop_node().

Referenced by Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ EmitOptimizedUnanchoredSearch()

int v8::internal::ChoiceNode::EmitOptimizedUnanchoredSearch ( RegExpCompiler compiler,
Trace trace 
)
private

Definition at line 4052 of file jsregexp.cc.

4053  {
4054  int eats_at_least = PreloadState::kEatsAtLeastNotYetInitialized;
4055  if (alternatives_->length() != 2) return eats_at_least;
4056 
4057  GuardedAlternative alt1 = alternatives_->at(1);
4058  if (alt1.guards() != NULL && alt1.guards()->length() != 0) {
4059  return eats_at_least;
4060  }
4061  RegExpNode* eats_anything_node = alt1.node();
4062  if (eats_anything_node->GetSuccessorOfOmnivorousTextNode(compiler) != this) {
4063  return eats_at_least;
4064  }
4065 
4066  // Really we should be creating a new trace when we execute this function,
4067  // but there is no need, because the code it generates cannot backtrack, and
4068  // we always arrive here with a trivial trace (since it's the entry to a
4069  // loop. That also implies that there are no preloaded characters, which is
4070  // good, because it means we won't be violating any assumptions by
4071  // overwriting those characters with new load instructions.
4072  DCHECK(trace->is_trivial());
4073 
4074  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4075  // At this point we know that we are at a non-greedy loop that will eat
4076  // any character one at a time. Any non-anchored regexp has such a
4077  // loop prepended to it in order to find where it starts. We look for
4078  // a pattern of the form ...abc... where we can look 6 characters ahead
4079  // and step forwards 3 if the character is not one of abc. Abc need
4080  // not be atoms, they can be any reasonably limited character class or
4081  // small alternation.
4082  BoyerMooreLookahead* bm = bm_info(false);
4083  if (bm == NULL) {
4084  eats_at_least = Min(kMaxLookaheadForBoyerMoore,
4087  false));
4088  if (eats_at_least >= 1) {
4089  bm = new(zone()) BoyerMooreLookahead(eats_at_least,
4090  compiler,
4091  zone());
4092  GuardedAlternative alt0 = alternatives_->at(0);
4093  alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, false);
4094  }
4095  }
4096  if (bm != NULL) {
4097  bm->EmitSkipInstructions(macro_assembler);
4098  }
4099  return eats_at_least;
4100 }
virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start)
Definition: jsregexp.cc:2400
BoyerMooreLookahead * bm_info(bool not_at_start)
Definition: jsregexp.h:664
static const int kRecursionBudget
Definition: jsregexp.h:621
const int kMaxLookaheadForBoyerMoore
Definition: jsregexp.cc:124
static const int kEatsAtLeastNotYetInitialized
Definition: jsregexp.h:1530

References alternatives_, v8::internal::RegExpNode::bm_info(), DCHECK, EatsAtLeast(), v8::internal::BoyerMooreLookahead::EmitSkipInstructions(), v8::internal::RegExpNode::FillInBMInfo(), v8::internal::RegExpNode::GetSuccessorOfOmnivorousTextNode(), v8::internal::GuardedAlternative::guards(), v8::internal::Trace::is_trivial(), v8::internal::PreloadState::kEatsAtLeastNotYetInitialized, v8::internal::kMaxLookaheadForBoyerMoore, v8::internal::RegExpNode::kRecursionBudget, v8::internal::RegExpCompiler::macro_assembler(), v8::internal::Min(), v8::internal::GuardedAlternative::node(), NULL, and v8::internal::RegExpNode::zone().

Referenced by Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ EmitOutOfLineContinuation()

void v8::internal::ChoiceNode::EmitOutOfLineContinuation ( RegExpCompiler compiler,
Trace trace,
GuardedAlternative  alternative,
AlternativeGeneration alt_gen,
int  preload_characters,
bool  next_expects_preload 
)
private

Definition at line 4192 of file jsregexp.cc.

4197  {
4198  if (!alt_gen->possible_success.is_linked()) return;
4199 
4200  RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
4201  macro_assembler->Bind(&alt_gen->possible_success);
4202  Trace out_of_line_trace(*trace);
4203  out_of_line_trace.set_characters_preloaded(preload_characters);
4204  out_of_line_trace.set_quick_check_performed(&alt_gen->quick_check_details);
4205  if (not_at_start_) out_of_line_trace.set_at_start(Trace::FALSE_VALUE);
4206  ZoneList<Guard*>* guards = alternative.guards();
4207  int guard_count = (guards == NULL) ? 0 : guards->length();
4208  if (next_expects_preload) {
4209  Label reload_current_char;
4210  out_of_line_trace.set_backtrack(&reload_current_char);
4211  for (int j = 0; j < guard_count; j++) {
4212  GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace);
4213  }
4214  alternative.node()->Emit(compiler, &out_of_line_trace);
4215  macro_assembler->Bind(&reload_current_char);
4216  // Reload the current character, since the next quick check expects that.
4217  // We don't need to check bounds here because we only get into this
4218  // code through a quick check which already did the checked load.
4219  macro_assembler->LoadCurrentCharacter(trace->cp_offset(),
4220  NULL,
4221  false,
4222  preload_characters);
4223  macro_assembler->GoTo(&(alt_gen->after));
4224  } else {
4225  out_of_line_trace.set_backtrack(&(alt_gen->after));
4226  for (int j = 0; j < guard_count; j++) {
4227  GenerateGuard(macro_assembler, guards->at(j), &out_of_line_trace);
4228  }
4229  alternative.node()->Emit(compiler, &out_of_line_trace);
4230  }
4231 }

References v8::internal::AlternativeGeneration::after, v8::internal::List< T, AllocationPolicy >::at(), v8::internal::RegExpMacroAssembler::Bind(), v8::internal::Trace::cp_offset(), v8::internal::RegExpNode::Emit(), v8::internal::Trace::FALSE_VALUE, GenerateGuard(), v8::internal::RegExpMacroAssembler::GoTo(), v8::internal::GuardedAlternative::guards(), v8::internal::RegExpMacroAssembler::LoadCurrentCharacter(), v8::internal::RegExpCompiler::macro_assembler(), v8::internal::GuardedAlternative::node(), not_at_start_, NULL, v8::internal::AlternativeGeneration::possible_success, v8::internal::AlternativeGeneration::quick_check_details, v8::internal::Trace::set_at_start(), v8::internal::Trace::set_backtrack(), v8::internal::Trace::set_characters_preloaded(), and v8::internal::Trace::set_quick_check_performed().

Referenced by Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FillInBMInfo()

void v8::internal::ChoiceNode::FillInBMInfo ( int  offset,
int  budget,
BoyerMooreLookahead bm,
bool  not_at_start 
)
virtual

Reimplemented from v8::internal::RegExpNode.

Reimplemented in v8::internal::LoopChoiceNode, and v8::internal::NegativeLookaheadChoiceNode.

Definition at line 5836 of file jsregexp.cc.

5839  {
5840  ZoneList<GuardedAlternative>* alts = alternatives();
5841  budget = (budget - 1) / alts->length();
5842  for (int i = 0; i < alts->length(); i++) {
5843  GuardedAlternative& alt = alts->at(i);
5844  if (alt.guards() != NULL && alt.guards()->length() != 0) {
5845  bm->SetRest(offset); // Give up trying to fill in info.
5846  SaveBMInfo(bm, not_at_start, offset);
5847  return;
5848  }
5849  alt.node()->FillInBMInfo(offset, budget, bm, not_at_start);
5850  }
5851  SaveBMInfo(bm, not_at_start, offset);
5852 }
void SaveBMInfo(BoyerMooreLookahead *bm, bool not_at_start, int offset)
Definition: jsregexp.h:650

References alternatives(), v8::internal::List< T, AllocationPolicy >::at(), v8::internal::RegExpNode::FillInBMInfo(), v8::internal::GuardedAlternative::guards(), v8::internal::GuardedAlternative::node(), not_at_start(), NULL, v8::internal::RegExpNode::SaveBMInfo(), and v8::internal::BoyerMooreLookahead::SetRest().

Referenced by v8::internal::LoopChoiceNode::FillInBMInfo().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FilterOneByte()

RegExpNode * v8::internal::ChoiceNode::FilterOneByte ( int  depth,
bool  ignore_case 
)
virtual

Reimplemented from v8::internal::RegExpNode.

Reimplemented in v8::internal::LoopChoiceNode, and v8::internal::NegativeLookaheadChoiceNode.

Definition at line 2861 of file jsregexp.cc.

2861  {
2862  if (info()->replacement_calculated) return replacement();
2863  if (depth < 0) return this;
2864  if (info()->visited) return this;
2865  VisitMarker marker(info());
2866  int choice_count = alternatives_->length();
2867 
2868  for (int i = 0; i < choice_count; i++) {
2869  GuardedAlternative alternative = alternatives_->at(i);
2870  if (alternative.guards() != NULL && alternative.guards()->length() != 0) {
2871  set_replacement(this);
2872  return this;
2873  }
2874  }
2875 
2876  int surviving = 0;
2877  RegExpNode* survivor = NULL;
2878  for (int i = 0; i < choice_count; i++) {
2879  GuardedAlternative alternative = alternatives_->at(i);
2881  alternative.node()->FilterOneByte(depth - 1, ignore_case);
2882  DCHECK(replacement != this); // No missing EMPTY_MATCH_CHECK.
2883  if (replacement != NULL) {
2884  alternatives_->at(i).set_node(replacement);
2885  surviving++;
2886  survivor = replacement;
2887  }
2888  }
2889  if (surviving < 2) return set_replacement(survivor);
2890 
2891  set_replacement(this);
2892  if (surviving == choice_count) {
2893  return this;
2894  }
2895  // Only some of the nodes survived the filtering. We need to rebuild the
2896  // alternatives list.
2897  ZoneList<GuardedAlternative>* new_alternatives =
2898  new(zone()) ZoneList<GuardedAlternative>(surviving, zone());
2899  for (int i = 0; i < choice_count; i++) {
2901  alternatives_->at(i).node()->FilterOneByte(depth - 1, ignore_case);
2902  if (replacement != NULL) {
2903  alternatives_->at(i).set_node(replacement);
2904  new_alternatives->Add(alternatives_->at(i), zone());
2905  }
2906  }
2907  alternatives_ = new_alternatives;
2908  return this;
2909 }
RegExpNode * replacement()
Definition: jsregexp.h:636
RegExpNode * set_replacement(RegExpNode *replacement)
Definition: jsregexp.h:640
virtual RegExpNode * FilterOneByte(int depth, bool ignore_case)
Definition: jsregexp.h:632

References v8::internal::List< T, AllocationPolicy >::Add(), DCHECK, v8::internal::RegExpNode::FilterOneByte(), v8::internal::GuardedAlternative::guards(), v8::internal::GuardedAlternative::node(), and NULL.

Referenced by v8::internal::LoopChoiceNode::FilterOneByte().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GenerateGuard()

void v8::internal::ChoiceNode::GenerateGuard ( RegExpMacroAssembler macro_assembler,
Guard guard,
Trace trace 
)
private

Definition at line 1568 of file jsregexp.cc.

1570  {
1571  switch (guard->op()) {
1572  case Guard::LT:
1573  DCHECK(!trace->mentions_reg(guard->reg()));
1574  macro_assembler->IfRegisterGE(guard->reg(),
1575  guard->value(),
1576  trace->backtrack());
1577  break;
1578  case Guard::GEQ:
1579  DCHECK(!trace->mentions_reg(guard->reg()));
1580  macro_assembler->IfRegisterLT(guard->reg(),
1581  guard->value(),
1582  trace->backtrack());
1583  break;
1584  }
1585 }

References v8::internal::Trace::backtrack(), DCHECK, v8::internal::Guard::GEQ, v8::internal::RegExpMacroAssembler::IfRegisterGE(), v8::internal::RegExpMacroAssembler::IfRegisterLT(), v8::internal::Guard::LT, v8::internal::Trace::mentions_reg(), v8::internal::Guard::op(), v8::internal::Guard::reg(), and v8::internal::Guard::value().

Referenced by EmitChoices(), and EmitOutOfLineContinuation().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GetQuickCheckDetails()

void v8::internal::ChoiceNode::GetQuickCheckDetails ( QuickCheckDetails details,
RegExpCompiler compiler,
int  characters_filled_in,
bool  not_at_start 
)
virtual

Implements v8::internal::RegExpNode.

Reimplemented in v8::internal::LoopChoiceNode, and v8::internal::NegativeLookaheadChoiceNode.

Definition at line 2962 of file jsregexp.cc.

2965  {
2967  int choice_count = alternatives_->length();
2968  DCHECK(choice_count > 0);
2969  alternatives_->at(0).node()->GetQuickCheckDetails(details,
2970  compiler,
2971  characters_filled_in,
2972  not_at_start);
2973  for (int i = 1; i < choice_count; i++) {
2974  QuickCheckDetails new_details(details->characters());
2975  RegExpNode* node = alternatives_->at(i).node();
2976  node->GetQuickCheckDetails(&new_details, compiler,
2977  characters_filled_in,
2978  not_at_start);
2979  // Here we merge the quick match details of the two branches.
2980  details->Merge(&new_details, characters_filled_in);
2981  }
2982 }

References v8::internal::QuickCheckDetails::characters(), DCHECK, v8::internal::RegExpNode::GetQuickCheckDetails(), and v8::internal::QuickCheckDetails::Merge().

Referenced by v8::internal::LoopChoiceNode::GetQuickCheckDetails().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GetTable()

DispatchTable * v8::internal::ChoiceNode::GetTable ( bool  ignore_case)

Definition at line 936 of file jsregexp.cc.

936  {
937  if (table_ == NULL) {
938  table_ = new(zone()) DispatchTable(zone());
939  DispatchTableConstructor cons(table_, ignore_case, zone());
940  cons.BuildTable(this);
941  }
942  return table_;
943 }
friend class DispatchTableConstructor
Definition: jsregexp.h:1095

References v8::internal::DispatchTableConstructor::BuildTable(), and NULL.

+ Here is the call graph for this function:

◆ GreedyLoopTextLengthForAlternative()

int v8::internal::ChoiceNode::GreedyLoopTextLengthForAlternative ( GuardedAlternative alternative)
protected

Definition at line 3446 of file jsregexp.cc.

3447  {
3448  int length = 0;
3449  RegExpNode* node = alternative->node();
3450  // Later we will generate code for all these text nodes using recursion
3451  // so we have to limit the max number.
3452  int recursion_depth = 0;
3453  while (node != this) {
3454  if (recursion_depth++ > RegExpCompiler::kMaxRecursion) {
3456  }
3457  int node_length = node->GreedyLoopTextLength();
3458  if (node_length == kNodeIsTooComplexForGreedyLoops) {
3460  }
3461  length += node_length;
3462  SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node);
3463  node = seq_node->on_success();
3464  }
3465  return length;
3466 }
static const int kMaxRecursion
Definition: jsregexp.cc:1020

References v8::internal::RegExpNode::GreedyLoopTextLength(), v8::internal::RegExpCompiler::kMaxRecursion, v8::internal::GuardedAlternative::node(), and v8::internal::SeqRegExpNode::on_success().

Referenced by Emit().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ not_at_start()

bool v8::internal::ChoiceNode::not_at_start ( )
inline

Definition at line 1082 of file jsregexp.h.

1082 { return not_at_start_; }

References not_at_start_.

Referenced by Emit(), EmitGreedyLoop(), FillInBMInfo(), and v8::internal::NegativeLookaheadChoiceNode::FillInBMInfo().

+ Here is the caller graph for this function:

◆ set_being_calculated()

void v8::internal::ChoiceNode::set_being_calculated ( bool  b)
inline

Definition at line 1084 of file jsregexp.h.

1084 { being_calculated_ = b; }

References being_calculated_.

Referenced by v8::internal::DispatchTableConstructor::BuildTable().

+ Here is the caller graph for this function:

◆ set_not_at_start()

void v8::internal::ChoiceNode::set_not_at_start ( )
inline

Definition at line 1083 of file jsregexp.h.

1083 { not_at_start_ = true; }

References not_at_start_.

◆ SetUpPreLoad()

void v8::internal::ChoiceNode::SetUpPreLoad ( RegExpCompiler compiler,
Trace current_trace,
PreloadState preloads 
)
private

Definition at line 3915 of file jsregexp.cc.

3917  {
3918  if (state->eats_at_least_ == PreloadState::kEatsAtLeastNotYetInitialized) {
3919  // Save some time by looking at most one machine word ahead.
3920  state->eats_at_least_ =
3921  EatsAtLeast(compiler->one_byte() ? 4 : 2, kRecursionBudget,
3922  current_trace->at_start() == Trace::FALSE_VALUE);
3923  }
3924  state->preload_characters_ =
3925  CalculatePreloadCharacters(compiler, state->eats_at_least_);
3926 
3927  state->preload_is_current_ =
3928  (current_trace->characters_preloaded() == state->preload_characters_);
3929  state->preload_has_checked_bounds_ = state->preload_is_current_;
3930 }
int CalculatePreloadCharacters(RegExpCompiler *compiler, int eats_at_least)
Definition: jsregexp.cc:3506

References v8::internal::Trace::at_start(), CalculatePreloadCharacters(), v8::internal::Trace::characters_preloaded(), v8::internal::PreloadState::eats_at_least_, EatsAtLeast(), v8::internal::Trace::FALSE_VALUE, v8::internal::PreloadState::kEatsAtLeastNotYetInitialized, v8::internal::RegExpNode::kRecursionBudget, v8::internal::RegExpCompiler::one_byte(), v8::internal::PreloadState::preload_characters_, v8::internal::PreloadState::preload_has_checked_bounds_, and v8::internal::PreloadState::preload_is_current_.

Referenced by EmitChoices().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ try_to_emit_quick_check_for_alternative()

virtual bool v8::internal::ChoiceNode::try_to_emit_quick_check_for_alternative ( bool  is_first)
inlinevirtual

Reimplemented in v8::internal::NegativeLookaheadChoiceNode.

Definition at line 1085 of file jsregexp.h.

1085  {
1086  return true;
1087  }

Referenced by EmitChoices().

+ Here is the caller graph for this function:

Friends And Related Function Documentation

◆ Analysis

friend class Analysis
friend

Definition at line 1096 of file jsregexp.h.

◆ DispatchTableConstructor

friend class DispatchTableConstructor
friend

Definition at line 1095 of file jsregexp.h.

Member Data Documentation

◆ alternatives_

◆ being_calculated_

bool v8::internal::ChoiceNode::being_calculated_
private

Definition at line 1127 of file jsregexp.h.

Referenced by being_calculated(), and set_being_calculated().

◆ not_at_start_

bool v8::internal::ChoiceNode::not_at_start_
private

◆ table_

DispatchTable* v8::internal::ChoiceNode::table_
private

Definition at line 1123 of file jsregexp.h.


The documentation for this class was generated from the following files: