From a9d2b1cd5a1e75a80076a3bb46f6cc934da1f637 Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Mon, 15 Nov 2010 23:15:02 -0500 Subject: [PATCH] Backed out changeset 759b21bbb64b (bug 610223) due to Windows build bustage, a=red --- .../tests/basic/regexp-reset-input.js | 8 - .../basic/regexp-sticky-undef-capture.js | 8 - js/src/jsregexp.cpp | 6 +- js/src/jsregexp.h | 182 +++++------------- js/src/jsregexpinlines.h | 93 ++++----- js/src/jsstr.cpp | 28 ++- 6 files changed, 113 insertions(+), 212 deletions(-) delete mode 100644 js/src/jit-test/tests/basic/regexp-reset-input.js delete mode 100644 js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js diff --git a/js/src/jit-test/tests/basic/regexp-reset-input.js b/js/src/jit-test/tests/basic/regexp-reset-input.js deleted file mode 100644 index 77cdd69dd639..000000000000 --- a/js/src/jit-test/tests/basic/regexp-reset-input.js +++ /dev/null @@ -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"); diff --git a/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js b/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js deleted file mode 100644 index 3d96d4e44cc7..000000000000 --- a/js/src/jit-test/tests/basic/regexp-sticky-undef-capture.js +++ /dev/null @@ -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); -} diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index a604d858a3b7..a973f0ec7cf8 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -393,7 +393,7 @@ regexp_resolve(JSContext *cx, JSObject *obj, jsid id, uint32 flags, JSObject **o 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()); return true) 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, if (!JSVAL_IS_STRING(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) return false; - res->setPendingInput(JSVAL_TO_STRING(*vp))) + res->setInput(JSVAL_TO_STRING(*vp))) DEFINE_STATIC_SETTER(static_multiline_setter, if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) return false; @@ -783,7 +783,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool te argv[0] = StringValue(str); } else { /* Need to grab input from statics. */ - str = res->getPendingInput(); + str = res->getInput(); if (!str) { const char *sourceBytes = js_GetStringBytes(cx, re->getSource()); if (sourceBytes) { diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index b2fdcffd9025..805977b802eb 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -59,14 +59,11 @@ namespace js { class RegExpStatics { typedef Vector MatchPairs; - MatchPairs matchPairs; - /* The input that was used to produce matchPairs. */ - JSString *matchPairsInput; - /* The input last set on the statics. */ - JSString *pendingInput; - uintN flags; - RegExpStatics *bufferLink; - bool copied; + MatchPairs matchPairs; + JSString *input; + uintN flags; + RegExpStatics *bufferLink; + bool copied; bool createDependent(JSContext *cx, size_t start, size_t end, Value *out) const; @@ -79,8 +76,7 @@ class RegExpStatics dst.matchPairs.clear(); /* 'save' has already reserved space in matchPairs */ JS_ALWAYS_TRUE(dst.matchPairs.append(matchPairs)); - dst.matchPairsInput = matchPairsInput; - dst.pendingInput = pendingInput; + dst.input = input; 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) { JS_ASSERT(!buffer->copied && !buffer->bufferLink); buffer->bufferLink = bufferLink; @@ -108,76 +123,6 @@ class RegExpStatics 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) { aboutToWrite(); if (enabled) @@ -188,61 +133,43 @@ class RegExpStatics void clear() { aboutToWrite(); + input = 0; flags = 0; - pendingInput = NULL; - matchPairsInput = NULL; 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) { aboutToWrite(); clear(); - pendingInput = newInput; + input = newInput; setMultiline(newMultiline); checkInvariants(); } - void setPendingInput(JSString *newInput) { + void setInput(JSString *newInput) { aboutToWrite(); - pendingInput = newInput; + input = newInput; } /* Accessors. */ - JSString *getPendingInput() const { return pendingInput; } + JSString *getInput() const { return input; } uintN getFlags() const { return flags; } bool multiline() const { return flags & JSREG_MULTILINE; } - - size_t matchStart() const { - 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; - } + 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 { - if (pendingInput) - JS_CALL_STRING_TRACER(trc, pendingInput, "res->pendingInput"); - if (matchPairsInput) - JS_CALL_STRING_TRACER(trc, matchPairsInput, "res->matchPairsInput"); + if (input) + JS_CALL_STRING_TRACER(trc, input, "res->input"); } size_t getParenLength(size_t parenNum) const { @@ -251,9 +178,14 @@ class RegExpStatics 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. */ - 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 createLastParen(JSContext *cx, Value *out) const; bool createLeftContext(JSContext *cx, Value *out) const; @@ -272,26 +204,6 @@ class RegExpStatics 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 diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h index 6dbdf00ae080..abbaf67b1722 100644 --- a/js/src/jsregexpinlines.h +++ b/js/src/jsregexpinlines.h @@ -93,8 +93,9 @@ class RegExp void handlePCREError(JSContext *cx, int error); void handleYarrError(JSContext *cx, int error); static inline bool initArena(JSContext *cx); - static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount); - static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount); + static inline void checkMatchPairs(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, size_t *lastIndex, bool test, Value *rval); @@ -217,29 +218,19 @@ RegExp::initArena(JSContext *cx) } inline void -RegExp::checkMatchPairs(JSString *input, int *buf, size_t matchItemCount) +RegExp::checkMatchPairs(int *buf, size_t matchItemCount) { #if DEBUG - size_t inputLength = input->length(); - int largestStartSeen = 0; - 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; - } + for (size_t i = 0; i < matchItemCount; i += 2) + JS_ASSERT(buf[i + 1] >= buf[i]); /* Limit index must be larger than the start index. */ #endif } 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: * 0: matched string @@ -251,13 +242,13 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC RegExpMatchBuilder builder(cx, array); for (size_t i = 0; i < matchItemCount; i += 2) { - int start = buf[i]; - int end = buf[i + 1]; + int start = MATCH_VALUE(i); + int end = MATCH_VALUE(i + 1); JSString *captured; if (start >= 0) { JS_ASSERT(start <= end); - JS_ASSERT(unsigned(end) <= input->length()); + JS_ASSERT((unsigned) end <= input->length()); captured = js_NewDependentString(cx, input, start, end - start); if (!(captured && builder.append(i / 2, captured))) 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)) return NULL; return array; +#undef MATCH_VALUE } inline bool @@ -305,11 +297,6 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input, const jschar *chars = input->chars(); 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; if (sticky()) { @@ -331,29 +318,27 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input, return true; } - /* - * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so - * just do another pass. - */ - if (JS_UNLIKELY(inputOffset)) { + checkMatchPairs(buf, matchItemCount); + + if (res) { + res->aboutToWrite(); + res->input = input; + if (!res->matchPairs.resizeUninitialized(matchItemCount)) { + js_ReportOutOfMemory(cx); + return false; + } 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|. */ - checkMatchPairs(input, buf, matchItemCount); - - if (res) - res->updateFromMatch(cx, input, buf, matchItemCount); - - *lastIndex = buf[1]; + *lastIndex = buf[1] + inputOffset; if (test) { *rval = BooleanValue(true); return true; } - JSObject *array = createResult(cx, input, buf, matchItemCount); + JSObject *array = createResult(cx, input, buf, matchItemCount, inputOffset); if (!array) return false; @@ -545,8 +530,8 @@ inline bool RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) const { JS_ASSERT(start <= end); - JS_ASSERT(end <= matchPairsInput->length()); - JSString *str = js_NewDependentString(cx, matchPairsInput, start, end - start); + JS_ASSERT(end <= input->length()); + JSString *str = js_NewDependentString(cx, input, start, end - start); if (!str) return false; *out = StringValue(str); @@ -554,9 +539,9 @@ RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *o } 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; } @@ -614,13 +599,13 @@ RegExpStatics::createRightContext(JSContext *cx, Value *out) const *out = UndefinedValue(); return true; } - return createDependent(cx, matchPairs[1], matchPairsInput->length(), out); + return createDependent(cx, matchPairs[1], input->length(), out); } inline void 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); } @@ -631,8 +616,8 @@ RegExpStatics::getLastMatch(JSSubString *out) const *out = js_EmptySubString; return; } - JS_ASSERT(matchPairsInput); - out->chars = matchPairsInput->chars() + get(0, 0); + JS_ASSERT(input); + out->chars = input->chars() + get(0, 0); JS_ASSERT(get(0, 1) >= get(0, 0)); out->length = get(0, 1) - get(0, 0); } @@ -645,7 +630,7 @@ RegExpStatics::getLastParen(JSSubString *out) const return; } 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)); out->length = get(num, 1) - get(num, 0); } @@ -657,7 +642,7 @@ RegExpStatics::getLeftContext(JSSubString *out) const *out = js_EmptySubString; return; } - out->chars = matchPairsInput->chars(); + out->chars = input->chars(); out->length = get(0, 0); } @@ -668,9 +653,9 @@ RegExpStatics::getRightContext(JSSubString *out) const *out = js_EmptySubString; return; } - out->chars = matchPairsInput->chars() + get(0, 1); - JS_ASSERT(get(0, 1) <= int(matchPairsInput->length())); - out->length = matchPairsInput->length() - get(0, 1); + out->chars = input->chars() + get(0, 1); + JS_ASSERT(get(0, 1) <= int(input->length())); + out->length = input->length() - get(0, 1); } } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 54b6cd92d04f..082fd4de3fa3 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1955,7 +1955,7 @@ str_search(JSContext *cx, uintN argc, Value *vp) return false; if (vp->isTrue()) - vp->setInt32(res->matchStart()); + vp->setInt32(res->get(0, 0)); else vp->setInt32(-1); return true; @@ -2045,6 +2045,26 @@ InterpretDollar(JSContext *cx, RegExpStatics *res, jschar *dp, jschar *ep, Repla 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 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. */ - session[argi++].setInt32(res->matchStart()); + session[argi++].setInt32(res->get(0, 0)); session[argi].setString(rdata.str); if (!session.invoke(cx)) @@ -2202,8 +2222,8 @@ ReplaceCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p) JSString *str = rdata.str; size_t leftoff = rdata.leftIndex; const jschar *left = str->chars() + leftoff; - size_t leftlen = res->matchStart() - leftoff; - rdata.leftIndex = res->matchLimit(); + size_t leftlen = res->get(0, 0) - leftoff; + rdata.leftIndex = res->get(0, 1); size_t replen = 0; /* silence 'unused' warning */ if (!FindReplaceLength(cx, res, rdata, &replen))