| Index: src/jsregexp.cc
|
| ===================================================================
|
| --- src/jsregexp.cc (revision 738)
|
| +++ src/jsregexp.cc (working copy)
|
| @@ -40,6 +40,7 @@
|
| #include "compilation-cache.h"
|
| #include "string-stream.h"
|
| #include "parser.h"
|
| +#include "regexp-macro-assembler.h"
|
|
|
| // Including pcre.h undefines DEBUG to avoid getting debug output from
|
| // the JSCRE implementation. Make sure to redefine it in debug mode
|
| @@ -632,13 +633,15 @@
|
| // New regular expression engine
|
|
|
|
|
| -class ExecutionState;
|
| +class RegExpCompiler;
|
| +class DotPrinter;
|
|
|
|
|
| class RegExpCompiler {
|
| public:
|
| explicit RegExpCompiler(int capture_count)
|
| - : next_register_(2 * capture_count) { }
|
| + : next_register_(2 * capture_count),
|
| + work_list_(NULL) { }
|
|
|
| RegExpNode* Compile(RegExpTree* tree,
|
| RegExpNode* on_success,
|
| @@ -646,11 +649,48 @@
|
|
|
| int AllocateRegister() { return next_register_++; }
|
|
|
| + Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler,
|
| + RegExpNode* start);
|
| +
|
| + inline void AddWork(RegExpNode* node) { work_list_->Add(node); }
|
| +
|
| + static const int kImplementationOffset = 0;
|
| + static const int kNumberOfRegistersOffset = 0;
|
| + static const int kCodeOffset = 1;
|
| +
|
| + RegExpMacroAssembler* macro_assembler() {
|
| + return macro_assembler_;
|
| + }
|
| private:
|
| int next_register_;
|
| + List<RegExpNode*>* work_list_;
|
| + RegExpMacroAssembler* macro_assembler_;
|
| };
|
|
|
|
|
| +Handle<FixedArray> RegExpCompiler::Assemble(
|
| + RegExpMacroAssembler* macro_assembler,
|
| + RegExpNode* start) {
|
| + macro_assembler_ = macro_assembler;
|
| + List <RegExpNode*> work_list(0);
|
| + work_list_ = &work_list;
|
| + start->GoTo(this);
|
| + while (!work_list.is_empty()) {
|
| + work_list.RemoveLast()->Emit(this);
|
| + }
|
| + Handle<FixedArray> array = Factory::NewFixedArray(3);
|
| + array->set(kImplementationOffset,
|
| + Smi::FromInt(macro_assembler->Implementation()),
|
| + SKIP_WRITE_BARRIER);
|
| + array->set(kNumberOfRegistersOffset,
|
| + Smi::FromInt(next_register_),
|
| + SKIP_WRITE_BARRIER);
|
| + Handle<Object> code = macro_assembler->GetCode();
|
| + work_list_ = NULL;
|
| + return array;
|
| +}
|
| +
|
| +
|
| #define FOR_EACH_NODE_TYPE(VISIT) \
|
| VISIT(End) \
|
| VISIT(Atom) \
|
| @@ -660,18 +700,26 @@
|
| VISIT(CharacterClass)
|
|
|
|
|
| -class RegExpNode: public ZoneObject {
|
| - public:
|
| - virtual ~RegExpNode() { }
|
| - virtual void Accept(NodeVisitor* visitor) = 0;
|
| -};
|
| +void RegExpNode::GoTo(RegExpCompiler* compiler) {
|
| + if (label.is_bound()) {
|
| + compiler->macro_assembler()->GoTo(&label);
|
| + } else {
|
| + Emit(compiler);
|
| + }
|
| +}
|
|
|
|
|
| +void RegExpNode::EmitAddress(RegExpCompiler* compiler) {
|
| + compiler->macro_assembler()->EmitOrLink(&label);
|
| +}
|
| +
|
| +
|
| class SeqRegExpNode: public RegExpNode {
|
| public:
|
| explicit SeqRegExpNode(RegExpNode* on_success)
|
| : on_success_(on_success) { }
|
| RegExpNode* on_success() { return on_success_; }
|
| + virtual void Emit(RegExpCompiler* compiler) { UNREACHABLE(); }
|
| private:
|
| RegExpNode* on_success_;
|
| };
|
| @@ -683,6 +731,7 @@
|
| virtual void Accept(NodeVisitor* visitor);
|
| static EndNode* GetAccept() { return &kAccept; }
|
| static EndNode* GetBacktrack() { return &kBacktrack; }
|
| + virtual void Emit(RegExpCompiler* compiler) { UNREACHABLE(); }
|
| private:
|
| explicit EndNode(Action action) : action_(action) { }
|
| Action action_;
|
| @@ -706,6 +755,7 @@
|
| virtual void Accept(NodeVisitor* visitor);
|
| Vector<const uc16> data() { return data_; }
|
| RegExpNode* on_failure() { return on_failure_; }
|
| + virtual void Emit(RegExpCompiler* compiler) { UNREACHABLE(); }
|
| private:
|
| RegExpNode* on_failure_;
|
| Vector<const uc16> data_;
|
| @@ -726,6 +776,7 @@
|
| RegExpNode* on_failure() { return on_failure_; }
|
| int start_register() { return start_reg_; }
|
| int end_register() { return end_reg_; }
|
| + virtual void Emit(RegExpCompiler* compiler) { UNREACHABLE(); }
|
| private:
|
| RegExpNode* on_failure_;
|
| int start_reg_;
|
| @@ -742,11 +793,12 @@
|
| : SeqRegExpNode(on_success),
|
| on_failure_(on_failure),
|
| ranges_(ranges),
|
| - is_negated_(is_negated ){ }
|
| + is_negated_(is_negated ) { }
|
| virtual void Accept(NodeVisitor* visitor);
|
| ZoneList<CharacterRange>* ranges() { return ranges_; }
|
| bool is_negated() { return is_negated_; }
|
| RegExpNode* on_failure() { return on_failure_; }
|
| + virtual void Emit(RegExpCompiler* compiler) { UNREACHABLE(); }
|
| static void AddInverseToTable(List<CharacterRange> ranges,
|
| DispatchTable* table,
|
| int index);
|
| @@ -804,6 +856,7 @@
|
| ZoneList<GuardedAlternative>* choices() { return choices_; }
|
| DispatchTable* table() { return &table_; }
|
| RegExpNode* on_failure() { return on_failure_; }
|
| + virtual void Emit(RegExpCompiler* compiler);
|
| bool visited() { return visited_; }
|
| void set_visited(bool value) { visited_ = value; }
|
| private:
|
| @@ -833,7 +886,8 @@
|
| static ActionNode* EscapeSubmatch(RegExpNode* on_success);
|
| static ActionNode* EndSubmatch(RegExpNode* on_success);
|
| virtual void Accept(NodeVisitor* visitor);
|
| - Type type;
|
| + virtual void Emit(RegExpCompiler* compiler);
|
| + private:
|
| union {
|
| struct {
|
| int reg;
|
| @@ -845,11 +899,12 @@
|
| struct {
|
| int reg;
|
| } u_position_register;
|
| - } data;
|
| - private:
|
| - ActionNode(Type _type, RegExpNode* on_success)
|
| + } data_;
|
| + ActionNode(Type type, RegExpNode* on_success)
|
| : SeqRegExpNode(on_success),
|
| - type(_type) { }
|
| + type_(type) { }
|
| + Type type_;
|
| + friend class DotPrinter;
|
| };
|
|
|
|
|
| @@ -857,29 +912,29 @@
|
| int val,
|
| RegExpNode* on_success) {
|
| ActionNode* result = new ActionNode(STORE_REGISTER, on_success);
|
| - result->data.u_store_register.reg = reg;
|
| - result->data.u_store_register.value = val;
|
| + result->data_.u_store_register.reg = reg;
|
| + result->data_.u_store_register.value = val;
|
| return result;
|
| }
|
|
|
|
|
| ActionNode* ActionNode::IncrementRegister(int reg, RegExpNode* on_success) {
|
| ActionNode* result = new ActionNode(INCREMENT_REGISTER, on_success);
|
| - result->data.u_increment_register.reg = reg;
|
| + result->data_.u_increment_register.reg = reg;
|
| return result;
|
| }
|
|
|
|
|
| ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
|
| ActionNode* result = new ActionNode(STORE_POSITION, on_success);
|
| - result->data.u_position_register.reg = reg;
|
| + result->data_.u_position_register.reg = reg;
|
| return result;
|
| }
|
|
|
|
|
| ActionNode* ActionNode::RestorePosition(int reg, RegExpNode* on_success) {
|
| ActionNode* result = new ActionNode(RESTORE_POSITION, on_success);
|
| - result->data.u_position_register.reg = reg;
|
| + result->data_.u_position_register.reg = reg;
|
| return result;
|
| }
|
|
|
| @@ -918,6 +973,48 @@
|
|
|
|
|
| // -------------------------------------------------------------------
|
| +// Emit code.
|
| +
|
| +
|
| +void ChoiceNode::Emit(RegExpCompiler* compiler) {
|
| + // TODO(erikcorry): Implement this.
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void ActionNode::Emit(RegExpCompiler* compiler) {
|
| + RegExpMacroAssembler* macro = compiler->macro_assembler();
|
| + switch (type_) {
|
| + case STORE_REGISTER:
|
| + macro->SetRegister(data_.u_store_register.reg,
|
| + data_.u_store_register.value);
|
| + break;
|
| + case INCREMENT_REGISTER:
|
| + macro->AdvanceRegister(data_.u_increment_register.reg, 1);
|
| + break;
|
| + case STORE_POSITION:
|
| + macro->PushCurrentPosition();
|
| + break;
|
| + case RESTORE_POSITION:
|
| + macro->PopCurrentPosition();
|
| + break;
|
| + case BEGIN_SUBMATCH:
|
| + // TODO(erikcorry): Implement this.
|
| + UNREACHABLE();
|
| + break;
|
| + case ESCAPE_SUBMATCH:
|
| + // TODO(erikcorry): Implement this.
|
| + UNREACHABLE();
|
| + break;
|
| + case END_SUBMATCH:
|
| + // TODO(erikcorry): Implement this.
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +
|
| +// -------------------------------------------------------------------
|
| // Dot/dotty output
|
|
|
|
|
| @@ -1048,23 +1145,23 @@
|
|
|
| void DotPrinter::VisitAction(ActionNode* that) {
|
| stream()->Add(" n%p [", that);
|
| - switch (that->type) {
|
| + switch (that->type_) {
|
| case ActionNode::STORE_REGISTER:
|
| stream()->Add("label=\"$%i:=%i\", shape=box",
|
| - that->data.u_store_register.reg,
|
| - that->data.u_store_register.value);
|
| + that->data_.u_store_register.reg,
|
| + that->data_.u_store_register.value);
|
| break;
|
| case ActionNode::INCREMENT_REGISTER:
|
| stream()->Add("label=\"$%i++\", shape=box",
|
| - that->data.u_increment_register.reg);
|
| + that->data_.u_increment_register.reg);
|
| break;
|
| case ActionNode::STORE_POSITION:
|
| stream()->Add("label=\"$%i:=$pos\", shape=box",
|
| - that->data.u_position_register.reg);
|
| + that->data_.u_position_register.reg);
|
| break;
|
| case ActionNode::RESTORE_POSITION:
|
| stream()->Add("label=\"$pos:=$%i\", shape=box",
|
| - that->data.u_position_register.reg);
|
| + that->data_.u_position_register.reg);
|
| break;
|
| case ActionNode::BEGIN_SUBMATCH:
|
| stream()->Add("label=\"begin\", shape=septagon");
|
| @@ -1084,7 +1181,7 @@
|
|
|
| class DispatchTableDumper {
|
| public:
|
| - DispatchTableDumper(StringStream* stream) : stream_(stream) { }
|
| + explicit DispatchTableDumper(StringStream* stream) : stream_(stream) { }
|
| void Call(uc16 key, DispatchTable::Entry entry);
|
| StringStream* stream() { return stream_; }
|
| private:
|
| @@ -1098,8 +1195,11 @@
|
| bool first = true;
|
| for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
|
| if (set->Get(i)) {
|
| - if (first) first = false;
|
| - else stream()->Add(", ");
|
| + if (first) {
|
| + first = false;
|
| + } else {
|
| + stream()->Add(", ");
|
| + }
|
| stream()->Add("%i", i);
|
| }
|
| }
|
| @@ -1121,7 +1221,7 @@
|
| }
|
|
|
|
|
| -#endif // DEBUG
|
| +#endif // DEBUG
|
|
|
|
|
| // -------------------------------------------------------------------
|
| @@ -1528,7 +1628,7 @@
|
|
|
| class Analysis: public NodeVisitor {
|
| public:
|
| - Analysis(RegExpCompiler* compiler)
|
| + explicit Analysis(RegExpCompiler* compiler)
|
| : compiler_(compiler),
|
| table_(NULL),
|
| choice_index_(-1) { }
|
| @@ -1541,7 +1641,7 @@
|
| FOR_EACH_NODE_TYPE(DECLARE_VISIT)
|
| #undef DECLARE_VISIT
|
| protected:
|
| - Analysis(Analysis* prev) { *this = *prev; }
|
| + explicit Analysis(Analysis* prev) { *this = *prev; }
|
| RegExpCompiler* compiler_;
|
| DispatchTable *table_;
|
| int choice_index_;
|
| @@ -1554,7 +1654,7 @@
|
| // which doesn't allow its fields to be changed.
|
| class AnalysisBuilder: public Analysis {
|
| public:
|
| - AnalysisBuilder(Analysis* prev) : Analysis(prev) { }
|
| + explicit AnalysisBuilder(Analysis* prev) : Analysis(prev) { }
|
| void set_table(DispatchTable* value) { table_ = value; }
|
| void set_choice_index(int value) { choice_index_ = value; }
|
| };
|
| @@ -1567,7 +1667,7 @@
|
|
|
| class AddDispatchRange {
|
| public:
|
| - AddDispatchRange(Analysis* analysis) : analysis_(analysis) { }
|
| + explicit AddDispatchRange(Analysis* analysis) : analysis_(analysis) { }
|
| void Call(uc32 from, DispatchTable::Entry entry);
|
| private:
|
| Analysis* analysis_;
|
| @@ -1652,4 +1752,8 @@
|
| }
|
|
|
|
|
| +RegExpMacroAssembler::~RegExpMacroAssembler() {
|
| +}
|
| +
|
| +
|
| }} // namespace v8::internal
|
|
|