Bug 691898 - Use YARR interpreter instead of PCRE on platforms where YARR JIT is not supported. r=dmandelin

This commit is contained in:
Landry Breuil 2012-03-07 12:06:19 +01:00
parent 255811e424
commit c78af1f2ba
9 changed files with 43 additions and 99 deletions

View File

@ -337,20 +337,21 @@ CPPSRCS += checks.cc \
# END enclude sources for V8 dtoa # END enclude sources for V8 dtoa
############################################# #############################################
# For architectures without YARR JIT, PCRE is faster than the YARR
# interpreter (bug 684559).
ifeq (,$(filter arm% sparc %86 x86_64 mips%,$(TARGET_CPU))) ifeq (,$(filter arm% sparc %86 x86_64 mips%,$(TARGET_CPU)))
VPATH += $(srcdir)/yarr/pcre \ VPATH += $(srcdir)/assembler \
$(srcdir)/assembler/wtf \
$(srcdir)/yarr \
$(NULL) $(NULL)
CPPSRCS += \ CPPSRCS += \
pcre_compile.cpp \ OSAllocatorOS2.cpp \
pcre_exec.cpp \ OSAllocatorPosix.cpp \
pcre_tables.cpp \ OSAllocatorWin.cpp \
pcre_xclass.cpp \ PageBlock.cpp \
pcre_ucp_searchfuncs.cpp \ YarrInterpreter.cpp \
YarrPattern.cpp \
YarrSyntaxChecker.cpp \
$(NULL) $(NULL)
else else
@ -885,10 +886,10 @@ endif
# Needed to "configure" it correctly. Unfortunately these # Needed to "configure" it correctly. Unfortunately these
# flags wind up being applied to all code in js/src, not just # flags wind up being applied to all code in js/src, not just
# the code in js/src/assembler. # the code in js/src/assembler.
CXXFLAGS += -DUSE_SYSTEM_MALLOC=1 -DENABLE_ASSEMBLER=1 CXXFLAGS += -DUSE_SYSTEM_MALLOC=1
ifneq (,$(ENABLE_YARR_JIT)$(ENABLE_METHODJIT)) ifneq (,$(ENABLE_YARR_JIT)$(ENABLE_METHODJIT))
CXXFLAGS += -DENABLE_JIT=1 CXXFLAGS += -DENABLE_JIT=1 -DENABLE_ASSEMBLER=1
endif endif
INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr

View File

@ -702,7 +702,9 @@ JSRuntime::JSRuntime()
ownerThread_(NULL), ownerThread_(NULL),
#endif #endif
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
#if ENABLE_ASSEMBLER
execAlloc_(NULL), execAlloc_(NULL),
#endif
bumpAlloc_(NULL), bumpAlloc_(NULL),
nativeStackBase(0), nativeStackBase(0),
nativeStackQuota(0), nativeStackQuota(0),
@ -864,7 +866,9 @@ JSRuntime::~JSRuntime()
{ {
JS_ASSERT(onOwnerThread()); JS_ASSERT(onOwnerThread());
#if ENABLE_ASSEMBLER
delete_<JSC::ExecutableAllocator>(execAlloc_); delete_<JSC::ExecutableAllocator>(execAlloc_);
#endif
delete_<WTF::BumpPointerAllocator>(bumpAlloc_); delete_<WTF::BumpPointerAllocator>(bumpAlloc_);
#ifdef DEBUG #ifdef DEBUG

View File

@ -105,9 +105,11 @@ JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, s
if (regexpCode) { if (regexpCode) {
size_t method = 0, regexp = 0, unused = 0; size_t method = 0, regexp = 0, unused = 0;
#if ENABLE_ASSEMBLER
if (execAlloc_) if (execAlloc_)
execAlloc_->sizeOfCode(&method, &regexp, &unused); execAlloc_->sizeOfCode(&method, &regexp, &unused);
JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */ JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */
#endif
*regexpCode = regexp + unused; *regexpCode = regexp + unused;
} }
@ -132,10 +134,13 @@ void
JSRuntime::setJitHardening(bool enabled) JSRuntime::setJitHardening(bool enabled)
{ {
jitHardening = enabled; jitHardening = enabled;
#if ENABLE_ASSEMBLER
if (execAlloc_) if (execAlloc_)
execAlloc_->setRandomize(enabled); execAlloc_->setRandomize(enabled);
#endif
} }
#if ENABLE_ASSEMBLER
JSC::ExecutableAllocator * JSC::ExecutableAllocator *
JSRuntime::createExecutableAllocator(JSContext *cx) JSRuntime::createExecutableAllocator(JSContext *cx)
{ {
@ -149,6 +154,7 @@ JSRuntime::createExecutableAllocator(JSContext *cx)
js_ReportOutOfMemory(cx); js_ReportOutOfMemory(cx);
return execAlloc_; return execAlloc_;
} }
#endif
WTF::BumpPointerAllocator * WTF::BumpPointerAllocator *
JSRuntime::createBumpPointerAllocator(JSContext *cx) JSRuntime::createBumpPointerAllocator(JSContext *cx)

View File

@ -224,16 +224,22 @@ struct JSRuntime : js::RuntimeFriendFields
* Both of these allocators are used for regular expression code which is shared at the * Both of these allocators are used for regular expression code which is shared at the
* thread-data level. * thread-data level.
*/ */
#if ENABLE_ASSEMBLER
JSC::ExecutableAllocator *execAlloc_; JSC::ExecutableAllocator *execAlloc_;
#endif
WTF::BumpPointerAllocator *bumpAlloc_; WTF::BumpPointerAllocator *bumpAlloc_;
#if ENABLE_ASSEMBLER
JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx); JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
#endif
WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx); WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
public: public:
#if ENABLE_ASSEMBLER
JSC::ExecutableAllocator *getExecutableAllocator(JSContext *cx) { JSC::ExecutableAllocator *getExecutableAllocator(JSContext *cx) {
return execAlloc_ ? execAlloc_ : createExecutableAllocator(cx); return execAlloc_ ? execAlloc_ : createExecutableAllocator(cx);
} }
#endif
WTF::BumpPointerAllocator *getBumpPointerAllocator(JSContext *cx) { WTF::BumpPointerAllocator *getBumpPointerAllocator(JSContext *cx) {
return bumpAlloc_ ? bumpAlloc_ : createBumpPointerAllocator(cx); return bumpAlloc_ ? bumpAlloc_ : createBumpPointerAllocator(cx);
} }

View File

@ -318,12 +318,13 @@ typedef Handle<Value> HandleValue;
} /* namespace js */ } /* namespace js */
#if ENABLE_ASSEMBLER
namespace JSC { namespace JSC {
class ExecutableAllocator; class ExecutableAllocator;
} /* namespace JSC */ } /* namespace JSC */
#endif
namespace WTF { namespace WTF {
class BumpPointerAllocator; class BumpPointerAllocator;

View File

@ -137,6 +137,7 @@ RegExpObject::setSticky(bool enabled)
setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled)); setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
} }
#if ENABLE_YARR_JIT
/* This function should be deleted once bad Android platforms phase out. See bug 604774. */ /* This function should be deleted once bad Android platforms phase out. See bug 604774. */
inline bool inline bool
detail::RegExpCode::isJITRuntimeEnabled(JSContext *cx) detail::RegExpCode::isJITRuntimeEnabled(JSContext *cx)
@ -147,6 +148,7 @@ detail::RegExpCode::isJITRuntimeEnabled(JSContext *cx)
return true; return true;
#endif #endif
} }
#endif
inline bool inline bool
RegExpToShared(JSContext *cx, JSObject &obj, RegExpGuard *g) RegExpToShared(JSContext *cx, JSObject &obj, RegExpGuard *g)

View File

@ -167,7 +167,6 @@ MatchPairs::checkAgainst(size_t inputLength)
/* detail::RegExpCode */ /* detail::RegExpCode */
#if ENABLE_YARR_JIT
void void
RegExpCode::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error) RegExpCode::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
{ {
@ -199,46 +198,9 @@ RegExpCode::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
} }
} }
#else /* !ENABLE_YARR_JIT */
void
RegExpCode::reportPCREError(JSContext *cx, int error)
{
#define REPORT(msg_) \
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
return
switch (error) {
case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred.");
case 1: REPORT(JSMSG_TRAILING_SLASH);
case 2: REPORT(JSMSG_TRAILING_SLASH);
case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 4: REPORT(JSMSG_BAD_QUANTIFIER);
case 5: REPORT(JSMSG_BAD_QUANTIFIER);
case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
case 9: REPORT(JSMSG_BAD_QUANTIFIER);
case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 14: REPORT(JSMSG_MISSING_PAREN);
case 15: REPORT(JSMSG_BAD_BACKREF);
case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
default:
JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
}
#undef REPORT
}
#endif /* ENABLE_YARR_JIT */
bool bool
RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags) RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags)
{ {
#if ENABLE_YARR_JIT
/* Parse the pattern. */ /* Parse the pattern. */
ErrorCode yarrError; ErrorCode yarrError;
YarrPattern yarrPattern(pattern, bool(flags & IgnoreCaseFlag), bool(flags & MultilineFlag), YarrPattern yarrPattern(pattern, bool(flags & IgnoreCaseFlag), bool(flags & MultilineFlag),
@ -255,7 +217,7 @@ RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount
* case we have to bytecode compile it. * case we have to bytecode compile it.
*/ */
#ifdef JS_METHODJIT #if ENABLE_YARR_JIT && defined(JS_METHODJIT)
if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) { if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) {
JSC::ExecutableAllocator *execAlloc = cx->runtime->getExecutableAllocator(cx); JSC::ExecutableAllocator *execAlloc = cx->runtime->getExecutableAllocator(cx);
if (!execAlloc) { if (!execAlloc) {
@ -276,21 +238,11 @@ RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount
return false; return false;
} }
#if ENABLE_YARR_JIT
codeBlock.setFallBack(true); codeBlock.setFallBack(true);
#endif
byteCode = byteCompile(yarrPattern, bumpAlloc).get(); byteCode = byteCompile(yarrPattern, bumpAlloc).get();
return true; return true;
#else /* !defined(ENABLE_YARR_JIT) */
int error = 0;
compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
parenCount, &error);
if (error) {
reportPCREError(cx, error);
return false;
}
return true;
#endif
} }
RegExpRunStatus RegExpRunStatus
@ -305,19 +257,12 @@ RegExpCode::execute(JSContext *cx, const jschar *chars, size_t length, size_t st
else else
result = JSC::Yarr::execute(codeBlock, chars, start, length, output); result = JSC::Yarr::execute(codeBlock, chars, start, length, output);
#else #else
result = jsRegExpExecute(cx, compiled, chars, length, start, output, outputCount); result = JSC::Yarr::interpret(byteCode, chars, start, length, output);
#endif #endif
if (result == -1) if (result == -1)
return RegExpRunStatus_Success_NotFound; return RegExpRunStatus_Success_NotFound;
#if !ENABLE_YARR_JIT
if (result < 0) {
reportPCREError(cx, result);
return RegExpRunStatus_Error;
}
#endif
JS_ASSERT(result >= 0); JS_ASSERT(result >= 0);
return RegExpRunStatus_Success; return RegExpRunStatus_Success;
} }

View File

@ -51,10 +51,8 @@
#include "yarr/Yarr.h" #include "yarr/Yarr.h"
#if ENABLE_YARR_JIT #if ENABLE_YARR_JIT
#include "yarr/YarrJIT.h" #include "yarr/YarrJIT.h"
#include "yarr/YarrSyntaxChecker.h"
#else
#include "yarr/pcre/pcre.h"
#endif #endif
#include "yarr/YarrSyntaxChecker.h"
/* /*
* JavaScript Regular Expressions * JavaScript Regular Expressions
@ -112,68 +110,51 @@ namespace detail {
class RegExpCode class RegExpCode
{ {
#if ENABLE_YARR_JIT
typedef JSC::Yarr::BytecodePattern BytecodePattern; typedef JSC::Yarr::BytecodePattern BytecodePattern;
typedef JSC::Yarr::ErrorCode ErrorCode; typedef JSC::Yarr::ErrorCode ErrorCode;
typedef JSC::Yarr::YarrPattern YarrPattern;
#if ENABLE_YARR_JIT
typedef JSC::Yarr::JSGlobalData JSGlobalData; typedef JSC::Yarr::JSGlobalData JSGlobalData;
typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock; typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock;
typedef JSC::Yarr::YarrPattern YarrPattern;
/* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */ /* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
YarrCodeBlock codeBlock; YarrCodeBlock codeBlock;
BytecodePattern *byteCode;
#else
JSRegExp *compiled;
#endif #endif
BytecodePattern *byteCode;
public: public:
RegExpCode() RegExpCode()
: :
#if ENABLE_YARR_JIT #if ENABLE_YARR_JIT
codeBlock(), codeBlock(),
byteCode(NULL)
#else
compiled(NULL)
#endif #endif
byteCode(NULL)
{ } { }
~RegExpCode() { ~RegExpCode() {
#if ENABLE_YARR_JIT #if ENABLE_YARR_JIT
codeBlock.release(); codeBlock.release();
#endif
if (byteCode) if (byteCode)
Foreground::delete_<BytecodePattern>(byteCode); Foreground::delete_<BytecodePattern>(byteCode);
#else
if (compiled)
jsRegExpFree(compiled);
#endif
} }
static bool checkSyntax(JSContext *cx, TokenStream *tokenStream, JSLinearString *source) { static bool checkSyntax(JSContext *cx, TokenStream *tokenStream, JSLinearString *source) {
#if ENABLE_YARR_JIT
ErrorCode error = JSC::Yarr::checkSyntax(*source); ErrorCode error = JSC::Yarr::checkSyntax(*source);
if (error == JSC::Yarr::NoError) if (error == JSC::Yarr::NoError)
return true; return true;
reportYarrError(cx, tokenStream, error); reportYarrError(cx, tokenStream, error);
return false; return false;
#else
# error "Syntax checking not implemented for !ENABLE_YARR_JIT"
#endif
} }
#if ENABLE_YARR_JIT #if ENABLE_YARR_JIT
static inline bool isJITRuntimeEnabled(JSContext *cx); static inline bool isJITRuntimeEnabled(JSContext *cx);
static void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
#else
static void reportPCREError(JSContext *cx, int error);
#endif #endif
static void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
static size_t getOutputSize(size_t pairCount) { static size_t getOutputSize(size_t pairCount) {
#if ENABLE_YARR_JIT
return pairCount * 2; return pairCount * 2;
#else
return pairCount * 3; /* Should be x2, but PCRE has... needs. */
#endif
} }
bool compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags); bool compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags);

View File

@ -49,9 +49,7 @@
#include "jsprvtd.h" #include "jsprvtd.h"
#include "vm/String.h" #include "vm/String.h"
#include "assembler/wtf/Platform.h" #include "assembler/wtf/Platform.h"
#if ENABLE_YARR_JIT
#include "assembler/jit/ExecutableAllocator.h" #include "assembler/jit/ExecutableAllocator.h"
#endif
namespace JSC { namespace Yarr { namespace JSC { namespace Yarr {