From c78af1f2baca4722ffa39a62f0375fd6c2ec5f73 Mon Sep 17 00:00:00 2001 From: Landry Breuil Date: Wed, 7 Mar 2012 12:06:19 +0100 Subject: [PATCH] Bug 691898 - Use YARR interpreter instead of PCRE on platforms where YARR JIT is not supported. r=dmandelin --- js/src/Makefile.in | 23 ++++++------- js/src/jsapi.cpp | 4 +++ js/src/jscntxt.cpp | 6 ++++ js/src/jscntxt.h | 6 ++++ js/src/jsprvtd.h | 3 +- js/src/vm/RegExpObject-inl.h | 2 ++ js/src/vm/RegExpObject.cpp | 63 +++--------------------------------- js/src/vm/RegExpObject.h | 33 ++++--------------- js/src/yarr/wtfbridge.h | 2 -- 9 files changed, 43 insertions(+), 99 deletions(-) diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 5c38969cbac..67c932d4736 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -337,20 +337,21 @@ CPPSRCS += checks.cc \ # 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))) -VPATH += $(srcdir)/yarr/pcre \ +VPATH += $(srcdir)/assembler \ + $(srcdir)/assembler/wtf \ + $(srcdir)/yarr \ $(NULL) CPPSRCS += \ - pcre_compile.cpp \ - pcre_exec.cpp \ - pcre_tables.cpp \ - pcre_xclass.cpp \ - pcre_ucp_searchfuncs.cpp \ + OSAllocatorOS2.cpp \ + OSAllocatorPosix.cpp \ + OSAllocatorWin.cpp \ + PageBlock.cpp \ + YarrInterpreter.cpp \ + YarrPattern.cpp \ + YarrSyntaxChecker.cpp \ $(NULL) else @@ -885,10 +886,10 @@ endif # Needed to "configure" it correctly. Unfortunately these # flags wind up being applied to all code in js/src, not just # 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)) -CXXFLAGS += -DENABLE_JIT=1 +CXXFLAGS += -DENABLE_JIT=1 -DENABLE_ASSEMBLER=1 endif INCLUDES += -I$(srcdir)/assembler -I$(srcdir)/yarr diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 04af605afd7..ae6a72e1b54 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -702,7 +702,9 @@ JSRuntime::JSRuntime() ownerThread_(NULL), #endif tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), +#if ENABLE_ASSEMBLER execAlloc_(NULL), +#endif bumpAlloc_(NULL), nativeStackBase(0), nativeStackQuota(0), @@ -864,7 +866,9 @@ JSRuntime::~JSRuntime() { JS_ASSERT(onOwnerThread()); +#if ENABLE_ASSEMBLER delete_(execAlloc_); +#endif delete_(bumpAlloc_); #ifdef DEBUG diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 414ed5b67d0..48ac1b4bf30 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -105,9 +105,11 @@ JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, s if (regexpCode) { size_t method = 0, regexp = 0, unused = 0; +#if ENABLE_ASSEMBLER if (execAlloc_) execAlloc_->sizeOfCode(&method, ®exp, &unused); JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */ +#endif *regexpCode = regexp + unused; } @@ -132,10 +134,13 @@ void JSRuntime::setJitHardening(bool enabled) { jitHardening = enabled; +#if ENABLE_ASSEMBLER if (execAlloc_) execAlloc_->setRandomize(enabled); +#endif } +#if ENABLE_ASSEMBLER JSC::ExecutableAllocator * JSRuntime::createExecutableAllocator(JSContext *cx) { @@ -149,6 +154,7 @@ JSRuntime::createExecutableAllocator(JSContext *cx) js_ReportOutOfMemory(cx); return execAlloc_; } +#endif WTF::BumpPointerAllocator * JSRuntime::createBumpPointerAllocator(JSContext *cx) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 4d1afcb45f0..0b08f32d9a5 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -224,16 +224,22 @@ struct JSRuntime : js::RuntimeFriendFields * Both of these allocators are used for regular expression code which is shared at the * thread-data level. */ +#if ENABLE_ASSEMBLER JSC::ExecutableAllocator *execAlloc_; +#endif WTF::BumpPointerAllocator *bumpAlloc_; +#if ENABLE_ASSEMBLER JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx); +#endif WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx); public: +#if ENABLE_ASSEMBLER JSC::ExecutableAllocator *getExecutableAllocator(JSContext *cx) { return execAlloc_ ? execAlloc_ : createExecutableAllocator(cx); } +#endif WTF::BumpPointerAllocator *getBumpPointerAllocator(JSContext *cx) { return bumpAlloc_ ? bumpAlloc_ : createBumpPointerAllocator(cx); } diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index afa591ee98d..99973f8cbd1 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -318,12 +318,13 @@ typedef Handle HandleValue; } /* namespace js */ +#if ENABLE_ASSEMBLER namespace JSC { class ExecutableAllocator; } /* namespace JSC */ - +#endif namespace WTF { class BumpPointerAllocator; diff --git a/js/src/vm/RegExpObject-inl.h b/js/src/vm/RegExpObject-inl.h index 12afce24b94..6ca34c5c528 100644 --- a/js/src/vm/RegExpObject-inl.h +++ b/js/src/vm/RegExpObject-inl.h @@ -137,6 +137,7 @@ RegExpObject::setSticky(bool 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. */ inline bool detail::RegExpCode::isJITRuntimeEnabled(JSContext *cx) @@ -147,6 +148,7 @@ detail::RegExpCode::isJITRuntimeEnabled(JSContext *cx) return true; #endif } +#endif inline bool RegExpToShared(JSContext *cx, JSObject &obj, RegExpGuard *g) diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 01763085281..fdaaa938482 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -167,7 +167,6 @@ MatchPairs::checkAgainst(size_t inputLength) /* detail::RegExpCode */ -#if ENABLE_YARR_JIT void 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 RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount, RegExpFlag flags) { -#if ENABLE_YARR_JIT /* Parse the pattern. */ ErrorCode yarrError; 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. */ -#ifdef JS_METHODJIT +#if ENABLE_YARR_JIT && defined(JS_METHODJIT) if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) { JSC::ExecutableAllocator *execAlloc = cx->runtime->getExecutableAllocator(cx); if (!execAlloc) { @@ -276,21 +238,11 @@ RegExpCode::compile(JSContext *cx, JSLinearString &pattern, unsigned *parenCount return false; } +#if ENABLE_YARR_JIT codeBlock.setFallBack(true); +#endif byteCode = byteCompile(yarrPattern, bumpAlloc).get(); 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 @@ -305,19 +257,12 @@ RegExpCode::execute(JSContext *cx, const jschar *chars, size_t length, size_t st else result = JSC::Yarr::execute(codeBlock, chars, start, length, output); #else - result = jsRegExpExecute(cx, compiled, chars, length, start, output, outputCount); + result = JSC::Yarr::interpret(byteCode, chars, start, length, output); #endif if (result == -1) return RegExpRunStatus_Success_NotFound; -#if !ENABLE_YARR_JIT - if (result < 0) { - reportPCREError(cx, result); - return RegExpRunStatus_Error; - } -#endif - JS_ASSERT(result >= 0); return RegExpRunStatus_Success; } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index ff888f0a4e2..2ad38f6b304 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -51,10 +51,8 @@ #include "yarr/Yarr.h" #if ENABLE_YARR_JIT #include "yarr/YarrJIT.h" -#include "yarr/YarrSyntaxChecker.h" -#else -#include "yarr/pcre/pcre.h" #endif +#include "yarr/YarrSyntaxChecker.h" /* * JavaScript Regular Expressions @@ -112,68 +110,51 @@ namespace detail { class RegExpCode { -#if ENABLE_YARR_JIT typedef JSC::Yarr::BytecodePattern BytecodePattern; typedef JSC::Yarr::ErrorCode ErrorCode; + typedef JSC::Yarr::YarrPattern YarrPattern; +#if ENABLE_YARR_JIT typedef JSC::Yarr::JSGlobalData JSGlobalData; typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock; - typedef JSC::Yarr::YarrPattern YarrPattern; /* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */ YarrCodeBlock codeBlock; - BytecodePattern *byteCode; -#else - JSRegExp *compiled; #endif + BytecodePattern *byteCode; public: RegExpCode() : #if ENABLE_YARR_JIT codeBlock(), - byteCode(NULL) -#else - compiled(NULL) #endif + byteCode(NULL) { } ~RegExpCode() { #if ENABLE_YARR_JIT codeBlock.release(); +#endif if (byteCode) Foreground::delete_(byteCode); -#else - if (compiled) - jsRegExpFree(compiled); -#endif } static bool checkSyntax(JSContext *cx, TokenStream *tokenStream, JSLinearString *source) { -#if ENABLE_YARR_JIT ErrorCode error = JSC::Yarr::checkSyntax(*source); if (error == JSC::Yarr::NoError) return true; reportYarrError(cx, tokenStream, error); return false; -#else -# error "Syntax checking not implemented for !ENABLE_YARR_JIT" -#endif } #if ENABLE_YARR_JIT 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 + static void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error); static size_t getOutputSize(size_t pairCount) { -#if ENABLE_YARR_JIT 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); diff --git a/js/src/yarr/wtfbridge.h b/js/src/yarr/wtfbridge.h index ac41d08585f..fb8eb867f65 100644 --- a/js/src/yarr/wtfbridge.h +++ b/js/src/yarr/wtfbridge.h @@ -49,9 +49,7 @@ #include "jsprvtd.h" #include "vm/String.h" #include "assembler/wtf/Platform.h" -#if ENABLE_YARR_JIT #include "assembler/jit/ExecutableAllocator.h" -#endif namespace JSC { namespace Yarr {