Revert of Experimental support for RegExp lookbehind. (patchset #18 id:340001 of https://codereview.chromium.org/1418963009/ )

Reason for revert:
gc stress breaks due to string_start_minus_one not being set correctly.

Original issue's description:
> Experimental support for RegExp lookbehind.
>
> R=erikcorry@chromium.org, littledan@chromium.org
> BUG=v8:4545
> LOG=N
>
> Committed: https://crrev.com/37632606bbce1418238b13fd90cb6ef6705871cd
> Cr-Commit-Position: refs/heads/master@{#32029}

TBR=littledan@chromium.org,erikcorry@chromium.org,erikcorry@google.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:4545

Review URL: https://codereview.chromium.org/1451373003

Cr-Commit-Position: refs/heads/master@{#32032}
This commit is contained in:
yangguo 2015-11-17 03:55:03 -08:00 committed by Commit bot
parent 2f7d6b46d0
commit 5b2ae9d908
29 changed files with 572 additions and 1117 deletions

View File

@ -850,7 +850,7 @@ Interval RegExpDisjunction::CaptureRegisters() {
}
Interval RegExpLookaround::CaptureRegisters() {
Interval RegExpLookahead::CaptureRegisters() {
return body()->CaptureRegisters();
}
@ -918,8 +918,8 @@ bool RegExpDisjunction::IsAnchoredAtEnd() {
}
bool RegExpLookaround::IsAnchoredAtStart() {
return is_positive() && type() == LOOKAHEAD && body()->IsAnchoredAtStart();
bool RegExpLookahead::IsAnchoredAtStart() {
return is_positive() && body()->IsAnchoredAtStart();
}
@ -1068,10 +1068,8 @@ void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
}
void* RegExpUnparser::VisitLookaround(RegExpLookaround* that, void* data) {
os_ << "(";
os_ << (that->type() == RegExpLookaround::LOOKAHEAD ? "->" : "<-");
os_ << (that->is_positive() ? " + " : " - ");
void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
os_ << "(-> " << (that->is_positive() ? "+ " : "- ");
that->body()->Accept(this, data);
os_ << ")";
return NULL;

View File

@ -119,7 +119,7 @@ class RegExpCharacterClass;
class RegExpCompiler;
class RegExpDisjunction;
class RegExpEmpty;
class RegExpLookaround;
class RegExpLookahead;
class RegExpQuantifier;
class RegExpText;
@ -3075,7 +3075,8 @@ class RegExpQuantifier final : public RegExpTree {
class RegExpCapture final : public RegExpTree {
public:
explicit RegExpCapture(int index) : body_(NULL), index_(index) {}
explicit RegExpCapture(RegExpTree* body, int index)
: body_(body), index_(index) { }
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
static RegExpNode* ToNode(RegExpTree* body,
@ -3090,7 +3091,6 @@ class RegExpCapture final : public RegExpTree {
int min_match() override { return body_->min_match(); }
int max_match() override { return body_->max_match(); }
RegExpTree* body() { return body_; }
void set_body(RegExpTree* body) { body_ = body; }
int index() { return index_; }
static int StartRegister(int index) { return index * 2; }
static int EndRegister(int index) { return index * 2 + 1; }
@ -3101,23 +3101,22 @@ class RegExpCapture final : public RegExpTree {
};
class RegExpLookaround final : public RegExpTree {
class RegExpLookahead final : public RegExpTree {
public:
enum Type { LOOKAHEAD, LOOKBEHIND };
RegExpLookaround(RegExpTree* body, bool is_positive, int capture_count,
int capture_from, Type type)
RegExpLookahead(RegExpTree* body,
bool is_positive,
int capture_count,
int capture_from)
: body_(body),
is_positive_(is_positive),
capture_count_(capture_count),
capture_from_(capture_from),
type_(type) {}
capture_from_(capture_from) { }
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
RegExpLookaround* AsLookaround() override;
RegExpLookahead* AsLookahead() override;
Interval CaptureRegisters() override;
bool IsLookaround() override;
bool IsLookahead() override;
bool IsAnchoredAtStart() override;
int min_match() override { return 0; }
int max_match() override { return 0; }
@ -3125,14 +3124,12 @@ class RegExpLookaround final : public RegExpTree {
bool is_positive() { return is_positive_; }
int capture_count() { return capture_count_; }
int capture_from() { return capture_from_; }
Type type() { return type_; }
private:
RegExpTree* body_;
bool is_positive_;
int capture_count_;
int capture_from_;
Type type_;
};
@ -3145,14 +3142,7 @@ class RegExpBackReference final : public RegExpTree {
RegExpBackReference* AsBackReference() override;
bool IsBackReference() override;
int min_match() override { return 0; }
// The capture may not be completely parsed yet, if the reference occurs
// before the capture. In the ordinary case, nothing has been captured yet,
// so the back reference must have the length 0. If the back reference is
// inside a lookbehind, effectively making it a forward reference, we return
// 0 since lookbehinds have a length of 0.
int max_match() override {
return capture_->body() ? capture_->max_match() : 0;
}
int max_match() override { return capture_->max_match(); }
int index() { return capture_->index(); }
RegExpCapture* capture() { return capture_; }
private:

View File

@ -2049,7 +2049,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_unicode_regexps)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_completion)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tolength)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_do_expressions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_lookbehind)
static void SimpleInstallFunction(Handle<JSObject>& base, const char* name,
@ -2562,7 +2561,6 @@ bool Genesis::InstallExperimentalNatives() {
static const char* harmony_completion_natives[] = {nullptr};
static const char* harmony_do_expressions_natives[] = {nullptr};
static const char* harmony_regexp_subclass_natives[] = {nullptr};
static const char* harmony_regexp_lookbehind_natives[] = {nullptr};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {

View File

@ -202,8 +202,7 @@ DEFINE_IMPLICATION(es_staging, harmony_destructuring)
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_simd, "harmony simd") \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_regexp_subclass, "harmony regexp subclassing") \
V(harmony_regexp_lookbehind, "harmony regexp lookbehind")
V(harmony_regexp_subclass, "harmony regexp subclassing")
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \

View File

@ -5182,7 +5182,6 @@ RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error,
in_(in),
current_(kEndMarker),
next_pos_(0),
captures_started_(0),
capture_count_(0),
has_more_(true),
multiline_(multiline),
@ -5286,26 +5285,25 @@ RegExpTree* RegExpParser::ParsePattern() {
// Atom Quantifier
RegExpTree* RegExpParser::ParseDisjunction() {
// Used to store current state while parsing subexpressions.
RegExpParserState initial_state(NULL, INITIAL, RegExpLookaround::LOOKAHEAD, 0,
zone());
RegExpParserState* state = &initial_state;
RegExpParserState initial_state(NULL, INITIAL, 0, zone());
RegExpParserState* stored_state = &initial_state;
// Cache the builder in a local variable for quick access.
RegExpBuilder* builder = initial_state.builder();
while (true) {
switch (current()) {
case kEndMarker:
if (state->IsSubexpression()) {
if (stored_state->IsSubexpression()) {
// Inside a parenthesized group when hitting end of input.
ReportError(CStrVector("Unterminated group") CHECK_FAILED);
}
DCHECK_EQ(INITIAL, state->group_type());
DCHECK_EQ(INITIAL, stored_state->group_type());
// Parsing completed successfully.
return builder->ToRegExp();
case ')': {
if (!state->IsSubexpression()) {
if (!stored_state->IsSubexpression()) {
ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
}
DCHECK_NE(INITIAL, state->group_type());
DCHECK_NE(INITIAL, stored_state->group_type());
Advance();
// End disjunction parsing and convert builder content to new single
@ -5314,27 +5312,27 @@ RegExpTree* RegExpParser::ParseDisjunction() {
int end_capture_index = captures_started();
int capture_index = state->capture_index();
SubexpressionType group_type = state->group_type();
int capture_index = stored_state->capture_index();
SubexpressionType group_type = stored_state->group_type();
// Restore previous state.
stored_state = stored_state->previous_state();
builder = stored_state->builder();
// Build result of subexpression.
if (group_type == CAPTURE) {
RegExpCapture* capture = GetCapture(capture_index);
capture->set_body(body);
RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
captures_->at(capture_index - 1) = capture;
body = capture;
} else if (group_type != GROUPING) {
DCHECK(group_type == POSITIVE_LOOKAROUND ||
group_type == NEGATIVE_LOOKAROUND);
bool is_positive = (group_type == POSITIVE_LOOKAROUND);
body = new (zone()) RegExpLookaround(
body, is_positive, end_capture_index - capture_index, capture_index,
state->lookaround_type());
DCHECK(group_type == POSITIVE_LOOKAHEAD ||
group_type == NEGATIVE_LOOKAHEAD);
bool is_positive = (group_type == POSITIVE_LOOKAHEAD);
body = new(zone()) RegExpLookahead(body,
is_positive,
end_capture_index - capture_index,
capture_index);
}
// Restore previous state.
state = state->previous_state();
builder = state->builder();
builder->AddAtom(body);
// For compatability with JSC and ES3, we allow quantifiers after
// lookaheads, and break in all cases.
@ -5381,7 +5379,6 @@ RegExpTree* RegExpParser::ParseDisjunction() {
}
case '(': {
SubexpressionType subexpr_type = CAPTURE;
RegExpLookaround::Type lookaround_type = state->lookaround_type();
Advance();
if (current() == '?') {
switch (Next()) {
@ -5389,41 +5386,29 @@ RegExpTree* RegExpParser::ParseDisjunction() {
subexpr_type = GROUPING;
break;
case '=':
lookaround_type = RegExpLookaround::LOOKAHEAD;
subexpr_type = POSITIVE_LOOKAROUND;
subexpr_type = POSITIVE_LOOKAHEAD;
break;
case '!':
lookaround_type = RegExpLookaround::LOOKAHEAD;
subexpr_type = NEGATIVE_LOOKAROUND;
subexpr_type = NEGATIVE_LOOKAHEAD;
break;
case '<':
if (FLAG_harmony_regexp_lookbehind) {
Advance();
lookaround_type = RegExpLookaround::LOOKBEHIND;
if (Next() == '=') {
subexpr_type = POSITIVE_LOOKAROUND;
break;
} else if (Next() == '!') {
subexpr_type = NEGATIVE_LOOKAROUND;
break;
}
}
// Fall through.
default:
ReportError(CStrVector("Invalid group") CHECK_FAILED);
break;
}
Advance(2);
} else {
if (captures_started_ >= kMaxCaptures) {
if (captures_ == NULL) {
captures_ = new(zone()) ZoneList<RegExpCapture*>(2, zone());
}
if (captures_started() >= kMaxCaptures) {
ReportError(CStrVector("Too many captures") CHECK_FAILED);
}
captures_started_++;
captures_->Add(NULL, zone());
}
// Store current state and begin new disjunction parsing.
state = new (zone()) RegExpParserState(
state, subexpr_type, lookaround_type, captures_started_, zone());
builder = state->builder();
stored_state = new(zone()) RegExpParserState(stored_state, subexpr_type,
captures_started(), zone());
builder = stored_state->builder();
continue;
}
case '[': {
@ -5466,15 +5451,16 @@ RegExpTree* RegExpParser::ParseDisjunction() {
case '7': case '8': case '9': {
int index = 0;
if (ParseBackReferenceIndex(&index)) {
if (state->IsInsideCaptureGroup(index)) {
// The backreference is inside the capture group it refers to.
// Nothing can possibly have been captured yet.
builder->AddEmpty();
} else {
RegExpCapture* capture = GetCapture(index);
RegExpTree* atom = new (zone()) RegExpBackReference(capture);
builder->AddAtom(atom);
RegExpCapture* capture = NULL;
if (captures_ != NULL && index <= captures_->length()) {
capture = captures_->at(index - 1);
}
if (capture == NULL) {
builder->AddEmpty();
break;
}
RegExpTree* atom = new(zone()) RegExpBackReference(capture);
builder->AddAtom(atom);
break;
}
uc32 first_digit = Next();
@ -5735,34 +5721,6 @@ bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
}
RegExpCapture* RegExpParser::GetCapture(int index) {
// The index for the capture groups are one-based. Its index in the list is
// zero-based.
int know_captures =
is_scanned_for_captures_ ? capture_count_ : captures_started_;
DCHECK(index <= know_captures);
if (captures_ == NULL) {
captures_ = new (zone()) ZoneList<RegExpCapture*>(know_captures, zone());
}
while (captures_->length() < know_captures) {
captures_->Add(new (zone()) RegExpCapture(captures_->length() + 1), zone());
}
return captures_->at(index - 1);
}
bool RegExpParser::RegExpParserState::IsInsideCaptureGroup(int index) {
for (RegExpParserState* s = this; s != NULL; s = s->previous_state()) {
if (s->group_type() != CAPTURE) continue;
// Return true if we found the matching capture index.
if (index == s->capture_index()) return true;
// Abort if index is larger than what has been parsed up till this state.
if (index > s->capture_index()) return false;
}
return false;
}
// QuantifierPrefix ::
// { DecimalDigits }
// { DecimalDigits , }
@ -6094,7 +6052,7 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
ranges->Add(CharacterRange::Everything(), zone());
is_negated = !is_negated;
}
return new (zone()) RegExpCharacterClass(ranges, is_negated);
return new(zone()) RegExpCharacterClass(ranges, is_negated);
}

View File

@ -450,7 +450,7 @@ class RegExpParser BASE_EMBEDDED {
bool simple();
bool contains_anchor() { return contains_anchor_; }
void set_contains_anchor() { contains_anchor_ = true; }
int captures_started() { return captures_started_; }
int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
int position() { return next_pos_ - 1; }
bool failed() { return failed_; }
@ -463,8 +463,8 @@ class RegExpParser BASE_EMBEDDED {
enum SubexpressionType {
INITIAL,
CAPTURE, // All positive values represent captures.
POSITIVE_LOOKAROUND,
NEGATIVE_LOOKAROUND,
POSITIVE_LOOKAHEAD,
NEGATIVE_LOOKAHEAD,
GROUPING
};
@ -472,12 +472,11 @@ class RegExpParser BASE_EMBEDDED {
public:
RegExpParserState(RegExpParserState* previous_state,
SubexpressionType group_type,
RegExpLookaround::Type lookaround_type,
int disjunction_capture_index, Zone* zone)
int disjunction_capture_index,
Zone* zone)
: previous_state_(previous_state),
builder_(new (zone) RegExpBuilder(zone)),
builder_(new(zone) RegExpBuilder(zone)),
group_type_(group_type),
lookaround_type_(lookaround_type),
disjunction_capture_index_(disjunction_capture_index) {}
// Parser state of containing expression, if any.
RegExpParserState* previous_state() { return previous_state_; }
@ -486,16 +485,11 @@ class RegExpParser BASE_EMBEDDED {
RegExpBuilder* builder() { return builder_; }
// Type of regexp being parsed (parenthesized group or entire regexp).
SubexpressionType group_type() { return group_type_; }
// Lookahead or Lookbehind.
RegExpLookaround::Type lookaround_type() { return lookaround_type_; }
// Index in captures array of first capture in this sub-expression, if any.
// Also the capture index of this sub-expression itself, if group_type
// is CAPTURE.
int capture_index() { return disjunction_capture_index_; }
// Check whether the parser is inside a capture group with the given index.
bool IsInsideCaptureGroup(int index);
private:
// Linked list implementation of stack of states.
RegExpParserState* previous_state_;
@ -503,15 +497,10 @@ class RegExpParser BASE_EMBEDDED {
RegExpBuilder* builder_;
// Stored disjunction type (capture, look-ahead or grouping), if any.
SubexpressionType group_type_;
// Stored read direction.
RegExpLookaround::Type lookaround_type_;
// Stored disjunction's capture index (if any).
int disjunction_capture_index_;
};
// Return the 1-indexed RegExpCapture object, allocate if necessary.
RegExpCapture* GetCapture(int index);
Isolate* isolate() { return isolate_; }
Zone* zone() const { return zone_; }
@ -529,7 +518,6 @@ class RegExpParser BASE_EMBEDDED {
FlatStringReader* in_;
uc32 current_;
int next_pos_;
int captures_started_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
bool has_more_;

View File

@ -58,7 +58,7 @@ namespace internal {
* - fp[-16] void* input_string (location of a handle containing the string).
* - fp[-20] success counter (only for global regexps to count matches).
* - fp[-24] Offset of location before start of input (effectively character
* string start - 1). Used to initialize capture registers to a
* position -1). Used to initialize capture registers to a
* non-position.
* - fp[-28] At start (if 1, we are starting at the start of the
* string, otherwise 0)
@ -176,18 +176,29 @@ void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
__ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ add(r0, current_input_offset(), Operand(-char_size()));
Label not_at_start;
// Did we start the match at the start of the string at all?
__ ldr(r0, MemOperand(frame_pointer(), kStartIndex));
__ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, &not_at_start);
// If we did, are we still at the start of the input?
__ ldr(r1, MemOperand(frame_pointer(), kInputStart));
__ add(r0, end_of_input_address(), Operand(current_input_offset()));
__ cmp(r0, r1);
BranchOrBacktrack(eq, on_at_start);
__ bind(&not_at_start);
}
void RegExpMacroAssemblerARM::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ add(r0, current_input_offset(),
Operand(-char_size() + cp_offset * char_size()));
void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ ldr(r0, MemOperand(frame_pointer(), kStartIndex));
__ cmp(r0, Operand::Zero());
BranchOrBacktrack(ne, on_not_at_start);
// If we did, are we still at the start of the input?
__ ldr(r1, MemOperand(frame_pointer(), kInputStart));
__ add(r0, end_of_input_address(), Operand(current_input_offset()));
__ cmp(r0, r1);
BranchOrBacktrack(ne, on_not_at_start);
}
@ -209,27 +220,20 @@ void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
__ ldr(r0, register_location(start_reg)); // Index of start of capture
__ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
__ sub(r1, r1, r0, SetCC); // Length of capture.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// If length is zero, either the capture is empty or it is not participating.
// In either case succeed immediately.
__ b(eq, &fallthrough);
// Check that there are enough characters left in the input.
if (read_backward) {
__ ldr(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
__ add(r3, r3, r1);
__ cmp(current_input_offset(), r3);
BranchOrBacktrack(le, on_no_match);
} else {
__ cmn(r1, Operand(current_input_offset()));
BranchOrBacktrack(gt, on_no_match);
}
__ cmn(r1, Operand(current_input_offset()));
BranchOrBacktrack(gt, on_no_match);
if (mode_ == LATIN1) {
Label success;
@ -238,12 +242,9 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
// r0 - offset of start of capture
// r1 - length of capture
__ add(r0, r0, end_of_input_address());
__ add(r2, end_of_input_address(), current_input_offset());
if (read_backward) {
__ sub(r2, r2, r1); // Offset by length when matching backwards.
}
__ add(r1, r0, r1);
__ add(r0, r0, Operand(end_of_input_address()));
__ add(r2, end_of_input_address(), Operand(current_input_offset()));
__ add(r1, r0, Operand(r1));
// r0 - Address of start of capture.
// r1 - Address of end of capture
@ -282,12 +283,6 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
__ bind(&success);
// Compute new value of character position after the matched part.
__ sub(current_input_offset(), r2, end_of_input_address());
if (read_backward) {
__ ldr(r0, register_location(start_reg)); // Index of start of capture
__ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
__ add(current_input_offset(), current_input_offset(), r0);
__ sub(current_input_offset(), current_input_offset(), r1);
}
} else {
DCHECK(mode_ == UC16);
int argument_count = 4;
@ -310,10 +305,7 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
// Save length in callee-save register for use on return.
__ mov(r4, Operand(r1));
// Address of current input position.
__ add(r1, current_input_offset(), end_of_input_address());
if (read_backward) {
__ sub(r1, r1, r4);
}
__ add(r1, current_input_offset(), Operand(end_of_input_address()));
// Isolate.
__ mov(r3, Operand(ExternalReference::isolate_address(isolate())));
@ -327,22 +319,17 @@ void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
// Check if function returned non-zero for success or zero for failure.
__ cmp(r0, Operand::Zero());
BranchOrBacktrack(eq, on_no_match);
// On success, advance position by length of capture.
if (read_backward) {
__ sub(current_input_offset(), current_input_offset(), r4);
} else {
__ add(current_input_offset(), current_input_offset(), r4);
}
// On success, increment position by length of capture.
__ add(current_input_offset(), current_input_offset(), Operand(r4));
}
__ bind(&fallthrough);
}
void RegExpMacroAssemblerARM::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerARM::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
Label success;
@ -350,31 +337,17 @@ void RegExpMacroAssemblerARM::CheckNotBackReference(int start_reg,
__ ldr(r0, register_location(start_reg));
__ ldr(r1, register_location(start_reg + 1));
__ sub(r1, r1, r0, SetCC); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// Succeed on empty capture (including no capture).
__ b(eq, &fallthrough);
// Check that there are enough characters left in the input.
if (read_backward) {
__ ldr(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
__ add(r3, r3, r1);
__ cmp(current_input_offset(), r3);
BranchOrBacktrack(lt, on_no_match);
} else {
__ cmn(r1, Operand(current_input_offset()));
BranchOrBacktrack(gt, on_no_match);
}
__ cmn(r1, Operand(current_input_offset()));
BranchOrBacktrack(gt, on_no_match);
// r0 - offset of start of capture
// r1 - length of capture
__ add(r0, r0, end_of_input_address());
__ add(r2, end_of_input_address(), current_input_offset());
if (read_backward) {
__ sub(r2, r2, r1); // Offset by length when matching backwards.
}
__ add(r1, r0, r1);
// Compute pointers to match string and capture string
__ add(r0, r0, Operand(end_of_input_address()));
__ add(r2, end_of_input_address(), Operand(current_input_offset()));
__ add(r1, r1, Operand(r0));
Label loop;
__ bind(&loop);
@ -393,13 +366,6 @@ void RegExpMacroAssemblerARM::CheckNotBackReference(int start_reg,
// Move current character position to position after match.
__ sub(current_input_offset(), r2, end_of_input_address());
if (read_backward) {
__ ldr(r0, register_location(start_reg)); // Index of start of capture
__ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
__ add(current_input_offset(), current_input_offset(), r0);
__ sub(current_input_offset(), current_input_offset(), r1);
}
__ bind(&fallthrough);
}
@ -637,7 +603,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ add(frame_pointer(), sp, Operand(4 * kPointerSize));
__ mov(r0, Operand::Zero());
__ push(r0); // Make room for success counter and initialize it to 0.
__ push(r0); // Make room for "string start - 1" constant.
__ push(r0); // Make room for "position - 1" constant (value is irrelevant).
// Check if we have space on the stack for registers.
Label stack_limit_hit;
Label stack_ok;
@ -681,7 +647,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ sub(r0, r0, Operand(r1, LSL, (mode_ == UC16) ? 1 : 0));
// Store this value in a local variable, for use when clearing
// position registers.
__ str(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
// Initialize code pointer register
__ mov(code_pointer(), Operand(masm_->CodeObject()));
@ -785,7 +751,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ str(r2, MemOperand(frame_pointer(), kRegisterOutput));
// Prepare r0 to initialize registers with its value in the next run.
__ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
if (global_with_zero_length_check()) {
// Special case for zero-length matches.
@ -926,13 +892,10 @@ void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input,
bool check_bounds,
int characters) {
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1020,7 +983,7 @@ void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
DCHECK(reg_from <= reg_to);
__ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
for (int reg = reg_from; reg <= reg_to; reg++) {
__ str(r0, register_location(reg));
}
@ -1106,15 +1069,8 @@ MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
__ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
BranchOrBacktrack(ge, on_outside_input);
} else {
__ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
__ cmp(r0, r1);
BranchOrBacktrack(le, on_outside_input);
}
__ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
BranchOrBacktrack(ge, on_outside_input);
}

View File

@ -34,11 +34,9 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(unsigned c,
@ -121,9 +119,9 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kSuccessfulCaptures = kInputString - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;

View File

@ -210,17 +210,23 @@ void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
__ Add(w10, current_input_offset(), Operand(-char_size()));
__ Cmp(w10, string_start_minus_one());
Label not_at_start;
// Did we start the match at the start of the input string?
CompareAndBranchOrBacktrack(start_offset(), 0, ne, &not_at_start);
// If we did, are we still at the start of the input string?
__ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
__ Cmp(x10, input_start());
BranchOrBacktrack(eq, on_at_start);
__ Bind(&not_at_start);
}
void RegExpMacroAssemblerARM64::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ Add(w10, current_input_offset(),
Operand(-char_size() + cp_offset * char_size()));
__ Cmp(w10, string_start_minus_one());
void RegExpMacroAssemblerARM64::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the input string?
CompareAndBranchOrBacktrack(start_offset(), 0, ne, on_not_at_start);
// If we did, are we still at the start of the input string?
__ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
__ Cmp(x10, input_start());
BranchOrBacktrack(ne, on_not_at_start);
}
@ -271,9 +277,9 @@ void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
BranchOrBacktrack(eq, on_equal);
}
void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
Register capture_start_offset = w10;
@ -291,21 +297,12 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
__ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
}
__ Sub(capture_length, w11, capture_start_offset); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
__ CompareAndBranch(capture_length, Operand(0), eq, &fallthrough);
// Succeed on empty capture (including no capture).
__ Cbz(capture_length, &fallthrough);
// Check that there are enough characters left in the input.
if (read_backward) {
__ Add(w12, string_start_minus_one(), capture_length);
__ Cmp(current_input_offset(), w12);
BranchOrBacktrack(le, on_no_match);
} else {
__ Cmn(capture_length, current_input_offset());
BranchOrBacktrack(gt, on_no_match);
}
__ Cmn(capture_length, current_input_offset());
BranchOrBacktrack(gt, on_no_match);
if (mode_ == LATIN1) {
Label success;
@ -325,11 +322,6 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
__ Add(current_position_address,
input_end(),
Operand(current_input_offset(), SXTW));
if (read_backward) {
// Offset by length when matching backwards.
__ Sub(current_position_address, current_position_address,
Operand(capture_length, SXTW));
}
Label loop;
__ Bind(&loop);
@ -369,10 +361,6 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
// The current input offset should be <= 0, and fit in a W register.
__ Check(le, kOffsetOutOfRange);
}
if (read_backward) {
__ Sub(current_input_offset(), current_input_offset(),
Operand(capture_length, SXTW));
}
} else {
DCHECK(mode_ == UC16);
int argument_count = 4;
@ -395,9 +383,6 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
__ Mov(w2, capture_length);
// Address of current input position.
__ Add(x1, input_end(), Operand(current_input_offset(), SXTW));
if (read_backward) {
__ Sub(x1, x1, Operand(capture_length, SXTW));
}
// Isolate.
__ Mov(x3, ExternalReference::isolate_address(isolate()));
@ -415,20 +400,16 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
__ PopCPURegList(cached_registers);
BranchOrBacktrack(eq, on_no_match);
// On success, advance position by length of capture.
if (read_backward) {
__ Sub(current_input_offset(), current_input_offset(), capture_length);
} else {
__ Add(current_input_offset(), current_input_offset(), capture_length);
}
// On success, increment position by length of capture.
__ Add(current_input_offset(), current_input_offset(), capture_length);
}
__ Bind(&fallthrough);
}
void RegExpMacroAssemblerARM64::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerARM64::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
Register capture_start_address = x12;
@ -445,21 +426,12 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference(int start_reg,
__ Ldp(w11, w10, capture_location(start_reg, x10));
}
__ Sub(capture_length, w11, w10); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
__ CompareAndBranch(capture_length, Operand(0), eq, &fallthrough);
// Succeed on empty capture (including no capture).
__ Cbz(capture_length, &fallthrough);
// Check that there are enough characters left in the input.
if (read_backward) {
__ Add(w12, string_start_minus_one(), capture_length);
__ Cmp(current_input_offset(), w12);
BranchOrBacktrack(le, on_no_match);
} else {
__ Cmn(capture_length, current_input_offset());
BranchOrBacktrack(gt, on_no_match);
}
__ Cmn(capture_length, current_input_offset());
BranchOrBacktrack(gt, on_no_match);
// Compute pointers to match string and capture string
__ Add(capture_start_address, input_end(), Operand(w10, SXTW));
@ -469,11 +441,6 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference(int start_reg,
__ Add(current_position_address,
input_end(),
Operand(current_input_offset(), SXTW));
if (read_backward) {
// Offset by length when matching backwards.
__ Sub(current_position_address, current_position_address,
Operand(capture_length, SXTW));
}
Label loop;
__ Bind(&loop);
@ -492,11 +459,6 @@ void RegExpMacroAssemblerARM64::CheckNotBackReference(int start_reg,
// Move current character position to position after match.
__ Sub(current_input_offset().X(), current_position_address, input_end());
if (read_backward) {
__ Sub(current_input_offset(), current_input_offset(),
Operand(capture_length, SXTW));
}
if (masm_->emit_debug_code()) {
__ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
__ Ccmp(current_input_offset(), 0, NoFlag, eq);
@ -796,13 +758,14 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
// The non-position value is used as a clearing value for the
// capture registers, it corresponds to the position of the first character
// minus one.
__ Sub(string_start_minus_one(), current_input_offset(), char_size());
__ Sub(string_start_minus_one(), string_start_minus_one(),
__ Sub(non_position_value(), current_input_offset(), char_size());
__ Sub(non_position_value(), non_position_value(),
Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0));
// We can store this value twice in an X register for initializing
// on-stack registers later.
__ Orr(twice_non_position_value(), string_start_minus_one().X(),
Operand(string_start_minus_one().X(), LSL, kWRegSizeInBits));
__ Orr(twice_non_position_value(),
non_position_value().X(),
Operand(non_position_value().X(), LSL, kWRegSizeInBits));
// Initialize code pointer register.
__ Mov(code_pointer(), Operand(masm_->CodeObject()));
@ -1118,14 +1081,11 @@ void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
int characters) {
// TODO(pielan): Make sure long strings are caught before this, and not
// just asserted in debug mode.
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
// Be sane! (And ensure that an int32_t can be used to index the string)
DCHECK(cp_offset < (1<<30));
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1250,7 +1210,7 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) {
// If the first capture register is cached in a hardware register but not
// aligned on a 64-bit one, we need to clear the first one specifically.
if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) {
StoreRegister(reg_from, string_start_minus_one());
StoreRegister(reg_from, non_position_value());
num_registers--;
reg_from++;
}
@ -1264,7 +1224,7 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) {
}
if ((num_registers % 2) == 1) {
StoreRegister(reg_from, string_start_minus_one());
StoreRegister(reg_from, non_position_value());
num_registers--;
reg_from++;
}
@ -1341,14 +1301,10 @@ int RegExpMacroAssemblerARM64::CheckStackGuardState(
void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
CompareAndBranchOrBacktrack(current_input_offset(),
-cp_offset * char_size(), ge, on_outside_input);
} else {
__ Add(w12, current_input_offset(), Operand(cp_offset * char_size()));
__ Cmp(w12, string_start_minus_one());
BranchOrBacktrack(le, on_outside_input);
}
CompareAndBranchOrBacktrack(current_input_offset(),
-cp_offset * char_size(),
ge,
on_outside_input);
}

View File

@ -39,11 +39,9 @@ class RegExpMacroAssemblerARM64: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(unsigned c,
@ -192,7 +190,7 @@ class RegExpMacroAssemblerARM64: public NativeRegExpMacroAssembler {
Register code_pointer() { return x20; }
// Register holding the value used for clearing capture registers.
Register string_start_minus_one() { return w24; }
Register non_position_value() { return w24; }
// The top 32 bit of this register is used to store this value
// twice. This is used for clearing more than one register at a time.
Register twice_non_position_value() { return x24; }

View File

@ -57,17 +57,15 @@ V(CHECK_LT, 35, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_GT, 36, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_NOT_BACK_REF, 37, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_BACK_REF_BACKWARD, 39, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD, 40, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_REGS_EQUAL, 41, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
V(CHECK_REGISTER_LT, 42, 12) /* bc8 reg_idx24 value32 addr32 */ \
V(CHECK_REGISTER_GE, 43, 12) /* bc8 reg_idx24 value32 addr32 */ \
V(CHECK_REGISTER_EQ_POS, 44, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_AT_START, 45, 8) /* bc8 pad24 addr32 */ \
V(CHECK_NOT_AT_START, 46, 8) /* bc8 offset24 addr32 */ \
V(CHECK_GREEDY, 47, 8) /* bc8 pad24 addr32 */ \
V(ADVANCE_CP_AND_GOTO, 48, 8) /* bc8 offset24 addr32 */ \
V(SET_CURRENT_POSITION_FROM_END, 49, 4) /* bc8 idx24 */
V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
V(CHECK_REGISTER_LT, 40, 12) /* bc8 reg_idx24 value32 addr32 */ \
V(CHECK_REGISTER_GE, 41, 12) /* bc8 reg_idx24 value32 addr32 */ \
V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_AT_START, 43, 8) /* bc8 pad24 addr32 */ \
V(CHECK_NOT_AT_START, 44, 8) /* bc8 pad24 addr32 */ \
V(CHECK_GREEDY, 45, 8) /* bc8 pad24 addr32 */ \
V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32 */ \
V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */
#define DECLARE_BYTECODES(name, code, length) \
static const int BC_##name = code;

View File

@ -53,8 +53,7 @@ namespace internal {
* - backup of caller ebx
* - success counter (only for global regexps to count matches).
* - Offset of location before start of input (effectively character
* string start - 1). Used to initialize capture registers to a
* non-position.
* position -1). Used to initialize capture registers to a non-position.
* - register 0 ebp[-4] (only positions must be stored in the first
* - register 1 ebp[-8] num_saved_registers_ registers)
* - ...
@ -157,16 +156,25 @@ void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
__ lea(eax, Operand(edi, -char_size()));
__ cmp(eax, Operand(ebp, kStringStartMinusOne));
Label not_at_start;
// Did we start the match at the start of the string at all?
__ cmp(Operand(ebp, kStartIndex), Immediate(0));
BranchOrBacktrack(not_equal, &not_at_start);
// If we did, are we still at the start of the input?
__ lea(eax, Operand(esi, edi, times_1, 0));
__ cmp(eax, Operand(ebp, kInputStart));
BranchOrBacktrack(equal, on_at_start);
__ bind(&not_at_start);
}
void RegExpMacroAssemblerIA32::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ lea(eax, Operand(edi, -char_size() + cp_offset * char_size()));
__ cmp(eax, Operand(ebp, kStringStartMinusOne));
void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ cmp(Operand(ebp, kStartIndex), Immediate(0));
BranchOrBacktrack(not_equal, on_not_at_start);
// If we did, are we still at the start of the input?
__ lea(eax, Operand(esi, edi, times_1, 0));
__ cmp(eax, Operand(ebp, kInputStart));
BranchOrBacktrack(not_equal, on_not_at_start);
}
@ -188,28 +196,26 @@ void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
__ mov(edx, register_location(start_reg)); // Index of start of capture
__ mov(ebx, register_location(start_reg + 1)); // Index of end of capture
__ sub(ebx, edx); // Length of capture.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// The length of a capture should not be negative. This can only happen
// if the end of the capture is unrecorded, or at a point earlier than
// the start of the capture.
BranchOrBacktrack(less, on_no_match);
// If length is zero, either the capture is empty or it is completely
// uncaptured. In either case succeed immediately.
__ j(equal, &fallthrough);
// Check that there are sufficient characters left in the input.
if (read_backward) {
__ mov(eax, Operand(ebp, kStringStartMinusOne));
__ add(eax, ebx);
__ cmp(edi, eax);
BranchOrBacktrack(less_equal, on_no_match);
} else {
__ mov(eax, edi);
__ add(eax, ebx);
BranchOrBacktrack(greater, on_no_match);
}
__ mov(eax, edi);
__ add(eax, ebx);
BranchOrBacktrack(greater, on_no_match);
if (mode_ == LATIN1) {
Label success;
@ -222,9 +228,6 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
__ add(edx, esi); // Start of capture
__ add(edi, esi); // Start of text to match against capture.
if (read_backward) {
__ sub(edi, ebx); // Offset by length when matching backwards.
}
__ add(ebx, edi); // End of text to match against capture.
Label loop;
@ -275,11 +278,6 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
__ add(esp, Immediate(kPointerSize));
// Compute new value of character position after the matched part.
__ sub(edi, esi);
if (read_backward) {
// Subtract match length if we matched backward.
__ add(edi, register_location(start_reg));
__ sub(edi, register_location(start_reg + 1));
}
} else {
DCHECK(mode_ == UC16);
// Save registers before calling C function.
@ -306,9 +304,6 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
// Found by adding negative string-end offset of current position (edi)
// to end of string.
__ add(edi, esi);
if (read_backward) {
__ sub(edi, ebx); // Offset by length when matching backwards.
}
__ mov(Operand(esp, 1 * kPointerSize), edi);
// Set byte_offset1.
// Start of capture, where edx already holds string-end negative offset.
@ -330,20 +325,16 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
// Check if function returned non-zero for success or zero for failure.
__ or_(eax, eax);
BranchOrBacktrack(zero, on_no_match);
// On success, advance position by length of capture.
if (read_backward) {
__ sub(edi, ebx);
} else {
__ add(edi, ebx);
}
// On success, increment position by length of capture.
__ add(edi, ebx);
}
__ bind(&fallthrough);
}
void RegExpMacroAssemblerIA32::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerIA32::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
Label success;
Label fail;
@ -352,33 +343,22 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference(int start_reg,
__ mov(edx, register_location(start_reg));
__ mov(eax, register_location(start_reg + 1));
__ sub(eax, edx); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// Fail on partial or illegal capture (start of capture after end of capture).
BranchOrBacktrack(less, on_no_match);
// Succeed on empty capture (including no capture)
__ j(equal, &fallthrough);
// Check that there are sufficient characters left in the input.
if (read_backward) {
__ mov(ebx, Operand(ebp, kStringStartMinusOne));
__ add(ebx, eax);
__ cmp(edi, ebx);
BranchOrBacktrack(less_equal, on_no_match);
} else {
__ mov(ebx, edi);
__ add(ebx, eax);
BranchOrBacktrack(greater, on_no_match);
}
__ mov(ebx, edi);
__ add(ebx, eax);
BranchOrBacktrack(greater, on_no_match);
// Save register to make it available below.
__ push(backtrack_stackpointer());
// Compute pointers to match string and capture string
__ add(edx, esi); // Start of capture.
__ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match.
if (read_backward) {
__ sub(ebx, eax); // Offset by length when matching backwards.
}
__ add(edx, esi); // Start of capture.
__ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match
Label loop;
@ -409,11 +389,6 @@ void RegExpMacroAssemblerIA32::CheckNotBackReference(int start_reg,
// Move current character position to position after match.
__ mov(edi, ecx);
__ sub(edi, esi);
if (read_backward) {
// Subtract match length if we matched backward.
__ add(edi, register_location(start_reg));
__ sub(edi, register_location(start_reg + 1));
}
// Restore backtrack stackpointer.
__ pop(backtrack_stackpointer());
@ -659,7 +634,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ push(edi);
__ push(ebx); // Callee-save on MacOS.
__ push(Immediate(0)); // Number of successful matches in a global regexp.
__ push(Immediate(0)); // Make room for "string start - 1" constant.
__ push(Immediate(0)); // Make room for "input start - 1" constant.
// Check if we have space on the stack for registers.
Label stack_limit_hit;
@ -709,7 +684,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
}
// Store this value in a local variable, for use when clearing
// position registers.
__ mov(Operand(ebp, kStringStartMinusOne), eax);
__ mov(Operand(ebp, kInputStartMinusOne), eax);
#if V8_OS_WIN
// Ensure that we write to each stack page, in order. Skipping a page
@ -792,7 +767,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
}
if (global()) {
// Restart matching if the regular expression is flagged as global.
// Restart matching if the regular expression is flagged as global.
// Increment success counter.
__ inc(Operand(ebp, kSuccessfulCaptures));
// Capture results have been stored, so the number of remaining global
@ -809,7 +784,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
Immediate(num_saved_registers_ * kPointerSize));
// Prepare eax to initialize registers with its value in the next run.
__ mov(eax, Operand(ebp, kStringStartMinusOne));
__ mov(eax, Operand(ebp, kInputStartMinusOne));
if (global_with_zero_length_check()) {
// Special case for zero-length matches.
@ -969,13 +944,10 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input,
bool check_bounds,
int characters) {
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1059,7 +1031,7 @@ void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
DCHECK(reg_from <= reg_to);
__ mov(eax, Operand(ebp, kStringStartMinusOne));
__ mov(eax, Operand(ebp, kInputStartMinusOne));
for (int reg = reg_from; reg <= reg_to; reg++) {
__ mov(register_location(reg), eax);
}
@ -1128,14 +1100,8 @@ Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
__ cmp(edi, -cp_offset * char_size());
BranchOrBacktrack(greater_equal, on_outside_input);
} else {
__ lea(eax, Operand(edi, cp_offset * char_size()));
__ cmp(eax, Operand(ebp, kStringStartMinusOne));
BranchOrBacktrack(less_equal, on_outside_input);
}
__ cmp(edi, -cp_offset * char_size());
BranchOrBacktrack(greater_equal, on_outside_input);
}

View File

@ -33,11 +33,9 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(uint32_t c,
@ -118,9 +116,9 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
static const int kBackup_edi = kBackup_esi - kPointerSize;
static const int kBackup_ebx = kBackup_edi - kPointerSize;
static const int kSuccessfulCaptures = kBackup_ebx - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;

View File

@ -270,7 +270,7 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
break;
BYTECODE(LOAD_CURRENT_CHAR) {
int pos = current + (insn >> BYTECODE_SHIFT);
if (pos >= subject.length() || pos < 0) {
if (pos >= subject.length()) {
pc = code_base + Load32Aligned(pc + 4);
} else {
current_char = subject[pos];
@ -286,7 +286,7 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
}
BYTECODE(LOAD_2_CURRENT_CHARS) {
int pos = current + (insn >> BYTECODE_SHIFT);
if (pos + 2 > subject.length() || pos < 0) {
if (pos + 2 > subject.length()) {
pc = code_base + Load32Aligned(pc + 4);
} else {
Char next = subject[pos + 1];
@ -306,7 +306,7 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
BYTECODE(LOAD_4_CURRENT_CHARS) {
DCHECK(sizeof(Char) == 1);
int pos = current + (insn >> BYTECODE_SHIFT);
if (pos + 4 > subject.length() || pos < 0) {
if (pos + 4 > subject.length()) {
pc = code_base + Load32Aligned(pc + 4);
} else {
Char next1 = subject[pos + 1];
@ -497,59 +497,46 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
BYTECODE(CHECK_NOT_BACK_REF) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
if (from >= 0 && len > 0) {
if (current + len > subject.length() ||
CompareChars(&subject[from], &subject[current], len) != 0) {
pc = code_base + Load32Aligned(pc + 4);
break;
if (from < 0 || len <= 0) {
pc += BC_CHECK_NOT_BACK_REF_LENGTH;
break;
}
if (current + len > subject.length()) {
pc = code_base + Load32Aligned(pc + 4);
break;
} else {
int i;
for (i = 0; i < len; i++) {
if (subject[from + i] != subject[current + i]) {
pc = code_base + Load32Aligned(pc + 4);
break;
}
}
if (i < len) break;
current += len;
}
pc += BC_CHECK_NOT_BACK_REF_LENGTH;
break;
}
BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
if (from >= 0 && len > 0) {
if (current - len < 0 ||
CompareChars(&subject[from], &subject[current - len], len) != 0) {
pc = code_base + Load32Aligned(pc + 4);
break;
}
current -= len;
}
pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
break;
}
BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
if (from >= 0 && len > 0) {
if (current + len > subject.length() ||
!BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
from, current, len, subject)) {
pc = code_base + Load32Aligned(pc + 4);
break;
}
current += len;
if (from < 0 || len <= 0) {
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
break;
}
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
break;
}
BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
if (from >= 0 && len > 0) {
if (current - len < 0 ||
!BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
from, current - len, len, subject)) {
if (current + len > subject.length()) {
pc = code_base + Load32Aligned(pc + 4);
break;
} else {
if (BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
from, current, len, subject)) {
current += len;
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
} else {
pc = code_base + Load32Aligned(pc + 4);
break;
}
current -= len;
}
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
break;
}
BYTECODE(CHECK_AT_START)
@ -560,7 +547,7 @@ static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
}
break;
BYTECODE(CHECK_NOT_AT_START)
if (current + (insn >> BYTECODE_SHIFT) == 0) {
if (current == 0) {
pc += BC_CHECK_NOT_AT_START_LENGTH;
} else {
pc = code_base + Load32Aligned(pc + 4);

View File

@ -1002,8 +1002,6 @@ class RegExpCompiler {
inline void set_limiting_recursion(bool value) {
limiting_recursion_ = value;
}
bool read_backward() { return read_backward_; }
void set_read_backward(bool value) { read_backward_ = value; }
FrequencyCollator* frequency_collator() { return &frequency_collator_; }
int current_expansion_factor() { return current_expansion_factor_; }
@ -1027,7 +1025,6 @@ class RegExpCompiler {
bool reg_exp_too_big_;
bool limiting_recursion_;
bool optimize_;
bool read_backward_;
int current_expansion_factor_;
FrequencyCollator frequency_collator_;
Isolate* isolate_;
@ -1063,7 +1060,6 @@ RegExpCompiler::RegExpCompiler(Isolate* isolate, Zone* zone, int capture_count,
reg_exp_too_big_(false),
limiting_recursion_(false),
optimize_(FLAG_regexp_optimization),
read_backward_(false),
current_expansion_factor_(1),
frequency_collator_(),
isolate_(isolate),
@ -1228,8 +1224,7 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
int value = 0;
bool absolute = false;
bool clear = false;
static const int kNoStore = kMinInt;
int store_position = kNoStore;
int store_position = -1;
// This is a little tricky because we are scanning the actions in reverse
// historical order (newest first).
for (DeferredAction* action = actions_;
@ -1250,7 +1245,7 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
// we can set undo_action to IGNORE if we know there is no value to
// restore.
undo_action = RESTORE;
DCHECK_EQ(store_position, kNoStore);
DCHECK_EQ(store_position, -1);
DCHECK(!clear);
break;
}
@ -1258,14 +1253,14 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
if (!absolute) {
value++;
}
DCHECK_EQ(store_position, kNoStore);
DCHECK_EQ(store_position, -1);
DCHECK(!clear);
undo_action = RESTORE;
break;
case ActionNode::STORE_POSITION: {
Trace::DeferredCapture* pc =
static_cast<Trace::DeferredCapture*>(action);
if (!clear && store_position == kNoStore) {
if (!clear && store_position == -1) {
store_position = pc->cp_offset();
}
@ -1289,7 +1284,7 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
// Since we're scanning in reverse order, if we've already
// set the position we have to ignore historically earlier
// clearing operations.
if (store_position == kNoStore) {
if (store_position == -1) {
clear = true;
}
undo_action = RESTORE;
@ -1320,7 +1315,7 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
}
// Perform the chronologically last action (or accumulated increment)
// for the register.
if (store_position != kNoStore) {
if (store_position != -1) {
assembler->WriteCurrentPositionToRegister(reg, store_position);
} else if (clear) {
assembler->ClearRegisters(reg, reg);
@ -2318,7 +2313,6 @@ void AssertionNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
int BackReferenceNode::EatsAtLeast(int still_to_find,
int budget,
bool not_at_start) {
if (read_backward()) return 0;
if (budget <= 0) return 0;
return on_success()->EatsAtLeast(still_to_find,
budget - 1,
@ -2329,7 +2323,6 @@ int BackReferenceNode::EatsAtLeast(int still_to_find,
int TextNode::EatsAtLeast(int still_to_find,
int budget,
bool not_at_start) {
if (read_backward()) return 0;
int answer = Length();
if (answer >= still_to_find) return answer;
if (budget <= 0) return answer;
@ -2533,8 +2526,8 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
} else {
char_mask = String::kMaxUtf16CodeUnit;
}
for (int k = 0; k < elements()->length(); k++) {
TextElement elm = elements()->at(k);
for (int k = 0; k < elms_->length(); k++) {
TextElement elm = elms_->at(k);
if (elm.text_type() == TextElement::ATOM) {
Vector<const uc16> quarks = elm.atom()->data();
for (int i = 0; i < characters && i < quarks.length(); i++) {
@ -2685,6 +2678,7 @@ void QuickCheckDetails::Clear() {
void QuickCheckDetails::Advance(int by, bool one_byte) {
DCHECK(by >= 0);
if (by >= characters_) {
Clear();
return;
@ -2786,9 +2780,9 @@ RegExpNode* TextNode::FilterOneByte(int depth, bool ignore_case) {
if (depth < 0) return this;
DCHECK(!info()->visited);
VisitMarker marker(info());
int element_count = elements()->length();
int element_count = elms_->length();
for (int i = 0; i < element_count; i++) {
TextElement elm = elements()->at(i);
TextElement elm = elms_->at(i);
if (elm.text_type() == TextElement::ATOM) {
Vector<const uc16> quarks = elm.atom()->data();
for (int j = 0; j < quarks.length(); j++) {
@ -3152,9 +3146,9 @@ void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
return;
}
if (trace->at_start() == Trace::UNKNOWN) {
assembler->CheckNotAtStart(trace->cp_offset(), trace->backtrack());
assembler->CheckNotAtStart(trace->backtrack());
Trace at_start_trace = *trace;
at_start_trace.set_at_start(Trace::TRUE_VALUE);
at_start_trace.set_at_start(true);
on_success()->Emit(compiler, &at_start_trace);
return;
}
@ -3227,11 +3221,10 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
bool one_byte = compiler->one_byte();
Label* backtrack = trace->backtrack();
QuickCheckDetails* quick_check = trace->quick_check_performed();
int element_count = elements()->length();
int backward_offset = read_backward() ? -Length() : 0;
int element_count = elms_->length();
for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
TextElement elm = elements()->at(i);
int cp_offset = trace->cp_offset() + elm.cp_offset() + backward_offset;
TextElement elm = elms_->at(i);
int cp_offset = trace->cp_offset() + elm.cp_offset();
if (elm.text_type() == TextElement::ATOM) {
Vector<const uc16> quarks = elm.atom()->data();
for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
@ -3259,10 +3252,13 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
break;
}
if (emit_function != NULL) {
bool bounds_check = *checked_up_to < cp_offset + j || read_backward();
bool bound_checked =
emit_function(isolate, compiler, quarks[j], backtrack,
cp_offset + j, bounds_check, preloaded);
bool bound_checked = emit_function(isolate,
compiler,
quarks[j],
backtrack,
cp_offset + j,
*checked_up_to < cp_offset + j,
preloaded);
if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to);
}
}
@ -3272,9 +3268,8 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
if (first_element_checked && i == 0) continue;
if (DeterminedAlready(quick_check, elm.cp_offset())) continue;
RegExpCharacterClass* cc = elm.char_class();
bool bounds_check = *checked_up_to < cp_offset || read_backward();
EmitCharClass(assembler, cc, one_byte, backtrack, cp_offset,
bounds_check, preloaded, zone());
*checked_up_to < cp_offset, preloaded, zone());
UpdateBoundsCheck(cp_offset, checked_up_to);
}
}
@ -3283,7 +3278,7 @@ void TextNode::TextEmitPass(RegExpCompiler* compiler,
int TextNode::Length() {
TextElement elm = elements()->last();
TextElement elm = elms_->last();
DCHECK(elm.cp_offset() >= 0);
return elm.cp_offset() + elm.length();
}
@ -3352,11 +3347,8 @@ void TextNode::Emit(RegExpCompiler* compiler, Trace* trace) {
}
Trace successor_trace(*trace);
// If we advance backward, we may end up at the start.
successor_trace.AdvanceCurrentPositionInTrace(
read_backward() ? -Length() : Length(), compiler);
successor_trace.set_at_start(read_backward() ? Trace::UNKNOWN
: Trace::FALSE_VALUE);
successor_trace.set_at_start(false);
successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
RecursionCheck rc(compiler);
on_success()->Emit(compiler, &successor_trace);
}
@ -3368,6 +3360,7 @@ void Trace::InvalidateCurrentCharacter() {
void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) {
DCHECK(by > 0);
// We don't have an instruction for shifting the current character register
// down or for using a shifted value for anything so lets just forget that
// we preloaded any characters into it.
@ -3386,9 +3379,9 @@ void Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler) {
void TextNode::MakeCaseIndependent(Isolate* isolate, bool is_one_byte) {
int element_count = elements()->length();
int element_count = elms_->length();
for (int i = 0; i < element_count; i++) {
TextElement elm = elements()->at(i);
TextElement elm = elms_->at(i);
if (elm.text_type() == TextElement::CHAR_CLASS) {
RegExpCharacterClass* cc = elm.char_class();
// None of the standard character classes is different in the case
@ -3404,14 +3397,16 @@ void TextNode::MakeCaseIndependent(Isolate* isolate, bool is_one_byte) {
}
int TextNode::GreedyLoopTextLength() { return Length(); }
int TextNode::GreedyLoopTextLength() {
TextElement elm = elms_->at(elms_->length() - 1);
return elm.cp_offset() + elm.length();
}
RegExpNode* TextNode::GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler) {
if (read_backward()) return NULL;
if (elements()->length() != 1) return NULL;
TextElement elm = elements()->at(0);
if (elms_->length() != 1) return NULL;
TextElement elm = elms_->at(0);
if (elm.text_type() != TextElement::CHAR_CLASS) return NULL;
RegExpCharacterClass* node = elm.char_class();
ZoneList<CharacterRange>* ranges = node->ranges(zone());
@ -3455,7 +3450,7 @@ int ChoiceNode::GreedyLoopTextLengthForAlternative(
SeqRegExpNode* seq_node = static_cast<SeqRegExpNode*>(node);
node = seq_node->on_success();
}
return read_backward() ? -length : length;
return length;
}
@ -3886,7 +3881,7 @@ void BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) {
GreedyLoopState::GreedyLoopState(bool not_at_start) {
counter_backtrack_trace_.set_backtrack(&label_);
if (not_at_start) counter_backtrack_trace_.set_at_start(Trace::FALSE_VALUE);
if (not_at_start) counter_backtrack_trace_.set_at_start(false);
}
@ -4013,7 +4008,7 @@ Trace* ChoiceNode::EmitGreedyLoop(RegExpCompiler* compiler,
macro_assembler->PushCurrentPosition();
Label greedy_match_failed;
Trace greedy_match_trace;
if (not_at_start()) greedy_match_trace.set_at_start(Trace::FALSE_VALUE);
if (not_at_start()) greedy_match_trace.set_at_start(false);
greedy_match_trace.set_backtrack(&greedy_match_failed);
Label loop_label;
macro_assembler->Bind(&loop_label);
@ -4359,14 +4354,11 @@ void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
DCHECK_EQ(start_reg_ + 1, end_reg_);
if (compiler->ignore_case()) {
assembler->CheckNotBackReferenceIgnoreCase(start_reg_, read_backward(),
assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
trace->backtrack());
} else {
assembler->CheckNotBackReference(start_reg_, read_backward(),
trace->backtrack());
assembler->CheckNotBackReference(start_reg_, trace->backtrack());
}
// We are going to advance backward, so we may end up at the start.
if (read_backward()) trace->set_at_start(Trace::UNKNOWN);
on_success()->Emit(compiler, trace);
}
@ -4727,15 +4719,13 @@ RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
ZoneList<TextElement>* elms =
new(compiler->zone()) ZoneList<TextElement>(1, compiler->zone());
elms->Add(TextElement::Atom(this), compiler->zone());
return new (compiler->zone())
TextNode(elms, compiler->read_backward(), on_success);
return new(compiler->zone()) TextNode(elms, on_success);
}
RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
return new (compiler->zone())
TextNode(elements(), compiler->read_backward(), on_success);
return new(compiler->zone()) TextNode(elements(), on_success);
}
@ -4832,8 +4822,7 @@ bool RegExpCharacterClass::is_standard(Zone* zone) {
RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
return new (compiler->zone())
TextNode(this, compiler->read_backward(), on_success);
return new(compiler->zone()) TextNode(this, on_success);
}
@ -5215,9 +5204,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
GuardedAlternative(body->ToNode(compiler, answer)));
}
answer = alternation;
if (not_at_start && !compiler->read_backward()) {
alternation->set_not_at_start();
}
if (not_at_start) alternation->set_not_at_start();
}
return answer;
}
@ -5229,9 +5216,9 @@ RegExpNode* RegExpQuantifier::ToNode(int min,
int reg_ctr = needs_counter
? compiler->AllocateRegister()
: RegExpCompiler::kNoRegister;
LoopChoiceNode* center = new (zone)
LoopChoiceNode(body->min_match() == 0, compiler->read_backward(), zone);
if (not_at_start && !compiler->read_backward()) center->set_not_at_start();
LoopChoiceNode* center = new(zone) LoopChoiceNode(body->min_match() == 0,
zone);
if (not_at_start) center->set_not_at_start();
RegExpNode* loop_return = needs_counter
? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
: static_cast<RegExpNode*>(center);
@ -5307,13 +5294,14 @@ RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
ZoneList<CharacterRange>* newline_ranges =
new(zone) ZoneList<CharacterRange>(3, zone);
CharacterRange::AddClassEscape('n', newline_ranges, zone);
RegExpCharacterClass* newline_atom = new (zone) RegExpCharacterClass('n');
TextNode* newline_matcher = new (zone) TextNode(
newline_atom, false, ActionNode::PositiveSubmatchSuccess(
stack_pointer_register, position_register,
0, // No captures inside.
-1, // Ignored if no captures.
on_success));
RegExpCharacterClass* newline_atom = new(zone) RegExpCharacterClass('n');
TextNode* newline_matcher = new(zone) TextNode(
newline_atom,
ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
position_register,
0, // No captures inside.
-1, // Ignored if no captures.
on_success));
// Create an end-of-input matcher.
RegExpNode* end_of_line = ActionNode::BeginSubmatch(
stack_pointer_register,
@ -5335,10 +5323,10 @@ RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
return new (compiler->zone())
return new(compiler->zone())
BackReferenceNode(RegExpCapture::StartRegister(index()),
RegExpCapture::EndRegister(index()),
compiler->read_backward(), on_success);
on_success);
}
@ -5348,8 +5336,8 @@ RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
}
RegExpNode* RegExpLookaround::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
int stack_pointer_register = compiler->AllocateRegister();
int position_register = compiler->AllocateRegister();
@ -5359,16 +5347,19 @@ RegExpNode* RegExpLookaround::ToNode(RegExpCompiler* compiler,
int register_start =
register_of_first_capture + capture_from_ * registers_per_capture;
RegExpNode* result;
bool was_reading_backward = compiler->read_backward();
compiler->set_read_backward(type() == LOOKBEHIND);
RegExpNode* success;
if (is_positive()) {
result = ActionNode::BeginSubmatch(
stack_pointer_register, position_register,
body()->ToNode(compiler,
ActionNode::PositiveSubmatchSuccess(
stack_pointer_register, position_register,
register_count, register_start, on_success)));
RegExpNode* node = ActionNode::BeginSubmatch(
stack_pointer_register,
position_register,
body()->ToNode(
compiler,
ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
position_register,
register_count,
register_start,
on_success)));
return node;
} else {
// We use a ChoiceNode for a negative lookahead because it has most of
// the characteristics we need. It has the body of the lookahead as its
@ -5383,18 +5374,21 @@ RegExpNode* RegExpLookaround::ToNode(RegExpCompiler* compiler,
Zone* zone = compiler->zone();
GuardedAlternative body_alt(
body()->ToNode(compiler, new (zone) NegativeSubmatchSuccess(
stack_pointer_register, position_register,
register_count, register_start, zone)));
body()->ToNode(
compiler,
success = new(zone) NegativeSubmatchSuccess(stack_pointer_register,
position_register,
register_count,
register_start,
zone)));
ChoiceNode* choice_node =
new(zone) NegativeLookaheadChoiceNode(body_alt,
GuardedAlternative(on_success),
zone);
result = ActionNode::BeginSubmatch(stack_pointer_register,
position_register, choice_node);
return ActionNode::BeginSubmatch(stack_pointer_register,
position_register,
choice_node);
}
compiler->set_read_backward(was_reading_backward);
return result;
}
@ -5408,10 +5402,8 @@ RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
int index,
RegExpCompiler* compiler,
RegExpNode* on_success) {
DCHECK_NOT_NULL(body);
int start_reg = RegExpCapture::StartRegister(index);
int end_reg = RegExpCapture::EndRegister(index);
if (compiler->read_backward()) std::swap(start_reg, end_reg);
RegExpNode* store_end = ActionNode::StorePosition(end_reg, true, on_success);
RegExpNode* body_node = body->ToNode(compiler, store_end);
return ActionNode::StorePosition(start_reg, true, body_node);
@ -5422,14 +5414,8 @@ RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
RegExpNode* on_success) {
ZoneList<RegExpTree*>* children = nodes();
RegExpNode* current = on_success;
if (compiler->read_backward()) {
for (int i = 0; i < children->length(); i++) {
current = children->at(i)->ToNode(compiler, current);
}
} else {
for (int i = children->length() - 1; i >= 0; i--) {
current = children->at(i)->ToNode(compiler, current);
}
for (int i = children->length() - 1; i >= 0; i--) {
current = children->at(i)->ToNode(compiler, current);
}
return current;
}
@ -6305,17 +6291,22 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(
if (!is_start_anchored && !is_sticky) {
// Add a .*? at the beginning, outside the body capture, unless
// this expression is anchored at the beginning or sticky.
RegExpNode* loop_node = RegExpQuantifier::ToNode(
0, RegExpTree::kInfinity, false, new (zone) RegExpCharacterClass('*'),
&compiler, captured_body, data->contains_anchor);
RegExpNode* loop_node =
RegExpQuantifier::ToNode(0,
RegExpTree::kInfinity,
false,
new(zone) RegExpCharacterClass('*'),
&compiler,
captured_body,
data->contains_anchor);
if (data->contains_anchor) {
// Unroll loop once, to take care of the case that might start
// at the start of input.
ChoiceNode* first_step_node = new(zone) ChoiceNode(2, zone);
first_step_node->AddAlternative(GuardedAlternative(captured_body));
first_step_node->AddAlternative(GuardedAlternative(new (zone) TextNode(
new (zone) RegExpCharacterClass('*'), false, loop_node)));
first_step_node->AddAlternative(GuardedAlternative(
new(zone) TextNode(new(zone) RegExpCharacterClass('*'), loop_node)));
node = first_step_node;
} else {
node = loop_node;

View File

@ -387,17 +387,17 @@ class DispatchTable : public ZoneObject {
VISIT(Text)
#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
VISIT(Disjunction) \
VISIT(Alternative) \
VISIT(Assertion) \
VISIT(CharacterClass) \
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
VISIT(Lookaround) \
VISIT(BackReference) \
VISIT(Empty) \
#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
VISIT(Disjunction) \
VISIT(Alternative) \
VISIT(Assertion) \
VISIT(CharacterClass) \
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
VISIT(Lookahead) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
@ -603,7 +603,7 @@ class RegExpNode: public ZoneObject {
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) = 0;
static const int kNodeIsTooComplexForGreedyLoops = kMinInt;
static const int kNodeIsTooComplexForGreedyLoops = -1;
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
// Only returns the successor for a text node of length 1 that matches any
// character and that has no guards on it.
@ -827,14 +827,14 @@ class ActionNode: public SeqRegExpNode {
class TextNode: public SeqRegExpNode {
public:
TextNode(ZoneList<TextElement>* elms, bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success), elms_(elms), read_backward_(read_backward) {}
TextNode(RegExpCharacterClass* that, bool read_backward,
TextNode(ZoneList<TextElement>* elms,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(new (zone()) ZoneList<TextElement>(1, zone())),
read_backward_(read_backward) {
elms_(elms) { }
TextNode(RegExpCharacterClass* that,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(new(zone()) ZoneList<TextElement>(1, zone())) {
elms_->Add(TextElement::CharClass(that), zone());
}
virtual void Accept(NodeVisitor* visitor);
@ -845,7 +845,6 @@ class TextNode: public SeqRegExpNode {
int characters_filled_in,
bool not_at_start);
ZoneList<TextElement>* elements() { return elms_; }
bool read_backward() { return read_backward_; }
void MakeCaseIndependent(Isolate* isolate, bool is_one_byte);
virtual int GreedyLoopTextLength();
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
@ -874,7 +873,6 @@ class TextNode: public SeqRegExpNode {
int* checked_up_to);
int Length();
ZoneList<TextElement>* elms_;
bool read_backward_;
};
@ -927,16 +925,15 @@ class AssertionNode: public SeqRegExpNode {
class BackReferenceNode: public SeqRegExpNode {
public:
BackReferenceNode(int start_reg, int end_reg, bool read_backward,
BackReferenceNode(int start_reg,
int end_reg,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
start_reg_(start_reg),
end_reg_(end_reg),
read_backward_(read_backward) {}
end_reg_(end_reg) { }
virtual void Accept(NodeVisitor* visitor);
int start_register() { return start_reg_; }
int end_register() { return end_reg_; }
bool read_backward() { return read_backward_; }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
@ -953,7 +950,6 @@ class BackReferenceNode: public SeqRegExpNode {
private:
int start_reg_;
int end_reg_;
bool read_backward_;
};
@ -1078,7 +1074,6 @@ class ChoiceNode: public RegExpNode {
return true;
}
virtual RegExpNode* FilterOneByte(int depth, bool ignore_case);
virtual bool read_backward() { return false; }
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
@ -1155,12 +1150,12 @@ class NegativeLookaheadChoiceNode: public ChoiceNode {
class LoopChoiceNode: public ChoiceNode {
public:
LoopChoiceNode(bool body_can_be_zero_length, bool read_backward, Zone* zone)
explicit LoopChoiceNode(bool body_can_be_zero_length, Zone* zone)
: ChoiceNode(2, zone),
loop_node_(NULL),
continue_node_(NULL),
body_can_be_zero_length_(body_can_be_zero_length),
read_backward_(read_backward) {}
body_can_be_zero_length_(body_can_be_zero_length)
{ }
void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
@ -1174,7 +1169,6 @@ class LoopChoiceNode: public ChoiceNode {
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
virtual bool read_backward() { return read_backward_; }
virtual void Accept(NodeVisitor* visitor);
virtual RegExpNode* FilterOneByte(int depth, bool ignore_case);
@ -1189,7 +1183,6 @@ class LoopChoiceNode: public ChoiceNode {
RegExpNode* loop_node_;
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
bool read_backward_;
};
@ -1445,7 +1438,9 @@ class Trace {
at_start_ == UNKNOWN;
}
TriBool at_start() { return at_start_; }
void set_at_start(TriBool at_start) { at_start_ = at_start; }
void set_at_start(bool at_start) {
at_start_ = at_start ? TRUE_VALUE : FALSE_VALUE;
}
Label* backtrack() { return backtrack_; }
Label* loop_label() { return loop_label_; }
RegExpNode* stop_node() { return stop_node_; }

View File

@ -181,17 +181,26 @@ void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
__ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Addu(a0, current_input_offset(), Operand(-char_size()));
Label not_at_start;
// Did we start the match at the start of the string at all?
__ lw(a0, MemOperand(frame_pointer(), kStartIndex));
BranchOrBacktrack(&not_at_start, ne, a0, Operand(zero_reg));
// If we did, are we still at the start of the input?
__ lw(a1, MemOperand(frame_pointer(), kInputStart));
__ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
__ bind(&not_at_start);
}
void RegExpMacroAssemblerMIPS::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Addu(a0, current_input_offset(),
Operand(-char_size() + cp_offset * char_size()));
void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ lw(a0, MemOperand(frame_pointer(), kStartIndex));
BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg));
// If we did, are we still at the start of the input?
__ lw(a1, MemOperand(frame_pointer(), kInputStart));
__ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
}
@ -214,26 +223,20 @@ void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
__ lw(a0, register_location(start_reg)); // Index of start of capture.
__ lw(a1, register_location(start_reg + 1)); // Index of end of capture.
__ Subu(a1, a1, a0); // Length of capture.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// If length is zero, either the capture is empty or it is not participating.
// In either case succeed immediately.
__ Branch(&fallthrough, eq, a1, Operand(zero_reg));
if (read_backward) {
__ lw(t0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Addu(t0, t0, a1);
BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t0));
} else {
__ Addu(t5, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
}
__ Addu(t5, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
if (mode_ == LATIN1) {
Label success;
@ -244,9 +247,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
// a1 - length of capture.
__ Addu(a0, a0, Operand(end_of_input_address()));
__ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
if (read_backward) {
__ Subu(a2, a2, Operand(a1));
}
__ Addu(a1, a0, Operand(a1));
// a0 - Address of start of capture.
@ -285,12 +285,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
__ bind(&success);
// Compute new value of character position after the matched part.
__ Subu(current_input_offset(), a2, end_of_input_address());
if (read_backward) {
__ lw(t0, register_location(start_reg)); // Index of start of capture.
__ lw(t5, register_location(start_reg + 1)); // Index of end of capture.
__ Addu(current_input_offset(), current_input_offset(), Operand(t0));
__ Subu(current_input_offset(), current_input_offset(), Operand(t5));
}
} else {
DCHECK(mode_ == UC16);
// Put regexp engine registers on stack.
@ -319,9 +313,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
__ mov(s3, a1);
// Address of current input position.
__ Addu(a1, current_input_offset(), Operand(end_of_input_address()));
if (read_backward) {
__ Subu(a1, a1, Operand(s3));
}
// Isolate.
__ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
@ -339,21 +330,17 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
// Check if function returned non-zero for success or zero for failure.
BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
// On success, advance position by length of capture.
if (read_backward) {
__ Subu(current_input_offset(), current_input_offset(), Operand(s3));
} else {
__ Addu(current_input_offset(), current_input_offset(), Operand(s3));
}
// On success, increment position by length of capture.
__ Addu(current_input_offset(), current_input_offset(), Operand(s3));
}
__ bind(&fallthrough);
}
void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerMIPS::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
Label success;
@ -361,35 +348,17 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
__ lw(a0, register_location(start_reg));
__ lw(a1, register_location(start_reg + 1));
__ Subu(a1, a1, a0); // Length to check.
// Succeed on empty capture (including no capture).
__ Branch(&fallthrough, eq, a1, Operand(zero_reg));
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
__ Branch(&fallthrough, le, a1, Operand(zero_reg));
__ Addu(t5, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
if (read_backward) {
__ lw(t0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Addu(t0, t0, a1);
BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t0));
} else {
__ Addu(t5, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
}
// a0 - offset of start of capture.
// a1 - length of capture.
// Compute pointers to match string and capture string.
__ Addu(a0, a0, Operand(end_of_input_address()));
__ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
if (read_backward) {
__ Subu(a2, a2, Operand(a1));
}
__ Addu(a1, a0, Operand(a1));
// a0 - Address of start of capture.
// a1 - Address of end of capture.
// a2 - Address of current input position.
__ Addu(a1, a1, Operand(a0));
Label loop;
__ bind(&loop);
@ -410,12 +379,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
// Move current character position to position after match.
__ Subu(current_input_offset(), a2, end_of_input_address());
if (read_backward) {
__ lw(t0, register_location(start_reg)); // Index of start of capture.
__ lw(t5, register_location(start_reg + 1)); // Index of end of capture.
__ Addu(current_input_offset(), current_input_offset(), Operand(t0));
__ Subu(current_input_offset(), current_input_offset(), Operand(t5));
}
__ bind(&fallthrough);
}
@ -636,7 +599,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
__ mov(a0, zero_reg);
__ push(a0); // Make room for success counter and initialize it to 0.
__ push(a0); // Make room for "string start - 1" constant.
__ push(a0); // Make room for "position - 1" constant (value irrelevant).
// Check if we have space on the stack for registers.
Label stack_limit_hit;
@ -679,7 +642,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ Subu(a0, a0, t5);
// Store this value in a local variable, for use when clearing
// position registers.
__ sw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
// Initialize code pointer register
__ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
@ -788,7 +751,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ sw(a2, MemOperand(frame_pointer(), kRegisterOutput));
// Prepare a0 to initialize registers with its value in the next run.
__ lw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
if (global_with_zero_length_check()) {
// Special case for zero-length matches.
@ -942,13 +905,10 @@ void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input,
bool check_bounds,
int characters) {
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1056,7 +1016,7 @@ void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
DCHECK(reg_from <= reg_to);
__ lw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
for (int reg = reg_from; reg <= reg_to; reg++) {
__ sw(a0, register_location(reg));
}
@ -1169,14 +1129,10 @@ MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
BranchOrBacktrack(on_outside_input, ge, current_input_offset(),
Operand(-cp_offset * char_size()));
} else {
__ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
BranchOrBacktrack(on_outside_input, le, a0, Operand(a1));
}
BranchOrBacktrack(on_outside_input,
ge,
current_input_offset(),
Operand(-cp_offset * char_size()));
}

View File

@ -33,11 +33,9 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(uint32_t c,
@ -122,9 +120,9 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kSuccessfulCaptures = kInputString - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;

View File

@ -61,7 +61,7 @@ namespace internal {
* - fp[-16] void* input_string (location of a handle containing the string).
* - fp[-20] success counter (only for global regexps to count matches).
* - fp[-24] Offset of location before start of input (effectively character
* string start - 1). Used to initialize capture registers to a
* position -1). Used to initialize capture registers to a
* non-position.
* - fp[-28] At start (if 1, we are starting at the start of the
* string, otherwise 0)
@ -91,7 +91,7 @@ namespace internal {
* - fp[-56] start index (character index of start). kStartIndex
* - fp[-64] void* input_string (location of a handle containing the string). kInputString
* - fp[-72] success counter (only for global regexps to count matches). kSuccessfulCaptures
* - fp[-80] Offset of location before start of input (effectively character kStringStartMinusOne
* - fp[-80] Offset of location before start of input (effectively character kInputStartMinusOne
* position -1). Used to initialize capture registers to a
* non-position.
* --------- The following output registers are 32-bit values. ---------
@ -217,17 +217,26 @@ void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
__ ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Daddu(a0, current_input_offset(), Operand(-char_size()));
Label not_at_start;
// Did we start the match at the start of the string at all?
__ ld(a0, MemOperand(frame_pointer(), kStartIndex));
BranchOrBacktrack(&not_at_start, ne, a0, Operand(zero_reg));
// If we did, are we still at the start of the input?
__ ld(a1, MemOperand(frame_pointer(), kInputStart));
__ Daddu(a0, end_of_input_address(), Operand(current_input_offset()));
BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
__ bind(&not_at_start);
}
void RegExpMacroAssemblerMIPS::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Daddu(a0, current_input_offset(),
Operand(-char_size() + cp_offset * char_size()));
void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ ld(a0, MemOperand(frame_pointer(), kStartIndex));
BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg));
// If we did, are we still at the start of the input?
__ ld(a1, MemOperand(frame_pointer(), kInputStart));
__ Daddu(a0, end_of_input_address(), Operand(current_input_offset()));
BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
}
@ -250,26 +259,20 @@ void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
__ ld(a0, register_location(start_reg)); // Index of start of capture.
__ ld(a1, register_location(start_reg + 1)); // Index of end of capture.
__ Dsubu(a1, a1, a0); // Length of capture.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// If length is zero, either the capture is empty or it is not participating.
// In either case succeed immediately.
__ Branch(&fallthrough, eq, a1, Operand(zero_reg));
if (read_backward) {
__ ld(t1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Daddu(t1, t1, a1);
BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
} else {
__ Daddu(t1, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
}
__ Daddu(t1, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
if (mode_ == LATIN1) {
Label success;
@ -280,9 +283,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
// a1 - length of capture.
__ Daddu(a0, a0, Operand(end_of_input_address()));
__ Daddu(a2, end_of_input_address(), Operand(current_input_offset()));
if (read_backward) {
__ Dsubu(a2, a2, Operand(a1));
}
__ Daddu(a1, a0, Operand(a1));
// a0 - Address of start of capture.
@ -321,12 +321,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
__ bind(&success);
// Compute new value of character position after the matched part.
__ Dsubu(current_input_offset(), a2, end_of_input_address());
if (read_backward) {
__ ld(t1, register_location(start_reg)); // Index of start of capture.
__ ld(a2, register_location(start_reg + 1)); // Index of end of capture.
__ Daddu(current_input_offset(), current_input_offset(), Operand(t1));
__ Dsubu(current_input_offset(), current_input_offset(), Operand(a2));
}
} else {
DCHECK(mode_ == UC16);
// Put regexp engine registers on stack.
@ -355,9 +349,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
__ mov(s3, a1);
// Address of current input position.
__ Daddu(a1, current_input_offset(), Operand(end_of_input_address()));
if (read_backward) {
__ Dsubu(a1, a1, Operand(s3));
}
// Isolate.
__ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
@ -376,20 +367,16 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
// Check if function returned non-zero for success or zero for failure.
BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
// On success, increment position by length of capture.
if (read_backward) {
__ Dsubu(current_input_offset(), current_input_offset(), Operand(s3));
} else {
__ Daddu(current_input_offset(), current_input_offset(), Operand(s3));
}
__ Daddu(current_input_offset(), current_input_offset(), Operand(s3));
}
__ bind(&fallthrough);
}
void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerMIPS::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
Label success;
@ -397,28 +384,16 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
__ ld(a0, register_location(start_reg));
__ ld(a1, register_location(start_reg + 1));
__ Dsubu(a1, a1, a0); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// Succeed on empty capture (including no capture).
__ Branch(&fallthrough, eq, a1, Operand(zero_reg));
if (read_backward) {
__ ld(t1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Daddu(t1, t1, a1);
BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
} else {
__ Daddu(t1, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
}
__ Daddu(t1, a1, current_input_offset());
// Check that there are enough characters left in the input.
BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
// Compute pointers to match string and capture string.
__ Daddu(a0, a0, Operand(end_of_input_address()));
__ Daddu(a2, end_of_input_address(), Operand(current_input_offset()));
if (read_backward) {
__ Dsubu(a2, a2, Operand(a1));
}
__ Daddu(a1, a1, Operand(a0));
Label loop;
@ -440,12 +415,6 @@ void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
// Move current character position to position after match.
__ Dsubu(current_input_offset(), a2, end_of_input_address());
if (read_backward) {
__ ld(t1, register_location(start_reg)); // Index of start of capture.
__ ld(a2, register_location(start_reg + 1)); // Index of end of capture.
__ Daddu(current_input_offset(), current_input_offset(), Operand(t1));
__ Dsubu(current_input_offset(), current_input_offset(), Operand(a2));
}
__ bind(&fallthrough);
}
@ -675,7 +644,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ Daddu(frame_pointer(), sp, Operand(8 * kPointerSize));
__ mov(a0, zero_reg);
__ push(a0); // Make room for success counter and initialize it to 0.
__ push(a0); // Make room for "string start - 1" constant.
__ push(a0); // Make room for "position - 1" constant (value irrelevant).
// Check if we have space on the stack for registers.
Label stack_limit_hit;
@ -718,7 +687,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ Dsubu(a0, a0, t1);
// Store this value in a local variable, for use when clearing
// position registers.
__ sd(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ sd(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
// Initialize code pointer register
__ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
@ -828,7 +797,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
__ sd(a2, MemOperand(frame_pointer(), kRegisterOutput));
// Prepare a0 to initialize registers with its value in the next run.
__ ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ ld(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
if (global_with_zero_length_check()) {
// Special case for zero-length matches.
@ -982,13 +951,10 @@ void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input,
bool check_bounds,
int characters) {
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1096,7 +1062,7 @@ void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
DCHECK(reg_from <= reg_to);
__ ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
__ ld(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
for (int reg = reg_from; reg <= reg_to; reg++) {
__ sd(a0, register_location(reg));
}
@ -1209,14 +1175,10 @@ MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
BranchOrBacktrack(on_outside_input, ge, current_input_offset(),
Operand(-cp_offset * char_size()));
} else {
__ ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
__ Daddu(a0, current_input_offset(), Operand(cp_offset * char_size()));
BranchOrBacktrack(on_outside_input, le, a0, Operand(a1));
}
BranchOrBacktrack(on_outside_input,
ge,
current_input_offset(),
Operand(-cp_offset * char_size()));
}

View File

@ -33,11 +33,9 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(uint32_t c,
@ -127,9 +125,9 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kSuccessfulCaptures = kInputString - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
#elif defined(MIPS_ABI_O32)
// Offsets from frame_pointer() of function parameters and stored registers.
@ -160,9 +158,9 @@ class RegExpMacroAssemblerMIPS: public NativeRegExpMacroAssembler {
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kSuccessfulCaptures = kInputString - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
#else
# error "undefined MIPS ABI"

View File

@ -273,9 +273,8 @@ void RegExpMacroAssemblerIrregexp::CheckAtStart(Label* on_at_start) {
}
void RegExpMacroAssemblerIrregexp::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
Emit(BC_CHECK_NOT_AT_START, cp_offset);
void RegExpMacroAssemblerIrregexp::CheckNotAtStart(Label* on_not_at_start) {
Emit(BC_CHECK_NOT_AT_START, 0);
EmitOrLink(on_not_at_start);
}
@ -371,23 +370,20 @@ void RegExpMacroAssemblerIrregexp::CheckBitInTable(
void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_not_equal) {
DCHECK(start_reg >= 0);
DCHECK(start_reg <= kMaxRegister);
Emit(read_backward ? BC_CHECK_NOT_BACK_REF_BACKWARD : BC_CHECK_NOT_BACK_REF,
start_reg);
Emit(BC_CHECK_NOT_BACK_REF, start_reg);
EmitOrLink(on_not_equal);
}
void RegExpMacroAssemblerIrregexp::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_not_equal) {
int start_reg,
Label* on_not_equal) {
DCHECK(start_reg >= 0);
DCHECK(start_reg <= kMaxRegister);
Emit(read_backward ? BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD
: BC_CHECK_NOT_BACK_REF_NO_CASE,
start_reg);
Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg);
EmitOrLink(on_not_equal);
}

View File

@ -66,7 +66,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckAtStart(Label* on_at_start);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(unsigned c,
unsigned mask,
@ -82,10 +82,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
uc16 to,
Label* on_not_in_range);
virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void IfRegisterLT(int register_index, int comparand, Label* if_lt);
virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);

View File

@ -13,9 +13,9 @@ RegExpMacroAssemblerTracer::RegExpMacroAssemblerTracer(
Isolate* isolate, RegExpMacroAssembler* assembler)
: RegExpMacroAssembler(isolate, assembler->zone()), assembler_(assembler) {
unsigned int type = assembler->Implementation();
DCHECK(type < 8);
const char* impl_names[] = {"IA32", "ARM", "ARM64", "MIPS",
"PPC", "X64", "X87", "Bytecode"};
DCHECK(type < 6);
const char* impl_names[] = {"IA32", "ARM", "ARM64",
"MIPS", "X64", "X87", "Bytecode"};
PrintF("RegExpMacroAssembler%s();\n", impl_names[type]);
}
@ -241,11 +241,9 @@ void RegExpMacroAssemblerTracer::CheckAtStart(Label* on_at_start) {
}
void RegExpMacroAssemblerTracer::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
PrintF(" CheckNotAtStart(cp_offset=%d, label[%08x]);\n", cp_offset,
LabelToInt(on_not_at_start));
assembler_->CheckNotAtStart(cp_offset, on_not_at_start);
void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) {
PrintF(" CheckNotAtStart(label[%08x]);\n", LabelToInt(on_not_at_start));
assembler_->CheckNotAtStart(on_not_at_start);
}
@ -351,21 +349,19 @@ void RegExpMacroAssemblerTracer::CheckBitInTable(
void RegExpMacroAssemblerTracer::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
PrintF(" CheckNotBackReference(register=%d, %s, label[%08x]);\n", start_reg,
read_backward ? "backward" : "forward", LabelToInt(on_no_match));
assembler_->CheckNotBackReference(start_reg, read_backward, on_no_match);
PrintF(" CheckNotBackReference(register=%d, label[%08x]);\n", start_reg,
LabelToInt(on_no_match));
assembler_->CheckNotBackReference(start_reg, on_no_match);
}
void RegExpMacroAssemblerTracer::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
PrintF(" CheckNotBackReferenceIgnoreCase(register=%d, %s, label[%08x]);\n",
start_reg, read_backward ? "backward" : "forward",
LabelToInt(on_no_match));
assembler_->CheckNotBackReferenceIgnoreCase(start_reg, read_backward,
on_no_match);
int start_reg,
Label* on_no_match) {
PrintF(" CheckNotBackReferenceIgnoreCase(register=%d, label[%08x]);\n",
start_reg, LabelToInt(on_no_match));
assembler_->CheckNotBackReferenceIgnoreCase(start_reg, on_no_match);
}

View File

@ -30,11 +30,9 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(unsigned c,

View File

@ -71,11 +71,9 @@ class RegExpMacroAssembler {
virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position) = 0;
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start) = 0;
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match) = 0;
virtual void CheckNotAtStart(Label* on_not_at_start) = 0;
virtual void CheckNotBackReference(int start_reg, Label* on_no_match) = 0;
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match) = 0;
// Check the current character for a match with a literal character. If we
// fail to match then goto the on_failure label. End of input always

View File

@ -64,8 +64,7 @@ namespace internal {
* - backup of callee save registers (rbx, possibly rsi and rdi).
* - success counter (only useful for global regexp to count matches)
* - Offset of location before start of input (effectively character
* string start - 1). Used to initialize capture registers to a
* non-position.
* position -1). Used to initialize capture registers to a non-position.
* - At start of string (if 1, we are starting at the start of the
* string, otherwise 0)
* - register 0 rbp[-n] (Only positions must be stored in the first
@ -172,16 +171,25 @@ void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
__ leap(rax, Operand(rdi, -char_size()));
__ cmpp(rax, Operand(rbp, kStringStartMinusOne));
Label not_at_start;
// Did we start the match at the start of the string at all?
__ cmpl(Operand(rbp, kStartIndex), Immediate(0));
BranchOrBacktrack(not_equal, &not_at_start);
// If we did, are we still at the start of the input?
__ leap(rax, Operand(rsi, rdi, times_1, 0));
__ cmpp(rax, Operand(rbp, kInputStart));
BranchOrBacktrack(equal, on_at_start);
__ bind(&not_at_start);
}
void RegExpMacroAssemblerX64::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ leap(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
__ cmpp(rax, Operand(rbp, kStringStartMinusOne));
void RegExpMacroAssemblerX64::CheckNotAtStart(Label* on_not_at_start) {
// Did we start the match at the start of the string at all?
__ cmpl(Operand(rbp, kStartIndex), Immediate(0));
BranchOrBacktrack(not_equal, on_not_at_start);
// If we did, are we still at the start of the input?
__ leap(rax, Operand(rsi, rdi, times_1, 0));
__ cmpp(rax, Operand(rbp, kInputStart));
BranchOrBacktrack(not_equal, on_not_at_start);
}
@ -203,7 +211,8 @@ void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
int start_reg, bool read_backward, Label* on_no_match) {
int start_reg,
Label* on_no_match) {
Label fallthrough;
ReadPositionFromRegister(rdx, start_reg); // Offset of start of capture
ReadPositionFromRegister(rbx, start_reg + 1); // Offset of end of capture
@ -213,25 +222,23 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
// rdx = Start offset of capture.
// rbx = Length of capture
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// If length is negative, this code will fail (it's a symptom of a partial or
// illegal capture where start of capture after end of capture).
// This must not happen (no back-reference can reference a capture that wasn't
// closed before in the reg-exp, and we must not generate code that can cause
// this condition).
// If length is zero, either the capture is empty or it is nonparticipating.
// In either case succeed immediately.
__ j(equal, &fallthrough);
// -----------------------
// rdx - Start of capture
// rbx - length of capture
// Check that there are sufficient characters left in the input.
if (read_backward) {
__ movl(rax, Operand(rbp, kStringStartMinusOne));
__ addl(rax, rbx);
__ cmpl(rdi, rax);
BranchOrBacktrack(less_equal, on_no_match);
} else {
__ movl(rax, rdi);
__ addl(rax, rbx);
BranchOrBacktrack(greater, on_no_match);
}
__ movl(rax, rdi);
__ addl(rax, rbx);
BranchOrBacktrack(greater, on_no_match);
if (mode_ == LATIN1) {
Label loop_increment;
@ -241,9 +248,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
__ leap(r9, Operand(rsi, rdx, times_1, 0));
__ leap(r11, Operand(rsi, rdi, times_1, 0));
if (read_backward) {
__ subp(r11, rbx); // Offset by length when matching backwards.
}
__ addp(rbx, r9); // End of capture
// ---------------------
// r11 - current input character address
@ -286,11 +290,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
// Compute new value of character position after the matched part.
__ movp(rdi, r11);
__ subq(rdi, rsi);
if (read_backward) {
// Subtract match length if we matched backward.
__ addq(rdi, register_location(start_reg));
__ subq(rdi, register_location(start_reg + 1));
}
} else {
DCHECK(mode_ == UC16);
// Save important/volatile registers before calling C function.
@ -314,9 +313,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
__ leap(rcx, Operand(rsi, rdx, times_1, 0));
// Set byte_offset2.
__ leap(rdx, Operand(rsi, rdi, times_1, 0));
if (read_backward) {
__ subq(rdx, rbx);
}
// Set byte_length.
__ movp(r8, rbx);
// Isolate.
@ -328,9 +324,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
__ leap(rdi, Operand(rsi, rdx, times_1, 0));
// Set byte_offset2.
__ movp(rsi, rax);
if (read_backward) {
__ subq(rsi, rbx);
}
// Set byte_length.
__ movp(rdx, rbx);
// Isolate.
@ -356,21 +349,17 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
// Check if function returned non-zero for success or zero for failure.
__ testp(rax, rax);
BranchOrBacktrack(zero, on_no_match);
// On success, advance position by length of capture.
// On success, increment position by length of capture.
// Requires that rbx is callee save (true for both Win64 and AMD64 ABIs).
if (read_backward) {
__ subq(rdi, rbx);
} else {
__ addq(rdi, rbx);
}
__ addq(rdi, rbx);
}
__ bind(&fallthrough);
}
void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
bool read_backward,
Label* on_no_match) {
void RegExpMacroAssemblerX64::CheckNotBackReference(
int start_reg,
Label* on_no_match) {
Label fallthrough;
// Find length of back-referenced capture.
@ -378,31 +367,25 @@ void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
ReadPositionFromRegister(rax, start_reg + 1); // Offset of end of capture
__ subp(rax, rdx); // Length to check.
// At this point, the capture registers are either both set or both cleared.
// If the capture length is zero, then the capture is either empty or cleared.
// Fall through in both cases.
// Fail on partial or illegal capture (start of capture after end of capture).
// This must not happen (no back-reference can reference a capture that wasn't
// closed before in the reg-exp).
__ Check(greater_equal, kInvalidCaptureReferenced);
// Succeed on empty capture (including non-participating capture)
__ j(equal, &fallthrough);
// -----------------------
// rdx - Start of capture
// rax - length of capture
// Check that there are sufficient characters left in the input.
if (read_backward) {
__ movl(rbx, Operand(rbp, kStringStartMinusOne));
__ addl(rbx, rax);
__ cmpl(rdi, rbx);
BranchOrBacktrack(less_equal, on_no_match);
} else {
__ movl(rbx, rdi);
__ addl(rbx, rax);
BranchOrBacktrack(greater, on_no_match);
}
__ movl(rbx, rdi);
__ addl(rbx, rax);
BranchOrBacktrack(greater, on_no_match);
// Compute pointers to match string and capture string
__ leap(rbx, Operand(rsi, rdi, times_1, 0)); // Start of match.
if (read_backward) {
__ subq(rbx, rax); // Offset by length when matching backwards.
}
__ addp(rdx, rsi); // Start of capture.
__ leap(r9, Operand(rdx, rax, times_1, 0)); // End of capture
@ -433,11 +416,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReference(int start_reg,
// Set current character position to position after match.
__ movp(rdi, rbx);
__ subq(rdi, rsi);
if (read_backward) {
// Subtract match length if we matched backward.
__ addq(rdi, register_location(start_reg));
__ subq(rdi, register_location(start_reg + 1));
}
__ bind(&fallthrough);
}
@ -704,7 +682,7 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
#endif
__ Push(Immediate(0)); // Number of successful matches in a global regexp.
__ Push(Immediate(0)); // Make room for "string start - 1" constant.
__ Push(Immediate(0)); // Make room for "input start - 1" constant.
// Check if we have space on the stack for registers.
Label stack_limit_hit;
@ -754,7 +732,7 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
}
// Store this value in a local variable, for use when clearing
// position registers.
__ movp(Operand(rbp, kStringStartMinusOne), rax);
__ movp(Operand(rbp, kInputStartMinusOne), rax);
#if V8_OS_WIN
// Ensure that we have written to each stack page, in order. Skipping a page
@ -857,7 +835,7 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
Immediate(num_saved_registers_ * kIntSize));
// Prepare rax to initialize registers with its value in the next run.
__ movp(rax, Operand(rbp, kStringStartMinusOne));
__ movp(rax, Operand(rbp, kInputStartMinusOne));
if (global_with_zero_length_check()) {
// Special case for zero-length matches.
@ -1040,13 +1018,10 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input,
bool check_bounds,
int characters) {
DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
CheckPosition(cp_offset + characters - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
CheckPosition(cp_offset + characters - 1, on_end_of_input);
}
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
@ -1149,7 +1124,7 @@ void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(int reg,
void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) {
DCHECK(reg_from <= reg_to);
__ movp(rax, Operand(rbp, kStringStartMinusOne));
__ movp(rax, Operand(rbp, kInputStartMinusOne));
for (int reg = reg_from; reg <= reg_to; reg++) {
__ movp(register_location(reg), rax);
}
@ -1230,14 +1205,8 @@ Operand RegExpMacroAssemblerX64::register_location(int register_index) {
void RegExpMacroAssemblerX64::CheckPosition(int cp_offset,
Label* on_outside_input) {
if (cp_offset >= 0) {
__ cmpl(rdi, Immediate(-cp_offset * char_size()));
BranchOrBacktrack(greater_equal, on_outside_input);
} else {
__ leap(rax, Operand(rdi, cp_offset * char_size()));
__ cmpp(rax, Operand(rbp, kStringStartMinusOne));
BranchOrBacktrack(less_equal, on_outside_input);
}
__ cmpl(rdi, Immediate(-cp_offset * char_size()));
BranchOrBacktrack(greater_equal, on_outside_input);
}

View File

@ -34,11 +34,9 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
bool read_backward,
Label* on_no_match);
virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(uint32_t c,
@ -173,10 +171,10 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
static const int kSuccessfulCaptures = kLastCalleeSaveRegister - kPointerSize;
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize;
// First register address. Following registers are below it on the stack.
static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;

View File

@ -159,10 +159,7 @@ static MinMaxPair CheckMinMaxMatch(const char* input) {
CHECK_EQ(max, min_max.max_match); \
}
void TestRegExpParser(bool lookbehind) {
FLAG_harmony_regexp_lookbehind = lookbehind;
TEST(Parser) {
CHECK_PARSE_ERROR("?");
CheckParseEq("abc", "'abc'");
@ -194,13 +191,6 @@ void TestRegExpParser(bool lookbehind) {
CheckParseEq("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
CheckParseEq("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
CheckParseEq("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')");
if (lookbehind) {
CheckParseEq("foo(?<=bar)baz", "(: 'foo' (<- + 'bar') 'baz')");
CheckParseEq("foo(?<!bar)baz", "(: 'foo' (<- - 'bar') 'baz')");
} else {
CHECK_PARSE_ERROR("foo(?<=bar)baz");
CHECK_PARSE_ERROR("foo(?<!bar)baz");
}
CheckParseEq("()", "(^ %)");
CheckParseEq("(?=)", "(-> + %)");
CheckParseEq("[]", "^[\\x00-\\uffff]"); // Doesn't compile on windows
@ -277,16 +267,9 @@ void TestRegExpParser(bool lookbehind) {
CheckParseEq("(?=a){1,10}a", "(: (-> + 'a') 'a')");
CheckParseEq("(?=a){9,10}a", "(: (-> + 'a') 'a')");
CheckParseEq("(?!a)?a", "'a'");
CheckParseEq("\\1(a)", "(: (<- 1) (^ 'a'))");
CheckParseEq("\\1(a)", "(^ 'a')");
CheckParseEq("(?!(a))\\1", "(: (-> - (^ 'a')) (<- 1))");
CheckParseEq("(?!\\1(a\\1)\\1)\\1",
"(: (-> - (: (<- 1) (^ 'a') (<- 1))) (<- 1))");
CheckParseEq("\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1",
"(: (<- 1) (<- 2) (^ (: 'a' (^ 'b') (<- 2))) (<- 1))");
if (lookbehind) {
CheckParseEq("\\1\\2(a(?<=\\1(b\\1\\2))\\2)\\1",
"(: (<- 1) (<- 2) (^ (: 'a' (<- + (^ 'b')) (<- 2))) (<- 1))");
}
CheckParseEq("(?!\\1(a\\1)\\1)\\1", "(: (-> - (: (^ 'a') (<- 1))) (<- 1))");
CheckParseEq("[\\0]", "[\\x00]");
CheckParseEq("[\\11]", "[\\x09]");
CheckParseEq("[\\11a]", "[\\x09 a]");
@ -417,16 +400,6 @@ void TestRegExpParser(bool lookbehind) {
}
TEST(ParserWithLookbehind) {
TestRegExpParser(true); // Lookbehind enabled.
}
TEST(ParserWithoutLookbehind) {
TestRegExpParser(true); // Lookbehind enabled.
}
TEST(ParserRegression) {
CheckParseEq("[A-Z$-][x]", "(! [A-Z $ -] [x])");
CheckParseEq("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')");
@ -817,7 +790,7 @@ TEST(MacroAssemblerNativeSimple) {
Label fail, backtrack;
m.PushBacktrack(&fail);
m.CheckNotAtStart(0, NULL);
m.CheckNotAtStart(NULL);
m.LoadCurrentCharacter(2, NULL);
m.CheckNotCharacter('o', NULL);
m.LoadCurrentCharacter(1, NULL, false);
@ -884,7 +857,7 @@ TEST(MacroAssemblerNativeSimpleUC16) {
Label fail, backtrack;
m.PushBacktrack(&fail);
m.CheckNotAtStart(0, NULL);
m.CheckNotAtStart(NULL);
m.LoadCurrentCharacter(2, NULL);
m.CheckNotCharacter('o', NULL);
m.LoadCurrentCharacter(1, NULL, false);
@ -1000,12 +973,12 @@ TEST(MacroAssemblerNativeBackReferenceLATIN1) {
m.AdvanceCurrentPosition(2);
m.WriteCurrentPositionToRegister(1, 0);
Label nomatch;
m.CheckNotBackReference(0, false, &nomatch);
m.CheckNotBackReference(0, &nomatch);
m.Fail();
m.Bind(&nomatch);
m.AdvanceCurrentPosition(2);
Label missing_match;
m.CheckNotBackReference(0, false, &missing_match);
m.CheckNotBackReference(0, &missing_match);
m.WriteCurrentPositionToRegister(2, 0);
m.Succeed();
m.Bind(&missing_match);
@ -1050,12 +1023,12 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
m.AdvanceCurrentPosition(2);
m.WriteCurrentPositionToRegister(1, 0);
Label nomatch;
m.CheckNotBackReference(0, false, &nomatch);
m.CheckNotBackReference(0, &nomatch);
m.Fail();
m.Bind(&nomatch);
m.AdvanceCurrentPosition(2);
Label missing_match;
m.CheckNotBackReference(0, false, &missing_match);
m.CheckNotBackReference(0, &missing_match);
m.WriteCurrentPositionToRegister(2, 0);
m.Succeed();
m.Bind(&missing_match);
@ -1100,7 +1073,7 @@ TEST(MacroAssemblernativeAtStart) {
0);
Label not_at_start, newline, fail;
m.CheckNotAtStart(0, &not_at_start);
m.CheckNotAtStart(&not_at_start);
// Check that prevchar = '\n' and current = 'f'.
m.CheckCharacter('\n', &newline);
m.Bind(&fail);
@ -1165,16 +1138,16 @@ TEST(MacroAssemblerNativeBackRefNoCase) {
m.WriteCurrentPositionToRegister(2, 0);
m.AdvanceCurrentPosition(3);
m.WriteCurrentPositionToRegister(3, 0);
m.CheckNotBackReferenceIgnoreCase(2, false, &fail); // Match "AbC".
m.CheckNotBackReferenceIgnoreCase(2, false, &fail); // Match "ABC".
m.CheckNotBackReferenceIgnoreCase(2, &fail); // Match "AbC".
m.CheckNotBackReferenceIgnoreCase(2, &fail); // Match "ABC".
Label expected_fail;
m.CheckNotBackReferenceIgnoreCase(2, false, &expected_fail);
m.CheckNotBackReferenceIgnoreCase(2, &expected_fail);
m.Bind(&fail);
m.Fail();
m.Bind(&expected_fail);
m.AdvanceCurrentPosition(3); // Skip "xYz"
m.CheckNotBackReferenceIgnoreCase(2, false, &succ);
m.CheckNotBackReferenceIgnoreCase(2, &succ);
m.Fail();
m.Bind(&succ);
@ -1366,7 +1339,7 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
m.WriteCurrentPositionToRegister(0, 0);
m.WriteCurrentPositionToRegister(1, 1);
Label done;
m.CheckNotBackReference(0, false, &done); // Performs a system-stack push.
m.CheckNotBackReference(0, &done); // Performs a system-stack push.
m.Bind(&done);
m.PushRegister(large_number, RegExpMacroAssembler::kNoStackLimitCheck);
m.PopRegister(1);
@ -1415,7 +1388,7 @@ TEST(MacroAssembler) {
m.Fail();
m.Bind(&start);
m.PushBacktrack(&fail);
m.CheckNotAtStart(0, NULL);
m.CheckNotAtStart(NULL);
m.LoadCurrentCharacter(0, NULL);
m.CheckNotCharacter('f', NULL);
m.LoadCurrentCharacter(1, NULL);

View File

@ -1,159 +0,0 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-regexp-lookbehind
// Simple fixed-length matches.
assertEquals(["a"], "a".match(/^.(?<=a)/));
assertNull("b".match(/^.(?<=a)/));
assertEquals(["foo"], "foo1".match(/^f..(?<=.oo)/));
assertEquals(["foo"], "foo2".match(/^f\w\w(?<=\woo)/));
assertNull("boo".match(/^f\w\w(?<=\woo)/));
assertNull("fao".match(/^f\w\w(?<=\woo)/));
assertNull("foa".match(/^f\w\w(?<=\woo)/));
assertEquals(["def"], "abcdef".match(/(?<=abc)\w\w\w/));
assertEquals(["def"], "abcdef".match(/(?<=a.c)\w\w\w/));
assertEquals(["def"], "abcdef".match(/(?<=a\wc)\w\w\w/));
assertEquals(["cde"], "abcdef".match(/(?<=a[a-z])\w\w\w/));
assertEquals(["def"], "abcdef".match(/(?<=a[a-z][a-z])\w\w\w/));
assertEquals(["def"], "abcdef".match(/(?<=a[a-z]{2})\w\w\w/));
assertEquals(["bcd"], "abcdef".match(/(?<=a{1})\w\w\w/));
assertEquals(["cde"], "abcdef".match(/(?<=a{1}b{1})\w\w\w/));
assertEquals(["def"], "abcdef".match(/(?<=a{1}[a-z]{2})\w\w\w/));
// Variable-length matches.
assertEquals(["def"], "abcdef".match(/(?<=[a|b|c]*)[^a|b|c]{3}/));
assertEquals(["def"], "abcdef".match(/(?<=\w*)[^a|b|c]{3}/));
// Start of line matches.
assertEquals(["def"], "abcdef".match(/(?<=^abc)def/));
assertEquals(["def"], "abcdef".match(/(?<=^[a-c]{3})def/));
assertEquals(["def"], "xyz\nabcdef".match(/(?<=^[a-c]{3})def/m));
assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/(?<=^)\w+/gm));
assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/\w+(?<=$)/gm));
assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/(?<=^)\w+(?<=$)/gm));
assertNull("abcdef".match(/(?<=^[^a-c]{3})def/));
assertNull("foooo".match(/"^foooo(?<=^o+)$/));
assertNull("foooo".match(/"^foooo(?<=^o*)$/));
assertEquals(["foo"], "foo".match(/^foo(?<=^fo+)$/));
assertEquals(["foooo"], "foooo".match(/^foooo(?<=^fo*)/));
assertEquals(["foo", "f"], "foo".match(/^(f)oo(?<=^\1o+)$/));
assertEquals(["foo", "f"], "foo".match(/^(f)oo(?<=^\1o+)$/i));
assertEquals(["foo\u1234", "f"], "foo\u1234".match(/^(f)oo(?<=^\1o+).$/i));
assertEquals(["def"], "abcdefdef".match(/(?<=^\w+)def/));
assertEquals(["def", "def"], "abcdefdef".match(/(?<=^\w+)def/g));
// Word boundary matches.
assertEquals(["def"], "abc def".match(/(?<=\b)[d-f]{3}/));
assertEquals(["def"], "ab cdef".match(/(?<=\B)\w{3}/));
assertEquals(["def"], "ab cdef".match(/(?<=\B)(?<=c(?<=\w))\w{3}/));
assertNull("abcdef".match(/(?<=\b)[d-f]{3}/));
// Negative lookbehind.
assertEquals(["abc"], "abcdef".match(/(?<!abc)\w\w\w/));
assertEquals(["abc"], "abcdef".match(/(?<!a.c)\w\w\w/));
assertEquals(["abc"], "abcdef".match(/(?<!a\wc)\w\w\w/));
assertEquals(["abc"], "abcdef".match(/(?<!a[a-z])\w\w\w/));
assertEquals(["abc"], "abcdef".match(/(?<!a[a-z]{2})\w\w\w/));
assertNull("abcdef".match(/(?<!abc)def/));
assertNull("abcdef".match(/(?<!a.c)def/));
assertNull("abcdef".match(/(?<!a\wc)def/));
assertNull("abcdef".match(/(?<!a[a-z][a-z])def/));
assertNull("abcdef".match(/(?<!a[a-z]{2})def/));
assertNull("abcdef".match(/(?<!a{1}b{1})cde/));
assertNull("abcdef".match(/(?<!a{1}[a-z]{2})def/));
// Capturing matches.
assertEquals(["def", "c"], "abcdef".match(/(?<=(c))def/));
assertEquals(["def", "bc"], "abcdef".match(/(?<=(\w{2}))def/));
assertEquals(["def", "bc", "c"], "abcdef".match(/(?<=(\w(\w)))def/));
assertEquals(["def", "a"], "abcdef".match(/(?<=(\w){3})def/));
assertEquals(["d", "bc", undefined], "abcdef".match(/(?<=(bc)|(cd))./));
assertEquals(["c", "a", undefined],
"abcdef".match(/(?<=([ab]{1,2})\D|(abc))\w/));
assertEquals(["ab", "a", "b"], "abcdef".match(/\D(?<=([ab]+))(\w)/));
assertEquals(["c", "d"], "abcdef".match(/(?<=b|c)\w/g));
assertEquals(["cd", "ef"], "abcdef".match(/(?<=[b-e])\w{2}/g));
// Captures inside negative lookbehind. (They never capture.)
assertEquals(["de", undefined], "abcdef".match(/(?<!(^|[ab]))\w{2}/));
// Nested lookaround.
assertEquals(["ef"], "abcdef".match(/(?<=ab(?=c)\wd)\w\w/));
assertEquals(["ef", "bc"], "abcdef".match(/(?<=a(?=([^a]{2})d)\w{3})\w\w/));
assertEquals(["ef", "bc"],
"abcdef".match(/(?<=a(?=([bc]{2}(?<!a{2}))d)\w{3})\w\w/));
assertNull("abcdef".match(/(?<=a(?=([bc]{2}(?<!a*))d)\w{3})\w\w/));
assertEquals(["faaa"], "faaao".match(/^faaao?(?<=^f[oa]+(?=o))/));
// Back references.
assertEquals(["b", "b", "bb"], "abb".match(/(.)(?<=(\1\1))/));
assertEquals(["B", "B", "bB"], "abB".match(/(.)(?<=(\1\1))/i));
assertEquals(["aB", "aB", "a"], "aabAaBa".match(/((\w)\w)(?<=\1\2\1)/i));
assertEquals(["Ba", "Ba", "a"], "aabAaBa".match(/(\w(\w))(?<=\1\2\1)/i));
assertEquals(["b", "b", "B"], "abaBbAa".match(/(?=(\w))(?<=(\1))./i));
assertEquals(["foo", "'", "foo"], " 'foo' ".match(/(?<=(.))(\w+)(?=\1)/));
assertEquals(["foo", "\"", "foo"], " \"foo\" ".match(/(?<=(.))(\w+)(?=\1)/));
assertNull(" .foo\" ".match(/(?<=(.))(\w+)(?=\1)/));
assertNull("ab".match(/(.)(?<=\1\1\1)/));
assertNull("abb".match(/(.)(?<=\1\1\1)/));
assertEquals(["b", "b"], "abbb".match(/(.)(?<=\1\1\1)/));
assertNull("ab".match(/(..)(?<=\1\1\1)/));
assertNull("abb".match(/(..)(?<=\1\1\1)/));
assertNull("aabb".match(/(..)(?<=\1\1\1)/));
assertNull("abab".match(/(..)(?<=\1\1\1)/));
assertNull("fabxbab".match(/(..)(?<=\1\1\1)/));
assertNull("faxabab".match(/(..)(?<=\1\1\1)/));
assertEquals(["ab", "ab"], "fababab".match(/(..)(?<=\1\1\1)/));
// Back references to captures inside the lookbehind.
assertEquals(["d", "C"], "abcCd".match(/(?<=\1(\w))d/i));
assertEquals(["d", "x"], "abxxd".match(/(?<=\1([abx]))d/));
assertEquals(["c", "ab"], "ababc".match(/(?<=\1(\w+))c/));
assertEquals(["c", "b"], "ababbc".match(/(?<=\1(\w+))c/));
assertNull("ababdc".match(/(?<=\1(\w+))c/));
assertEquals(["c", "abab"], "ababc".match(/(?<=(\w+)\1)c/));
// Alternations are tried left to right,
// and we do not backtrack into a lookbehind.
assertEquals(["xabcd", "cd", ""], "xabcd".match(/.*(?<=(..|...|....))(.*)/));
assertEquals(["xabcd", "bcd", ""], "xabcd".match(/.*(?<=(xx|...|....))(.*)/));
assertEquals(["xxabcd", "bcd", ""], "xxabcd".match(/.*(?<=(xx|...))(.*)/));
assertEquals(["xxabcd", "xx", "abcd"], "xxabcd".match(/.*(?<=(xx|xxx))(.*)/));
// We do not backtrack into a lookbehind.
// The lookbehind captures "abc" so that \1 does not match. We do not backtrack
// to capture only "bc" in the lookbehind.
assertNull("abcdbc".match(/(?<=([abc]+)).\1/));
// Greedy loop.
assertEquals(["c", "bbbbbb"], "abbbbbbc".match(/(?<=(b+))c/));
assertEquals(["c", "b1234"], "ab1234c".match(/(?<=(b\d+))c/));
assertEquals(["c", "b12b23b34"], "ab12b23b34c".match(/(?<=((?:b\d{2})+))c/));
// Sticky
var re1 = /(?<=^(\w+))def/g;
assertEquals(["def", "abc"], re1.exec("abcdefdef"));
assertEquals(["def", "abcdef"], re1.exec("abcdefdef"));
var re2 = /\Bdef/g;
assertEquals(["def"], re2.exec("abcdefdef"));
assertEquals(["def"], re2.exec("abcdefdef"));
// Misc
assertNull("abcdef".match(/(?<=$abc)def/));
assertEquals(["foo"], "foo".match(/^foo(?<=foo)$/));
assertEquals(["foo"], "foo".match(/^f.o(?<=foo)$/));
assertNull("fno".match(/^f.o(?<=foo)$/));
assertNull("foo".match(/^foo(?<!foo)$/));
assertNull("foo".match(/^f.o(?<!foo)$/));
assertEquals(["fno"], "fno".match(/^f.o(?<!foo)$/));
assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo+)$/));
assertEquals(["foooo"], "foooo".match(/^foooo(?<=fo*)$/));
assertEquals(["abc", "abc"], /(abc\1)/.exec("abc"));
assertEquals(["abc", "abc"], /(abc\1)/.exec("abc\u1234"));
assertEquals(["abc", "abc"], /(abc\1)/i.exec("abc"));
assertEquals(["abc", "abc"], /(abc\1)/i.exec("abc\u1234"));
var oob_subject = "abcdefghijklmnabcdefghijklmn".substr(14);
assertNull(oob_subject.match(/(?=(abcdefghijklmn))(?<=\1)a/i));
assertNull(oob_subject.match(/(?=(abcdefghijklmn))(?<=\1)a/));