Index: src/jsregexp.h |
=================================================================== |
--- src/jsregexp.h (revision 927) |
+++ src/jsregexp.h (working copy) |
@@ -346,6 +346,7 @@ |
uint32_t first_; |
ZoneList<unsigned>* remaining_; |
ZoneList<OutSet*>* successors_; |
+ friend class GenerationVariant; |
}; |
@@ -432,7 +433,7 @@ |
public: |
enum Type {UNINITIALIZED, ATOM, CHAR_CLASS}; |
TextElement() : type(UNINITIALIZED) { } |
- explicit TextElement(Type t) : type(t) { } |
+ explicit TextElement(Type t) : type(t), cp_offset(-1) { } |
static TextElement Atom(RegExpAtom* atom); |
static TextElement CharClass(RegExpCharacterClass* char_class); |
Type type; |
@@ -440,9 +441,13 @@ |
RegExpAtom* u_atom; |
RegExpCharacterClass* u_char_class; |
} data; |
+ int cp_offset; |
}; |
+class GenerationVariant; |
+ |
+ |
struct NodeInfo { |
enum TriBool { |
UNKNOWN = -1, FALSE = 0, TRUE = 1 |
@@ -607,18 +612,18 @@ |
class RegExpNode: public ZoneObject { |
public: |
+ RegExpNode() : variants_generated_(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 GoTo(RegExpCompiler* compiler); |
- Label* label(); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0; |
+ static const int kNodeIsTooComplexForGreedyLoops = -1; |
+ virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
+ Label* label() { return &label_; } |
+ static const int kMaxVariantsGenerated = 10; |
- // Until the implementation is complete we will return true for success and |
- // false for failure. |
- virtual bool Emit(RegExpCompiler* compiler) = 0; |
- |
RegExpNode* EnsureExpanded(NodeInfo* info); |
virtual RegExpNode* ExpandLocal(NodeInfo* info) = 0; |
virtual void ExpandChildren() = 0; |
@@ -630,7 +635,6 @@ |
virtual RegExpNode* PropagateForward(NodeInfo* info) = 0; |
NodeInfo* info() { return &info_; } |
- virtual bool IsBacktrack() { return false; } |
void AddSibling(RegExpNode* node) { siblings_.Add(node); } |
@@ -645,6 +649,9 @@ |
void set_siblings(SiblingList* other) { siblings_ = *other; } |
protected: |
+ enum LimitResult { DONE, FAIL, CONTINUE }; |
+ LimitResult LimitVersions(RegExpCompiler* compiler, |
+ GenerationVariant* variant); |
// Returns a sibling of this node whose interests and assumptions |
// match the ones in the given node info. If no sibling exists NULL |
@@ -663,12 +670,11 @@ |
// processed before it is on a useable state. |
virtual RegExpNode* Clone() = 0; |
- inline void Bind(RegExpMacroAssembler* macro); |
- |
private: |
Label label_; |
NodeInfo info_; |
SiblingList siblings_; |
+ int variants_generated_; |
}; |
@@ -678,7 +684,6 @@ |
: on_success_(on_success) { } |
RegExpNode* on_success() { return on_success_; } |
void set_on_success(RegExpNode* node) { on_success_ = node; } |
- virtual bool Emit(RegExpCompiler* compiler) { return false; } |
private: |
RegExpNode* on_success_; |
}; |
@@ -687,29 +692,31 @@ |
class ActionNode: public SeqRegExpNode { |
public: |
enum Type { |
- STORE_REGISTER, |
+ SET_REGISTER, |
INCREMENT_REGISTER, |
STORE_POSITION, |
- RESTORE_POSITION, |
BEGIN_SUBMATCH, |
- ESCAPE_SUBMATCH |
+ POSITIVE_SUBMATCH_SUCCESS |
}; |
- static ActionNode* StoreRegister(int reg, int val, RegExpNode* on_success); |
+ static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success); |
static ActionNode* IncrementRegister(int reg, RegExpNode* on_success); |
static ActionNode* StorePosition(int reg, RegExpNode* on_success); |
- static ActionNode* RestorePosition(int reg, RegExpNode* on_success); |
- static ActionNode* BeginSubmatch(int stack_pointer_reg, |
- int position_reg, |
- RegExpNode* on_success); |
- static ActionNode* EscapeSubmatch(int stack_pointer_reg, |
- bool and_restore_position, |
- int restore_reg, |
- RegExpNode* on_success); |
+ static ActionNode* BeginSubmatch( |
+ int stack_pointer_reg, |
+ int position_reg, |
+ RegExpNode* on_success); |
+ static ActionNode* PositiveSubmatchSuccess( |
+ int stack_pointer_reg, |
+ int restore_reg, |
+ RegExpNode* on_success); |
virtual void Accept(NodeVisitor* visitor); |
- virtual bool Emit(RegExpCompiler* compiler); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
virtual RegExpNode* ExpandLocal(NodeInfo* info); |
virtual void ExpandChildren(); |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
+ Type type() { return type_; } |
+ // TODO(erikcorry): We should allow some action nodes in greedy loops. |
+ virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; } |
virtual ActionNode* Clone() { return new ActionNode(*this); } |
private: |
@@ -740,16 +747,12 @@ |
class TextNode: public SeqRegExpNode { |
public: |
TextNode(ZoneList<TextElement>* elms, |
- RegExpNode* on_success, |
- RegExpNode* on_failure) |
+ RegExpNode* on_success) |
: SeqRegExpNode(on_success), |
- on_failure_(on_failure), |
elms_(elms) { } |
TextNode(RegExpCharacterClass* that, |
- RegExpNode* on_success, |
- RegExpNode* on_failure) |
+ RegExpNode* on_success) |
: SeqRegExpNode(on_success), |
- on_failure_(on_failure), |
elms_(new ZoneList<TextElement>(1)) { |
elms_->Add(TextElement::CharClass(that)); |
} |
@@ -757,17 +760,20 @@ |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
virtual RegExpNode* ExpandLocal(NodeInfo* info); |
virtual void ExpandChildren(); |
- RegExpNode* on_failure() { return on_failure_; } |
- virtual bool Emit(RegExpCompiler* compiler); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
ZoneList<TextElement>* elements() { return elms_; } |
void MakeCaseIndependent(); |
- virtual TextNode* Clone() { return new TextNode(*this); } |
- |
+ virtual int GreedyLoopTextLength(); |
+ virtual TextNode* Clone() { |
+ TextNode* result = new TextNode(*this); |
+ result->CalculateOffsets(); |
+ return result; |
+ } |
+ void CalculateOffsets(); |
private: |
void ExpandAtomChildren(RegExpAtom* that); |
void ExpandCharClassChildren(RegExpCharacterClass* that); |
- RegExpNode* on_failure_; |
ZoneList<TextElement>* elms_; |
}; |
@@ -776,24 +782,20 @@ |
public: |
BackReferenceNode(int start_reg, |
int end_reg, |
- RegExpNode* on_success, |
- RegExpNode* on_failure) |
+ RegExpNode* on_success) |
: SeqRegExpNode(on_success), |
- on_failure_(on_failure), |
start_reg_(start_reg), |
end_reg_(end_reg) { } |
virtual void Accept(NodeVisitor* visitor); |
- RegExpNode* on_failure() { return on_failure_; } |
int start_register() { return start_reg_; } |
int end_register() { return end_reg_; } |
- virtual bool Emit(RegExpCompiler* compiler); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
virtual RegExpNode* ExpandLocal(NodeInfo* info); |
virtual void ExpandChildren(); |
virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); } |
private: |
- RegExpNode* on_failure_; |
int start_reg_; |
int end_reg_; |
}; |
@@ -801,22 +803,37 @@ |
class EndNode: public RegExpNode { |
public: |
- enum Action { ACCEPT, BACKTRACK }; |
+ enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS }; |
explicit EndNode(Action action) : action_(action) { } |
virtual void Accept(NodeVisitor* visitor); |
- virtual bool Emit(RegExpCompiler* compiler); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
virtual RegExpNode* ExpandLocal(NodeInfo* info); |
virtual void ExpandChildren(); |
- virtual bool IsBacktrack() { return action_ == BACKTRACK; } |
- virtual bool GoTo(RegExpCompiler* compiler); |
virtual EndNode* Clone() { return new EndNode(*this); } |
+ protected: |
+ void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant); |
+ |
private: |
Action action_; |
}; |
+class NegativeSubmatchSuccess: public EndNode { |
+ public: |
+ NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg) |
+ : EndNode(NEGATIVE_SUBMATCH_SUCCESS), |
+ stack_pointer_register_(stack_pointer_reg), |
+ current_position_register_(position_reg) { } |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ |
+ private: |
+ int stack_pointer_register_; |
+ int current_position_register_; |
+}; |
+ |
+ |
class Guard: public ZoneObject { |
public: |
enum Relation { LT, GEQ }; |
@@ -851,17 +868,15 @@ |
class ChoiceNode: public RegExpNode { |
public: |
- explicit ChoiceNode(int expected_size, RegExpNode* on_failure) |
- : on_failure_(on_failure), |
- alternatives_(new ZoneList<GuardedAlternative>(expected_size)), |
+ explicit ChoiceNode(int expected_size) |
+ : alternatives_(new ZoneList<GuardedAlternative>(expected_size)), |
table_(NULL), |
being_calculated_(false) { } |
virtual void Accept(NodeVisitor* visitor); |
void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); } |
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; } |
DispatchTable* GetTable(bool ignore_case); |
- RegExpNode* on_failure() { return on_failure_; } |
- virtual bool Emit(RegExpCompiler* compiler); |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
virtual RegExpNode* PropagateForward(NodeInfo* info); |
virtual RegExpNode* ExpandLocal(NodeInfo* info); |
virtual void ExpandChildren(); |
@@ -870,19 +885,128 @@ |
bool being_calculated() { return being_calculated_; } |
void set_being_calculated(bool b) { being_calculated_ = b; } |
+ protected: |
+ int GreedyLoopTextLength(GuardedAlternative *alternative); |
+ ZoneList<GuardedAlternative>* alternatives_; |
+ |
private: |
friend class DispatchTableConstructor; |
friend class Analysis; |
void GenerateGuard(RegExpMacroAssembler* macro_assembler, |
Guard *guard, |
- Label* on_failure); |
- RegExpNode* on_failure_; |
- ZoneList<GuardedAlternative>* alternatives_; |
+ GenerationVariant* variant); |
DispatchTable* table_; |
bool being_calculated_; |
}; |
+class LoopChoiceNode: public ChoiceNode { |
+ public: |
+ explicit LoopChoiceNode(int expected_size) : ChoiceNode(expected_size) { } |
+ virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant); |
+ virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); } |
+}; |
+ |
+ |
+// 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 { |
Christian Plesner Hansen
2008/12/08 08:54:19
Not a fan of this name though I can't think of any
|
+ public: |
+ class DeferredAction { |
+ public: |
+ DeferredAction(ActionNode::Type type, int reg) |
+ : type_(type), reg_(reg), next_(NULL) { } |
+ DeferredAction* next() { return next_; } |
+ int reg() { return reg_; } |
+ ActionNode::Type type() { return type_; } |
+ private: |
+ ActionNode::Type type_; |
+ int reg_; |
+ DeferredAction* next_; |
+ friend class GenerationVariant; |
+ }; |
+ |
+ class DeferredCapture: public DeferredAction { |
+ public: |
+ DeferredCapture(int reg, GenerationVariant* variant) |
+ : DeferredAction(ActionNode::STORE_POSITION, reg), |
+ cp_offset_(variant->cp_offset()) { } |
+ int cp_offset() { return cp_offset_; } |
+ private: |
+ int cp_offset_; |
+ void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; } |
+ }; |
+ |
+ class DeferredSetRegister :public DeferredAction { |
+ public: |
+ DeferredSetRegister(int reg, int value) |
+ : DeferredAction(ActionNode::SET_REGISTER, reg), |
+ value_(value) { } |
+ int value() { return value_; } |
+ private: |
+ int value_; |
+ }; |
+ |
+ class DeferredIncrementRegister: public DeferredAction { |
+ public: |
+ explicit DeferredIncrementRegister(int reg) |
+ : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { } |
+ }; |
+ |
+ explicit GenerationVariant(Label* backtrack) |
+ : cp_offset_(0), |
+ actions_(NULL), |
+ backtrack_(backtrack), |
+ stop_node_(NULL), |
+ loop_label_(NULL) { } |
+ GenerationVariant() |
+ : cp_offset_(0), |
+ actions_(NULL), |
+ backtrack_(NULL), |
+ stop_node_(NULL), |
+ loop_label_(NULL) { } |
+ bool Flush(RegExpCompiler* compiler, RegExpNode* successor); |
+ int cp_offset() { return cp_offset_; } |
+ DeferredAction* actions() { return actions_; } |
+ bool is_trivial() { |
+ return backtrack_ == NULL && actions_ == NULL && cp_offset_ == 0; |
+ } |
+ Label* backtrack() { return backtrack_; } |
+ Label* loop_label() { return loop_label_; } |
+ RegExpNode* stop_node() { return stop_node_; } |
+ // These set methods should be used only on new GenerationVariants - the |
+ // intention is that GenerationVariants are immutable after creation. |
+ void add_action(DeferredAction* new_action) { |
+ ASSERT(new_action->next_ == NULL); |
+ new_action->next_ = actions_; |
+ actions_ = new_action; |
+ } |
+ void set_cp_offset(int new_cp_offset) { |
+ ASSERT(new_cp_offset >= cp_offset_); |
+ cp_offset_ = new_cp_offset; |
+ } |
+ void set_backtrack(Label* backtrack) { backtrack_ = backtrack; } |
+ void set_stop_node(RegExpNode* node) { stop_node_ = node; } |
+ void set_loop_label(Label* label) { loop_label_ = label; } |
+ bool mentions_reg(int reg); |
+ private: |
+ int FindAffectedRegisters(OutSet* affected_registers); |
+ void PerformDeferredActions(RegExpMacroAssembler* macro, |
+ int max_register, |
+ OutSet& affected_registers); |
+ void RestoreAffectedRegisters(RegExpMacroAssembler* macro, |
+ int max_register, |
+ OutSet& affected_registers); |
+ void PushAffectedRegisters(RegExpMacroAssembler* macro, |
+ int max_register, |
+ OutSet& affected_registers); |
+ int cp_offset_; |
+ DeferredAction* actions_; |
+ Label* backtrack_; |
+ RegExpNode* stop_node_; |
+ Label* loop_label_; |
+}; |
class NodeVisitor { |
public: |
virtual ~NodeVisitor() { } |
@@ -956,7 +1080,8 @@ |
static Handle<FixedArray> Compile(RegExpParseResult* input, |
RegExpNode** node_return, |
bool ignore_case, |
- bool multiline); |
+ bool multiline, |
+ Handle<String> pattern); |
static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); |
}; |