Backed out changeset 759b21bbb64b (bug 610223) due to Windows build bustage, a=red

This commit is contained in:
Gavin Sharp 2010-11-15 23:15:02 -05:00
parent e7f1aced19
commit a9d2b1cd5a
6 changed files with 113 additions and 212 deletions

View File

@ -1,8 +0,0 @@
var re = /(pattern)/g;
var input = "patternpatternpattern";
re.exec(input)
RegExp.input = "satturn";
assertEq(RegExp.$1, "pattern");
assertEq(RegExp.lastMatch, "pattern");
assertEq(RegExp.lastParen, "pattern");
assertEq(RegExp.rightContext, "patternpattern");

View File

@ -1,8 +0,0 @@
var re = /abc(WHOO!)?def/y;
var input = 'abcdefabcdefabcdef';
var count = 0;
while ((match = re.exec(input)) !== null) {
print(count++);
assertEq(match[0], 'abcdef');
assertEq(match[1], undefined);
}

View File

@ -393,7 +393,7 @@ regexp_resolve(JSContext *cx, JSObject *obj, jsid id, uint32 flags, JSObject **o
code; \ code; \
} }
DEFINE_STATIC_GETTER(static_input_getter, return res->createPendingInput(cx, Valueify(vp))) DEFINE_STATIC_GETTER(static_input_getter, return res->createInput(cx, Valueify(vp)))
DEFINE_STATIC_GETTER(static_multiline_getter, *vp = BOOLEAN_TO_JSVAL(res->multiline()); DEFINE_STATIC_GETTER(static_multiline_getter, *vp = BOOLEAN_TO_JSVAL(res->multiline());
return true) return true)
DEFINE_STATIC_GETTER(static_lastMatch_getter, return res->createLastMatch(cx, Valueify(vp))) DEFINE_STATIC_GETTER(static_lastMatch_getter, return res->createLastMatch(cx, Valueify(vp)))
@ -423,7 +423,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, return res->createParen(cx, 8,
DEFINE_STATIC_SETTER(static_input_setter, DEFINE_STATIC_SETTER(static_input_setter,
if (!JSVAL_IS_STRING(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) if (!JSVAL_IS_STRING(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp))
return false; return false;
res->setPendingInput(JSVAL_TO_STRING(*vp))) res->setInput(JSVAL_TO_STRING(*vp)))
DEFINE_STATIC_SETTER(static_multiline_setter, DEFINE_STATIC_SETTER(static_multiline_setter,
if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp))
return false; return false;
@ -783,7 +783,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool te
argv[0] = StringValue(str); argv[0] = StringValue(str);
} else { } else {
/* Need to grab input from statics. */ /* Need to grab input from statics. */
str = res->getPendingInput(); str = res->getInput();
if (!str) { if (!str) {
const char *sourceBytes = js_GetStringBytes(cx, re->getSource()); const char *sourceBytes = js_GetStringBytes(cx, re->getSource());
if (sourceBytes) { if (sourceBytes) {

View File

@ -59,14 +59,11 @@ namespace js {
class RegExpStatics class RegExpStatics
{ {
typedef Vector<int, 20, SystemAllocPolicy> MatchPairs; typedef Vector<int, 20, SystemAllocPolicy> MatchPairs;
MatchPairs matchPairs; MatchPairs matchPairs;
/* The input that was used to produce matchPairs. */ JSString *input;
JSString *matchPairsInput; uintN flags;
/* The input last set on the statics. */ RegExpStatics *bufferLink;
JSString *pendingInput; bool copied;
uintN flags;
RegExpStatics *bufferLink;
bool copied;
bool createDependent(JSContext *cx, size_t start, size_t end, Value *out) const; bool createDependent(JSContext *cx, size_t start, size_t end, Value *out) const;
@ -79,8 +76,7 @@ class RegExpStatics
dst.matchPairs.clear(); dst.matchPairs.clear();
/* 'save' has already reserved space in matchPairs */ /* 'save' has already reserved space in matchPairs */
JS_ALWAYS_TRUE(dst.matchPairs.append(matchPairs)); JS_ALWAYS_TRUE(dst.matchPairs.append(matchPairs));
dst.matchPairsInput = matchPairsInput; dst.input = input;
dst.pendingInput = pendingInput;
dst.flags = flags; dst.flags = flags;
} }
@ -91,6 +87,25 @@ class RegExpStatics
} }
} }
/*
* Check whether the index at |checkValidIndex| is valid (>= 0).
* If so, construct a string for it and place it in |*out|.
* If not, place undefined in |*out|.
*/
bool makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum, Value *out) const;
static const uintN allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_STICKY | JSREG_MULTILINE;
friend class RegExp;
public:
RegExpStatics() : bufferLink(NULL), copied(false) { clear(); }
struct InitBuffer {};
explicit RegExpStatics(InitBuffer) : bufferLink(NULL), copied(false) {}
static RegExpStatics *extractFrom(JSObject *global);
/* Mutators. */
bool save(JSContext *cx, RegExpStatics *buffer) { bool save(JSContext *cx, RegExpStatics *buffer) {
JS_ASSERT(!buffer->copied && !buffer->bufferLink); JS_ASSERT(!buffer->copied && !buffer->bufferLink);
buffer->bufferLink = bufferLink; buffer->bufferLink = bufferLink;
@ -108,76 +123,6 @@ class RegExpStatics
bufferLink = bufferLink->bufferLink; bufferLink = bufferLink->bufferLink;
} }
void checkInvariants() {
#if DEBUG
if (pairCount() == 0) {
JS_ASSERT(!matchPairsInput);
return;
}
/* Pair count is non-zero, so there must be match pairs input. */
JS_ASSERT(matchPairsInput);
size_t mpiLen = matchPairsInput->length();
JS_ASSERT(pairIsPresent(0));
/* Present pairs must be valid. */
for (size_t i = 0; i < pairCount(); ++i) {
if (!pairIsPresent(i))
continue;
int start = get(i, 0);
int limit = get(i, 1);
JS_ASSERT(mpiLen >= size_t(limit) && limit >= start && start >= 0);
}
#endif
}
int get(size_t pairNum, bool which) const {
JS_ASSERT(pairNum < pairCount());
return matchPairs[2 * pairNum + which];
}
/*
* Check whether the index at |checkValidIndex| is valid (>= 0).
* If so, construct a string for it and place it in |*out|.
* If not, place undefined in |*out|.
*/
bool makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum, Value *out) const;
static const uintN allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_STICKY | JSREG_MULTILINE;
struct InitBuffer {};
explicit RegExpStatics(InitBuffer) : bufferLink(NULL), copied(false) {}
friend class PreserveRegExpStatics;
public:
RegExpStatics() : bufferLink(NULL), copied(false) { clear(); }
static RegExpStatics *extractFrom(JSObject *global);
/* Mutators. */
/*
* The inputOffset parameter is added to the present (i.e. non-negative) match items to emulate
* sticky mode.
*/
bool updateFromMatch(JSContext *cx, JSString *input, int *buf, size_t matchItemCount) {
aboutToWrite();
pendingInput = input;
if (!matchPairs.resizeUninitialized(matchItemCount)) {
js_ReportOutOfMemory(cx);
return false;
}
for (size_t i = 0; i < matchItemCount; ++i)
matchPairs[i] = buf[i];
matchPairsInput = input;
return true;
}
void setMultiline(bool enabled) { void setMultiline(bool enabled) {
aboutToWrite(); aboutToWrite();
if (enabled) if (enabled)
@ -188,61 +133,43 @@ class RegExpStatics
void clear() { void clear() {
aboutToWrite(); aboutToWrite();
input = 0;
flags = 0; flags = 0;
pendingInput = NULL;
matchPairsInput = NULL;
matchPairs.clear(); matchPairs.clear();
} }
bool pairIsPresent(size_t pairNum) { return get(0, 0) != -1; } void checkInvariants() {
if (pairCount() > 0) {
JS_ASSERT(input);
JS_ASSERT(get(0, 0) <= get(0, 1));
JS_ASSERT(get(0, 1) <= int(input->length()));
}
}
/* Corresponds to JSAPI functionality to set the pending RegExp input. */
void reset(JSString *newInput, bool newMultiline) { void reset(JSString *newInput, bool newMultiline) {
aboutToWrite(); aboutToWrite();
clear(); clear();
pendingInput = newInput; input = newInput;
setMultiline(newMultiline); setMultiline(newMultiline);
checkInvariants(); checkInvariants();
} }
void setPendingInput(JSString *newInput) { void setInput(JSString *newInput) {
aboutToWrite(); aboutToWrite();
pendingInput = newInput; input = newInput;
} }
/* Accessors. */ /* Accessors. */
JSString *getPendingInput() const { return pendingInput; } JSString *getInput() const { return input; }
uintN getFlags() const { return flags; } uintN getFlags() const { return flags; }
bool multiline() const { return flags & JSREG_MULTILINE; } bool multiline() const { return flags & JSREG_MULTILINE; }
bool matched() const { JS_ASSERT(pairCount() > 0); return get(0, 1) - get(0, 0) > 0; }
size_t matchStart() const { size_t getParenCount() const { JS_ASSERT(pairCount() > 0); return pairCount() - 1; }
int start = get(0, 0);
JS_ASSERT(start >= 0);
return size_t(start);
}
size_t matchLimit() const {
int limit = get(0, 1);
JS_ASSERT(size_t(limit) >= matchStart() && limit >= 0);
return size_t(limit);
}
bool matched() const {
JS_ASSERT(pairCount() > 0);
return get(0, 1) - get(0, 0) > 0;
}
size_t getParenCount() const {
JS_ASSERT(pairCount() > 0);
return pairCount() - 1;
}
void mark(JSTracer *trc) const { void mark(JSTracer *trc) const {
if (pendingInput) if (input)
JS_CALL_STRING_TRACER(trc, pendingInput, "res->pendingInput"); JS_CALL_STRING_TRACER(trc, input, "res->input");
if (matchPairsInput)
JS_CALL_STRING_TRACER(trc, matchPairsInput, "res->matchPairsInput");
} }
size_t getParenLength(size_t parenNum) const { size_t getParenLength(size_t parenNum) const {
@ -251,9 +178,14 @@ class RegExpStatics
return get(parenNum + 1, 1) - get(parenNum + 1, 0); return get(parenNum + 1, 1) - get(parenNum + 1, 0);
} }
int get(size_t pairNum, bool which) const {
JS_ASSERT(pairNum < pairCount());
return matchPairs[2 * pairNum + which];
}
/* Value creators. */ /* Value creators. */
bool createPendingInput(JSContext *cx, Value *out) const; bool createInput(JSContext *cx, Value *out) const;
bool createLastMatch(JSContext *cx, Value *out) const { return makeMatch(cx, 0, 0, out); } bool createLastMatch(JSContext *cx, Value *out) const { return makeMatch(cx, 0, 0, out); }
bool createLastParen(JSContext *cx, Value *out) const; bool createLastParen(JSContext *cx, Value *out) const;
bool createLeftContext(JSContext *cx, Value *out) const; bool createLeftContext(JSContext *cx, Value *out) const;
@ -272,26 +204,6 @@ class RegExpStatics
void getRightContext(JSSubString *out) const; void getRightContext(JSSubString *out) const;
}; };
class PreserveRegExpStatics
{
RegExpStatics *const original;
RegExpStatics buffer;
public:
explicit PreserveRegExpStatics(RegExpStatics *original)
: original(original),
buffer(RegExpStatics::InitBuffer())
{}
bool init(JSContext *cx) {
return original->save(cx, &buffer);
}
~PreserveRegExpStatics() {
original->restore();
}
};
} }
static inline bool static inline bool

View File

@ -93,8 +93,9 @@ class RegExp
void handlePCREError(JSContext *cx, int error); void handlePCREError(JSContext *cx, int error);
void handleYarrError(JSContext *cx, int error); void handleYarrError(JSContext *cx, int error);
static inline bool initArena(JSContext *cx); static inline bool initArena(JSContext *cx);
static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount); static inline void checkMatchPairs(int *buf, size_t matchItemCount);
static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount); JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount,
size_t inputOffset);
inline bool executeInternal(JSContext *cx, RegExpStatics *res, JSString *input, inline bool executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
size_t *lastIndex, bool test, Value *rval); size_t *lastIndex, bool test, Value *rval);
@ -217,29 +218,19 @@ RegExp::initArena(JSContext *cx)
} }
inline void inline void
RegExp::checkMatchPairs(JSString *input, int *buf, size_t matchItemCount) RegExp::checkMatchPairs(int *buf, size_t matchItemCount)
{ {
#if DEBUG #if DEBUG
size_t inputLength = input->length(); for (size_t i = 0; i < matchItemCount; i += 2)
int largestStartSeen = 0; JS_ASSERT(buf[i + 1] >= buf[i]); /* Limit index must be larger than the start index. */
for (size_t i = 0; i < matchItemCount; i += 2) {
int start = buf[i];
int limit = buf[i + 1];
JS_ASSERT(limit >= start); /* Limit index must be larger than the start index. */
if (start == -1)
continue;
JS_ASSERT(start >= 0);
JS_ASSERT(size_t(limit) <= inputLength);
/* Test the monotonically increasing nature of left parens. */
JS_ASSERT(start >= largestStartSeen);
largestStartSeen = start;
}
#endif #endif
} }
inline JSObject * inline JSObject *
RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount) RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount,
size_t inputOffset)
{ {
#define MATCH_VALUE(__index) (buf[(__index)] + inputOffset)
/* /*
* Create the result array for a match. Array contents: * Create the result array for a match. Array contents:
* 0: matched string * 0: matched string
@ -251,13 +242,13 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
RegExpMatchBuilder builder(cx, array); RegExpMatchBuilder builder(cx, array);
for (size_t i = 0; i < matchItemCount; i += 2) { for (size_t i = 0; i < matchItemCount; i += 2) {
int start = buf[i]; int start = MATCH_VALUE(i);
int end = buf[i + 1]; int end = MATCH_VALUE(i + 1);
JSString *captured; JSString *captured;
if (start >= 0) { if (start >= 0) {
JS_ASSERT(start <= end); JS_ASSERT(start <= end);
JS_ASSERT(unsigned(end) <= input->length()); JS_ASSERT((unsigned) end <= input->length());
captured = js_NewDependentString(cx, input, start, end - start); captured = js_NewDependentString(cx, input, start, end - start);
if (!(captured && builder.append(i / 2, captured))) if (!(captured && builder.append(i / 2, captured)))
return NULL; return NULL;
@ -270,11 +261,12 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
} }
} }
if (!builder.appendIndex(buf[0]) || if (!builder.appendIndex(MATCH_VALUE(0)) ||
!builder.appendInput(input)) !builder.appendInput(input))
return NULL; return NULL;
return array; return array;
#undef MATCH_VALUE
} }
inline bool inline bool
@ -305,11 +297,6 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
const jschar *chars = input->chars(); const jschar *chars = input->chars();
size_t len = input->length(); size_t len = input->length();
/*
* inputOffset emulates sticky mode by matching from this offset into the char buf and
* subtracting the delta off at the end.
*/
size_t inputOffset = 0; size_t inputOffset = 0;
if (sticky()) { if (sticky()) {
@ -331,29 +318,27 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
return true; return true;
} }
/* checkMatchPairs(buf, matchItemCount);
* Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
* just do another pass. if (res) {
*/ res->aboutToWrite();
if (JS_UNLIKELY(inputOffset)) { res->input = input;
if (!res->matchPairs.resizeUninitialized(matchItemCount)) {
js_ReportOutOfMemory(cx);
return false;
}
for (size_t i = 0; i < matchItemCount; ++i) for (size_t i = 0; i < matchItemCount; ++i)
buf[i] = buf[i] < 0 ? -1 : buf[i] + inputOffset; res->matchPairs[i] = buf[i] + inputOffset;
} }
/* Make sure the populated contents of |buf| are sane values against |input|. */ *lastIndex = buf[1] + inputOffset;
checkMatchPairs(input, buf, matchItemCount);
if (res)
res->updateFromMatch(cx, input, buf, matchItemCount);
*lastIndex = buf[1];
if (test) { if (test) {
*rval = BooleanValue(true); *rval = BooleanValue(true);
return true; return true;
} }
JSObject *array = createResult(cx, input, buf, matchItemCount); JSObject *array = createResult(cx, input, buf, matchItemCount, inputOffset);
if (!array) if (!array)
return false; return false;
@ -545,8 +530,8 @@ inline bool
RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) const RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) const
{ {
JS_ASSERT(start <= end); JS_ASSERT(start <= end);
JS_ASSERT(end <= matchPairsInput->length()); JS_ASSERT(end <= input->length());
JSString *str = js_NewDependentString(cx, matchPairsInput, start, end - start); JSString *str = js_NewDependentString(cx, input, start, end - start);
if (!str) if (!str)
return false; return false;
*out = StringValue(str); *out = StringValue(str);
@ -554,9 +539,9 @@ RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *o
} }
inline bool inline bool
RegExpStatics::createPendingInput(JSContext *cx, Value *out) const RegExpStatics::createInput(JSContext *cx, Value *out) const
{ {
out->setString(pendingInput ? pendingInput : cx->runtime->emptyString); out->setString(input ? input : cx->runtime->emptyString);
return true; return true;
} }
@ -614,13 +599,13 @@ RegExpStatics::createRightContext(JSContext *cx, Value *out) const
*out = UndefinedValue(); *out = UndefinedValue();
return true; return true;
} }
return createDependent(cx, matchPairs[1], matchPairsInput->length(), out); return createDependent(cx, matchPairs[1], input->length(), out);
} }
inline void inline void
RegExpStatics::getParen(size_t num, JSSubString *out) const RegExpStatics::getParen(size_t num, JSSubString *out) const
{ {
out->chars = matchPairsInput->chars() + get(num + 1, 0); out->chars = input->chars() + get(num + 1, 0);
out->length = getParenLength(num); out->length = getParenLength(num);
} }
@ -631,8 +616,8 @@ RegExpStatics::getLastMatch(JSSubString *out) const
*out = js_EmptySubString; *out = js_EmptySubString;
return; return;
} }
JS_ASSERT(matchPairsInput); JS_ASSERT(input);
out->chars = matchPairsInput->chars() + get(0, 0); out->chars = input->chars() + get(0, 0);
JS_ASSERT(get(0, 1) >= get(0, 0)); JS_ASSERT(get(0, 1) >= get(0, 0));
out->length = get(0, 1) - get(0, 0); out->length = get(0, 1) - get(0, 0);
} }
@ -645,7 +630,7 @@ RegExpStatics::getLastParen(JSSubString *out) const
return; return;
} }
size_t num = pairCount() - 1; size_t num = pairCount() - 1;
out->chars = matchPairsInput->chars() + get(num, 0); out->chars = input->chars() + get(num, 0);
JS_ASSERT(get(num, 1) >= get(num, 0)); JS_ASSERT(get(num, 1) >= get(num, 0));
out->length = get(num, 1) - get(num, 0); out->length = get(num, 1) - get(num, 0);
} }
@ -657,7 +642,7 @@ RegExpStatics::getLeftContext(JSSubString *out) const
*out = js_EmptySubString; *out = js_EmptySubString;
return; return;
} }
out->chars = matchPairsInput->chars(); out->chars = input->chars();
out->length = get(0, 0); out->length = get(0, 0);
} }
@ -668,9 +653,9 @@ RegExpStatics::getRightContext(JSSubString *out) const
*out = js_EmptySubString; *out = js_EmptySubString;
return; return;
} }
out->chars = matchPairsInput->chars() + get(0, 1); out->chars = input->chars() + get(0, 1);
JS_ASSERT(get(0, 1) <= int(matchPairsInput->length())); JS_ASSERT(get(0, 1) <= int(input->length()));
out->length = matchPairsInput->length() - get(0, 1); out->length = input->length() - get(0, 1);
} }
} }

View File

@ -1955,7 +1955,7 @@ str_search(JSContext *cx, uintN argc, Value *vp)
return false; return false;
if (vp->isTrue()) if (vp->isTrue())
vp->setInt32(res->matchStart()); vp->setInt32(res->get(0, 0));
else else
vp->setInt32(-1); vp->setInt32(-1);
return true; return true;
@ -2045,6 +2045,26 @@ InterpretDollar(JSContext *cx, RegExpStatics *res, jschar *dp, jschar *ep, Repla
return false; return false;
} }
class PreserveRegExpStatics
{
js::RegExpStatics *const original;
js::RegExpStatics buffer;
public:
explicit PreserveRegExpStatics(RegExpStatics *original)
: original(original),
buffer(RegExpStatics::InitBuffer())
{}
bool init(JSContext *cx) {
return original->save(cx, &buffer);
}
~PreserveRegExpStatics() {
original->restore();
}
};
static bool static bool
FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep) FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
{ {
@ -2135,7 +2155,7 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
} }
/* Push match index and input string. */ /* Push match index and input string. */
session[argi++].setInt32(res->matchStart()); session[argi++].setInt32(res->get(0, 0));
session[argi].setString(rdata.str); session[argi].setString(rdata.str);
if (!session.invoke(cx)) if (!session.invoke(cx))
@ -2202,8 +2222,8 @@ ReplaceCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
JSString *str = rdata.str; JSString *str = rdata.str;
size_t leftoff = rdata.leftIndex; size_t leftoff = rdata.leftIndex;
const jschar *left = str->chars() + leftoff; const jschar *left = str->chars() + leftoff;
size_t leftlen = res->matchStart() - leftoff; size_t leftlen = res->get(0, 0) - leftoff;
rdata.leftIndex = res->matchLimit(); rdata.leftIndex = res->get(0, 1);
size_t replen = 0; /* silence 'unused' warning */ size_t replen = 0; /* silence 'unused' warning */
if (!FindReplaceLength(cx, res, rdata, &replen)) if (!FindReplaceLength(cx, res, rdata, &replen))