Bug 702426: Hoist executable allocator for better RegExp code sharing. (r=luke)

--HG--
extra : rebase_source : fa6c50980d6b0539064140567ddaddab45341a49
This commit is contained in:
Chris Leary 2011-11-15 12:18:34 -08:00
parent f784d8150d
commit 90f6a5f8e1
7 changed files with 99 additions and 32 deletions

View File

@ -724,6 +724,7 @@ JSRuntime::JSRuntime()
#ifdef JS_THREADSAFE
interruptCounter(0),
#endif
threadData(thisFromCtor()),
trustedPrincipals_(NULL),
shapeGen(0),
wrapObjectCallback(NULL),

View File

@ -87,6 +87,7 @@
#endif
#include "frontend/TokenStream.h"
#include "frontend/ParseMaps.h"
#include "yarr/BumpPointerAllocator.h"
#include "jsatominlines.h"
#include "jscntxtinlines.h"
@ -98,8 +99,9 @@ using namespace js::gc;
namespace js {
ThreadData::ThreadData()
: interruptFlags(0),
ThreadData::ThreadData(JSRuntime *rt)
: rt(rt),
interruptFlags(0),
#ifdef JS_THREADSAFE
requestDepth(0),
#endif
@ -111,6 +113,8 @@ ThreadData::ThreadData()
#endif
waiveGCQuota(false),
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
execAlloc(NULL),
bumpAlloc(NULL),
repCache(NULL),
dtoaState(NULL),
nativeStackBase(GetNativeStackBase()),
@ -126,6 +130,9 @@ ThreadData::~ThreadData()
{
JS_ASSERT(!repCache);
rt->delete_<JSC::ExecutableAllocator>(execAlloc);
rt->delete_<WTF::BumpPointerAllocator>(bumpAlloc);
if (dtoaState)
js_DestroyDtoaState(dtoaState);
}
@ -140,6 +147,8 @@ ThreadData::init()
void
ThreadData::triggerOperationCallback(JSRuntime *rt)
{
JS_ASSERT(rt == this->rt);
/*
* Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
* the write will become immediately visible to other processors polling
@ -157,13 +166,40 @@ ThreadData::triggerOperationCallback(JSRuntime *rt)
#endif
}
JSC::ExecutableAllocator *
ThreadData::createExecutableAllocator(JSContext *cx)
{
JS_ASSERT(!execAlloc);
JS_ASSERT(cx->runtime == rt);
execAlloc = rt->new_<JSC::ExecutableAllocator>();
if (!execAlloc)
js_ReportOutOfMemory(cx);
return execAlloc;
}
WTF::BumpPointerAllocator *
ThreadData::createBumpPointerAllocator(JSContext *cx)
{
JS_ASSERT(!bumpAlloc);
JS_ASSERT(cx->runtime == rt);
bumpAlloc = rt->new_<WTF::BumpPointerAllocator>();
if (!bumpAlloc)
js_ReportOutOfMemory(cx);
return bumpAlloc;
}
RegExpPrivateCache *
ThreadData::createRegExpPrivateCache(JSRuntime *rt)
ThreadData::createRegExpPrivateCache(JSContext *cx)
{
JS_ASSERT(!repCache);
JS_ASSERT(cx->runtime == rt);
RegExpPrivateCache *newCache = rt->new_<RegExpPrivateCache>(rt);
if (!newCache || !newCache->init()) {
js_ReportOutOfMemory(cx);
rt->delete_<RegExpPrivateCache>(newCache);
return NULL;
}
@ -173,7 +209,7 @@ ThreadData::createRegExpPrivateCache(JSRuntime *rt)
}
void
ThreadData::purgeRegExpPrivateCache(JSRuntime *rt)
ThreadData::purgeRegExpPrivateCache()
{
rt->delete_<RegExpPrivateCache>(repCache);
repCache = NULL;
@ -355,7 +391,7 @@ js_PurgeThreads_PostGlobalSweep(JSContext *cx)
thread->data.purgeRegExpPrivateCache(cx->runtime);
}
#else
cx->runtime->threadData.purgeRegExpPrivateCache(cx->runtime);
cx->runtime->threadData.purgeRegExpPrivateCache();
#endif
}

View File

@ -153,6 +153,8 @@ struct PendingProxyOperation {
};
struct ThreadData {
JSRuntime *rt;
/*
* If non-zero, we were been asked to call the operation callback as soon
* as possible. If the thread has an active request, this contributes
@ -198,23 +200,45 @@ struct ThreadData {
LifoAlloc tempLifoAlloc;
private:
js::RegExpPrivateCache *repCache;
/*
* Both of these allocators are used for regular expression code which is shared at the
* thread-data level.
*/
JSC::ExecutableAllocator *execAlloc;
WTF::BumpPointerAllocator *bumpAlloc;
js::RegExpPrivateCache *repCache;
js::RegExpPrivateCache *createRegExpPrivateCache(JSRuntime *rt);
JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
js::RegExpPrivateCache *createRegExpPrivateCache(JSContext *cx);
public:
js::RegExpPrivateCache *getRegExpPrivateCache() { return repCache; }
JSC::ExecutableAllocator *getOrCreateExecutableAllocator(JSContext *cx) {
if (execAlloc)
return execAlloc;
/* N.B. caller is responsible for reporting OOM. */
js::RegExpPrivateCache *getOrCreateRegExpPrivateCache(JSRuntime *rt) {
return createExecutableAllocator(cx);
}
WTF::BumpPointerAllocator *getOrCreateBumpPointerAllocator(JSContext *cx) {
if (bumpAlloc)
return bumpAlloc;
return createBumpPointerAllocator(cx);
}
js::RegExpPrivateCache *getRegExpPrivateCache() {
return repCache;
}
js::RegExpPrivateCache *getOrCreateRegExpPrivateCache(JSContext *cx) {
if (repCache)
return repCache;
return createRegExpPrivateCache(rt);
return createRegExpPrivateCache(cx);
}
/* Called at the end of the global GC sweep phase to deallocate repCache memory. */
void purgeRegExpPrivateCache(JSRuntime *rt);
void purgeRegExpPrivateCache();
/*
* The GSN cache is per thread since even multi-cx-per-thread embeddings
@ -240,7 +264,7 @@ struct ThreadData {
size_t noGCOrAllocationCheck;
#endif
ThreadData();
ThreadData(JSRuntime *rt);
~ThreadData();
bool init();

View File

@ -87,9 +87,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
hasDebugModeCodeToDrop(false),
#ifdef JS_METHODJIT
jaegerCompartment_(NULL),
#endif
#if ENABLE_YARR_JIT
regExpAllocator(NULL),
#endif
propertyTree(thisForCtor()),
emptyArgumentsShape(NULL),
@ -110,10 +107,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
JSCompartment::~JSCompartment()
{
#if ENABLE_YARR_JIT
Foreground::delete_(regExpAllocator);
#endif
#ifdef JS_METHODJIT
Foreground::delete_(jaegerCompartment_);
#endif
@ -143,10 +136,6 @@ JSCompartment::init(JSContext *cx)
if (!scriptFilenameTable.init())
return false;
regExpAllocator = rt->new_<WTF::BumpPointerAllocator>();
if (!regExpAllocator)
return false;
if (!backEdgeTable.init())
return false;

View File

@ -53,9 +53,6 @@
#pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
#endif
namespace JSC { class ExecutableAllocator; }
namespace WTF { class BumpPointerAllocator; }
namespace js {
/* Holds the number of recording attemps for an address. */
@ -473,7 +470,6 @@ struct JS_FRIEND_API(JSCompartment) {
void getMjitCodeStats(size_t& method, size_t& regexp, size_t& unused) const;
#endif
WTF::BumpPointerAllocator *regExpAllocator;
/*
* Shared scope property tree, and arena-pool for allocating its nodes.

View File

@ -269,6 +269,18 @@ struct TypeCompartment;
} /* namespace js */
namespace JSC {
class ExecutableAllocator;
} /* namespace JSC */
namespace WTF {
class BumpPointerAllocator;
} /* namespace WTF */
} /* export "C++" */
#else

View File

@ -248,7 +248,7 @@ RegExpObject::setSticky(bool enabled)
inline RegExpPrivateCache *
detail::RegExpPrivate::getOrCreateCache(JSContext *cx)
{
if (RegExpPrivateCache *cache = cx->threadData()->getOrCreateRegExpPrivateCache(cx->runtime))
if (RegExpPrivateCache *cache = cx->threadData()->getOrCreateRegExpPrivateCache(cx))
return cache;
js_ReportOutOfMemory(cx);
@ -379,18 +379,27 @@ detail::RegExpPrivateCode::compile(JSContext *cx, JSLinearString &pattern, Token
#ifdef JS_METHODJIT
if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) {
if (!cx->compartment->ensureJaegerCompartmentExists(cx))
JSC::ExecutableAllocator *execAlloc = cx->threadData()->getOrCreateExecutableAllocator(cx);
if (!execAlloc) {
js_ReportOutOfMemory(cx);
return false;
}
JSGlobalData globalData(cx->compartment->jaegerCompartment()->execAlloc());
JSGlobalData globalData(execAlloc);
jitCompile(yarrPattern, &globalData, codeBlock);
if (!codeBlock.isFallBack())
return true;
}
#endif
WTF::BumpPointerAllocator *bumpAlloc = cx->threadData()->getOrCreateBumpPointerAllocator(cx);
if (!bumpAlloc) {
js_ReportOutOfMemory(cx);
return false;
}
codeBlock.setFallBack(true);
byteCode = byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
byteCode = byteCompile(yarrPattern, bumpAlloc).get();
return true;
#else /* !defined(ENABLE_YARR_JIT) */
int error = 0;