Index: src/jsregexp.h |
=================================================================== |
--- src/jsregexp.h (revision 1074) |
+++ src/jsregexp.h (working copy) |
@@ -349,7 +349,7 @@ |
uint32_t first_; |
ZoneList<unsigned>* remaining_; |
ZoneList<OutSet*>* successors_; |
- friend class GenerationVariant; |
+ friend class Trace; |
}; |
@@ -449,7 +449,7 @@ |
}; |
-class GenerationVariant; |
+class Trace; |
struct NodeInfo { |
@@ -583,13 +583,13 @@ |
class RegExpNode: public ZoneObject { |
public: |
- RegExpNode() : variants_generated_(0) { } |
+ RegExpNode() : trace_count_(0) { } |
virtual ~RegExpNode(); |
virtual void Accept(NodeVisitor* visitor) = 0; |
// Generates a goto to this node or actually generates the code at this point. |
// Until the implementation is complete we will return true for success and |
// false for failure. |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0; |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace) = 0; |
// How many characters must this node consume at a minimum in order to |
// succeed. |
virtual int EatsAtLeast(int recursion_depth) = 0; |
@@ -597,7 +597,7 @@ |
// Falls through on certain failure, jumps to the label on possible success. |
// If the node cannot make a quick check it does nothing and returns false. |
bool EmitQuickCheck(RegExpCompiler* compiler, |
- GenerationVariant* variant, |
+ Trace* trace, |
bool preload_has_checked_bounds, |
Label* on_possible_success, |
QuickCheckDetails* details_return, |
@@ -612,7 +612,12 @@ |
static const int kNodeIsTooComplexForGreedyLoops = -1; |
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
Label* label() { return &label_; } |
- static const int kMaxVariantsGenerated = 10; |
+ // If non-generic code is generated for a node (ie the node is not at the |
+ // start of the trace) then it cannot be reused. This variable sets a limit |
+ // on how often we allow that to happen before we insist on starting a new |
+ // trace and generating generic code for a node that can be reused by flushing |
+ // the deferred actions in the current trace and generating a goto. |
+ static const int kMaxCopiesCodeGenerated = 10; |
// Propagates the given interest information forward. When seeing |
// \bfoo for instance, the \b is implemented by propagating forward |
@@ -636,8 +641,7 @@ |
protected: |
enum LimitResult { DONE, FAIL, CONTINUE }; |
- LimitResult LimitVersions(RegExpCompiler* compiler, |
- GenerationVariant* variant); |
+ LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace); |
// Returns a sibling of this node whose interests and assumptions |
// match the ones in the given node info. If no sibling exists NULL |
@@ -660,7 +664,12 @@ |
Label label_; |
NodeInfo info_; |
SiblingList siblings_; |
- int variants_generated_; |
+ // This variable keeps track of how many times code has been generated for |
+ // this node (in different traces). We don't keep track of where the |
+ // generated code is located unless the code is generated at the start of |
+ // a trace, in which case it is generic and can be reused by flushing the |
+ // deferred operations in the current trace and generating a goto. |
+ int trace_count_; |
}; |
@@ -728,7 +737,7 @@ |
int repetition_limit, |
RegExpNode* on_success); |
virtual void Accept(NodeVisitor* visitor); |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth); |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
RegExpCompiler* compiler, |
@@ -789,7 +798,7 @@ |
} |
virtual void Accept(NodeVisitor* visitor); |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth); |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
RegExpCompiler* compiler, |
@@ -814,7 +823,7 @@ |
void TextEmitPass(RegExpCompiler* compiler, |
TextEmitPassType pass, |
bool preloaded, |
- GenerationVariant* variant, |
+ Trace* trace, |
bool first_element_checked, |
int* checked_up_to); |
int Length(); |
@@ -833,7 +842,7 @@ |
virtual void Accept(NodeVisitor* visitor); |
int start_register() { return start_reg_; } |
int end_register() { return end_reg_; } |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth) { return 0; } |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
RegExpCompiler* compiler, |
@@ -854,7 +863,7 @@ |
enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; |
explicit EndNode(Action action) : action_(action) { } |
virtual void Accept(NodeVisitor* visitor); |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth) { return 0; } |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
RegExpCompiler* compiler, |
@@ -866,7 +875,7 @@ |
virtual EndNode* Clone() { return new EndNode(*this); } |
protected: |
- void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant); |
+ void EmitInfoChecks(RegExpMacroAssembler* macro, Trace* trace); |
private: |
Action action_; |
@@ -879,7 +888,7 @@ |
: EndNode(NEGATIVE_SUBMATCH_SUCCESS), |
stack_pointer_register_(stack_pointer_reg), |
current_position_register_(position_reg) { } |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
private: |
int stack_pointer_register_; |
@@ -932,7 +941,7 @@ |
void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } |
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } |
DispatchTable* GetTable(bool ignore_case); |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth); |
int EatsAtLeastHelper(int recursion_depth, RegExpNode* ignore_this_node); |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
@@ -953,10 +962,10 @@ |
friend class Analysis; |
void GenerateGuard(RegExpMacroAssembler* macro_assembler, |
Guard *guard, |
- GenerationVariant* variant); |
+ Trace* trace); |
int CalculatePreloadCharacters(RegExpCompiler* compiler); |
bool EmitOutOfLineContinuation(RegExpCompiler* compiler, |
- GenerationVariant* variant, |
+ Trace* trace, |
GuardedAlternative alternative, |
AlternativeGeneration* alt_gen, |
int preload_characters, |
@@ -975,7 +984,7 @@ |
body_can_be_zero_length_(body_can_be_zero_length) { } |
void AddLoopAlternative(GuardedAlternative alt); |
void AddContinueAlternative(GuardedAlternative alt); |
- virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual bool Emit(RegExpCompiler* compiler, Trace* trace); |
virtual int EatsAtLeast(int recursion_depth); // Returns 0. |
virtual void GetQuickCheckDetails(QuickCheckDetails* details, |
RegExpCompiler* compiler, |
@@ -1002,8 +1011,16 @@ |
// There are many ways to generate code for a node. This class encapsulates |
// the current way we should be generating. In other words it encapsulates |
-// the current state of the code generator. |
-class GenerationVariant { |
+// the current state of the code generator. The effect of this is that we |
+// generate code for paths that the matcher can take through the regular |
+// expression. A given node in the regexp can be code-generated several times |
+// as it can be part of several traces. For example for the regexp: |
+// /foo(bar|ip)baz/ the code to match baz will be generated twice, once as part |
+// of the foo-bar-baz trace and once as part of the foo-ip-baz trace. The code |
+// to match foo is generated only once (the traces have a common prefix). The |
+// code to store the capture is deferred and generated (twice) after the places |
+// where baz has been matched. |
+class Trace { |
public: |
class DeferredAction { |
public: |
@@ -1017,14 +1034,14 @@ |
ActionNode::Type type_; |
int reg_; |
DeferredAction* next_; |
- friend class GenerationVariant; |
+ friend class Trace; |
}; |
class DeferredCapture: public DeferredAction { |
public: |
- DeferredCapture(int reg, GenerationVariant* variant) |
+ DeferredCapture(int reg, Trace* trace) |
: DeferredAction(ActionNode::STORE_POSITION, reg), |
- cp_offset_(variant->cp_offset()) { } |
+ cp_offset_(trace->cp_offset()) { } |
int cp_offset() { return cp_offset_; } |
private: |
int cp_offset_; |
@@ -1057,7 +1074,7 @@ |
: DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } |
}; |
- GenerationVariant() |
+ Trace() |
: cp_offset_(0), |
actions_(NULL), |
backtrack_(NULL), |
@@ -1065,9 +1082,22 @@ |
loop_label_(NULL), |
characters_preloaded_(0), |
bound_checked_up_to_(0) { } |
+ // End the trace. This involves flushing the deferred actions in the trace and |
+ // pushing a backtrack location onto the backtrack stack. Once this is done we |
+ // can start a new trace or go to one that has already been generated. |
bool Flush(RegExpCompiler* compiler, RegExpNode* successor); |
int cp_offset() { return cp_offset_; } |
DeferredAction* actions() { return actions_; } |
+ // A trivial trace is one that has no deferred actions or other state that |
+ // affects the assumptions used when generating code. There is no recorded |
+ // backtrack location in a trivial trace, so with a trivial trace we will |
+ // generate code that, on a failure to match, gets the backtrack location |
+ // from the backtrack stack rather than using a direct jump instruction. We |
+ // always start code generation with a trivial trace and non-trivial traces |
+ // are created as we emit code for nodes or add to the list of deferred |
+ // actions in the trace. The location of the code generated for a node using |
+ // a trivial trace is recorded in a label in the node so that gotos can be |
+ // generated to that code. |
bool is_trivial() { |
return backtrack_ == NULL && |
actions_ == NULL && |
@@ -1087,9 +1117,8 @@ |
// register and stores the offset in the out-parameter. Otherwise |
// returns false. |
bool GetStoredPosition(int reg, int* cp_offset); |
- // These set methods and AdvanceVariant should be used only on new |
- // GenerationVariants - the intention is that GenerationVariants are |
- // immutable after creation. |
+ // These set methods and AdvanceCurrentPositionInTrace should be used only on |
+ // new traces - the intention is that traces are immutable after creation. |
void add_action(DeferredAction* new_action) { |
ASSERT(new_action->next_ == NULL); |
new_action->next_ = actions_; |
@@ -1105,7 +1134,7 @@ |
} |
void clear_quick_check_performed() { |
} |
- void AdvanceVariant(int by, bool ascii); |
+ void AdvanceCurrentPositionInTrace(int by, bool ascii); |
private: |
int FindAffectedRegisters(OutSet* affected_registers); |
void PerformDeferredActions(RegExpMacroAssembler* macro, |