Bug 965712: Part 1 - Use our string matching logic for regexps when possible, r=luke

This commit is contained in:
Hannes Verschore 2014-04-30 16:42:25 +02:00
parent 9f228ac8a9
commit 1eddd2ecf5
5 changed files with 73 additions and 16 deletions

View File

@ -0,0 +1,2 @@
var result = "D1D1D1D1D1D1D1D1D1D1".replace(/d1/ig,1);
assertEq(result, "1111111111");

View File

@ -1173,6 +1173,13 @@ js::StringHasPattern(const jschar *text, uint32_t textlen,
return StringMatch(text, textlen, pat, patlen) != -1;
}
int
js::StringFindPattern(const jschar *text, uint32_t textlen,
const jschar *pat, uint32_t patlen)
{
return StringMatch(text, textlen, pat, patlen);
}
// When an algorithm does not need a string represented as a single linear
// array of characters, this range utility may be used to traverse the string a
// sequence of linear arrays of characters. This avoids flattening ropes.
@ -1737,6 +1744,12 @@ HasRegExpMetaChars(const jschar *chars, size_t length)
return false;
}
bool
js::StringHasRegExpMetaChars(const jschar *chars, size_t length)
{
return HasRegExpMetaChars(chars, length);
}
namespace {
/*

View File

@ -213,6 +213,13 @@ extern bool
StringHasPattern(const jschar *text, uint32_t textlen,
const jschar *pat, uint32_t patlen);
extern int
StringFindPattern(const jschar *text, uint32_t textlen,
const jschar *pat, uint32_t patlen);
extern bool
StringHasRegExpMetaChars(const jschar *chars, size_t length);
} /* namespace js */
extern size_t

View File

@ -8,6 +8,8 @@
#include "mozilla/MemoryReporting.h"
#include "jsstr.h"
#include "frontend/TokenStream.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpStatics.h"
@ -377,7 +379,7 @@ RegExpObject::toString(JSContext *cx) const
/* RegExpShared */
RegExpShared::RegExpShared(JSAtom *source, RegExpFlag flags, uint64_t gcNumber)
: source(source), flags(flags), parenCount(0),
: source(source), flags(flags), parenCount(0), canStringMatch(false),
#if ENABLE_YARR_JIT
codeBlock(),
#endif
@ -438,6 +440,9 @@ RegExpShared::checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLine
bool
RegExpShared::compile(JSContext *cx, bool matchOnly)
{
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
AutoTraceLog logCompile(logger, TraceLogger::YarrCompile);
if (!sticky())
return compile(cx, *source, matchOnly);
@ -466,6 +471,12 @@ RegExpShared::compile(JSContext *cx, bool matchOnly)
bool
RegExpShared::compile(JSContext *cx, JSLinearString &pattern, bool matchOnly)
{
if (!ignoreCase() && !StringHasRegExpMetaChars(pattern.chars(), pattern.length())) {
canStringMatch = true;
parenCount = 0;
return true;
}
/* Parse the pattern. */
ErrorCode yarrError;
YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
@ -507,7 +518,7 @@ RegExpShared::compile(JSContext *cx, JSLinearString &pattern, bool matchOnly)
bool
RegExpShared::compileIfNecessary(JSContext *cx)
{
if (hasCode() || hasBytecode())
if (hasCode() || hasBytecode() || canStringMatch)
return true;
return compile(cx, false);
}
@ -515,7 +526,7 @@ RegExpShared::compileIfNecessary(JSContext *cx)
bool
RegExpShared::compileMatchOnlyIfNecessary(JSContext *cx)
{
if (hasMatchOnlyCode() || hasBytecode())
if (hasMatchOnlyCode() || hasBytecode() || canStringMatch)
return true;
return compile(cx, true);
}
@ -526,12 +537,9 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
{
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
{
/* Compile the code at point-of-use. */
AutoTraceLog logCompile(logger, TraceLogger::YarrCompile);
if (!compileIfNecessary(cx))
return RegExpRunStatus_Error;
}
/* Compile the code at point-of-use. */
if (!compileIfNecessary(cx))
return RegExpRunStatus_Error;
/* Ensure sufficient memory for output vector. */
if (!matches.initArray(pairCount()))
@ -555,6 +563,20 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
unsigned *outputBuf = matches.rawBuf();
unsigned result;
if (canStringMatch) {
int res = StringFindPattern(chars+start, length-start, source->chars(), source->length());
if (res == -1)
return RegExpRunStatus_Success_NotFound;
outputBuf[0] = res + start;
outputBuf[1] = outputBuf[0] + source->length();
matches.displace(displacement);
matches.checkAgainst(origLength);
*lastIndex = matches[0].limit;
return RegExpRunStatus_Success;
}
#if ENABLE_YARR_JIT
if (codeBlock.isFallBack()) {
AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
@ -590,12 +612,9 @@ RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length
{
TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
{
/* Compile the code at point-of-use. */
AutoTraceLog logCompile(logger, TraceLogger::YarrCompile);
if (!compileMatchOnlyIfNecessary(cx))
return RegExpRunStatus_Error;
}
/* Compile the code at point-of-use. */
if (!compileMatchOnlyIfNecessary(cx))
return RegExpRunStatus_Error;
#ifdef DEBUG
const size_t origLength = length;
@ -610,6 +629,17 @@ RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length
start = 0;
}
if (canStringMatch) {
int res = StringFindPattern(chars+start, length-start, source->chars(), source->length());
if (res == -1)
return RegExpRunStatus_Success_NotFound;
match = MatchPair(res + start, res + start + source->length());
match.displace(displacement);
*lastIndex = match.limit;
return RegExpRunStatus_Success;
}
#if ENABLE_YARR_JIT
if (!codeBlock.isFallBack()) {
AutoTraceLog logJIT(logger, TraceLogger::YarrJIT);

View File

@ -145,6 +145,7 @@ class RegExpShared
RegExpFlag flags;
unsigned parenCount;
bool canStringMatch;
#if ENABLE_YARR_JIT
/* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
@ -204,7 +205,11 @@ class RegExpShared
/* Accessors */
size_t getParenCount() const { JS_ASSERT(isCompiled()); return parenCount; }
size_t getParenCount() const {
JS_ASSERT(isCompiled() || canStringMatch);
return parenCount;
}
void incRef() { activeUseCount++; }
void decRef() { JS_ASSERT(activeUseCount > 0); activeUseCount--; }