From bed7e5fdbf381f60e06a03306bbb065596351956 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 3 May 2012 09:12:48 +0200 Subject: [PATCH] Bug 720753 - hoist EvalCache from JSCompartment into JSRuntime (r=igor) --- js/src/jscntxt.h | 13 +++++++++++++ js/src/jscompartment.cpp | 21 --------------------- js/src/jscompartment.h | 15 --------------- js/src/jsgc.cpp | 1 + js/src/jsobj.cpp | 30 +++++++++++++++++++++++++----- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 44ff377f09cd..dc37a4845212 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -204,6 +204,18 @@ class ToSourceCache void purge(); }; +class EvalCache +{ + static const unsigned SHIFT = 6; + static const unsigned LENGTH = 1 << SHIFT; + JSScript *table_[LENGTH]; + + public: + EvalCache() { PodArrayZero(table_); } + JSScript **bucket(JSLinearString *str); + void purge(); +}; + class NativeIterCache { static const size_t SIZE = size_t(1) << 8; @@ -755,6 +767,7 @@ struct JSRuntime : js::RuntimeFriendFields js::NewObjectCache newObjectCache; js::NativeIterCache nativeIterCache; js::ToSourceCache toSourceCache; + js::EvalCache evalCache; /* State used by jsdtoa.cpp. */ DtoaState *dtoaState; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 06fe6a8ed111..eac9f8578473 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -92,7 +92,6 @@ JSCompartment::JSCompartment(JSRuntime *rt) sourceMapMap(NULL), debugScriptMap(NULL) { - PodArrayZero(evalCache); setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9); } @@ -102,11 +101,6 @@ JSCompartment::~JSCompartment() Foreground::delete_(scriptCountsMap); Foreground::delete_(sourceMapMap); Foreground::delete_(debugScriptMap); - -#ifdef DEBUG - for (size_t i = 0; i < ArrayLength(evalCache); ++i) - JS_ASSERT(!evalCache[i]); -#endif } bool @@ -536,21 +530,6 @@ void JSCompartment::purge() { dtoaCache.purge(); - - /* - * Clear the hash and reset all evalHashLink to null before the GC. This - * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is - * not null when we have script owned by an object and not from the eval - * cache. - */ - for (size_t i = 0; i < ArrayLength(evalCache); ++i) { - for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) { - JSScript *script = *listHeadp; - JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT); - *listHeadp = NULL; - listHeadp = &script->evalHashLink(); - } - } } void diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index eaa66e602d0b..6cc004824600 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -61,17 +61,6 @@ namespace js { /* Defined in jsapi.cpp */ extern Class dummy_class; -} /* namespace js */ - -#ifndef JS_EVAL_CACHE_SHIFT -# define JS_EVAL_CACHE_SHIFT 6 -#endif - -/* Number of buckets in the hash of eval scripts. */ -#define JS_EVAL_CACHE_SIZE JS_BIT(JS_EVAL_CACHE_SHIFT) - -namespace js { - /* * A single-entry cache for some base-10 double-to-string conversions. This * helps date-format-xparb.js. It also avoids skewing the results for @@ -207,10 +196,6 @@ struct JSCompartment /* Type information about the scripts and objects in this compartment. */ js::types::TypeCompartment types; - public: - /* Hashed lists of scripts created by eval to garbage-collect. */ - JSScript *evalCache[JS_EVAL_CACHE_SIZE]; - void *data; bool active; // GC flag, whether there are active frames js::WrapperMap crossCompartmentWrappers; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 3de35384c8e6..4fc220e93106 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2893,6 +2893,7 @@ PurgeRuntime(JSTracer *trc) rt->newObjectCache.purge(); rt->nativeIterCache.purge(); rt->toSourceCache.purge(); + rt->evalCache.purge(); for (ContextIter acx(rt); !acx.done(); acx.next()) acx->purge(); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 97c8175c564d..3d2728e3180f 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -744,8 +744,27 @@ AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj) # define EVAL_CACHE_CHAIN_LIMIT 4 #endif -static inline JSScript ** -EvalCacheHash(JSContext *cx, JSLinearString *str) +void +EvalCache::purge() +{ + /* + * Purge all scripts from the eval cache. In addition to removing them from + * table_, null out the evalHashLink field of any script removed. Since + * evalHashLink is in a union with globalObject, this allows the GC to + * indiscriminately use the union as a nullable globalObject pointer. + */ + for (size_t i = 0; i < ArrayLength(table_); ++i) { + for (JSScript **listHeadp = &table_[i]; *listHeadp; ) { + JSScript *script = *listHeadp; + JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT); + *listHeadp = script->evalHashLink(); + script->evalHashLink() = NULL; + } + } +} + +inline JSScript ** +EvalCache::bucket(JSLinearString *str) { const jschar *s = str->chars(); size_t n = str->length(); @@ -757,8 +776,9 @@ EvalCacheHash(JSContext *cx, JSLinearString *str) h = JS_ROTATE_LEFT32(h, 4) ^ *s; h *= JS_GOLDEN_RATIO; - h >>= 32 - JS_EVAL_CACHE_SHIFT; - return &cx->compartment->evalCache[h]; + h >>= 32 - SHIFT; + JS_ASSERT(h < ArrayLength(table_)); + return &table_[h]; } static JS_ALWAYS_INLINE JSScript * @@ -857,7 +877,7 @@ class EvalScriptGuard : cx_(cx), str_(str), script_(cx) { - bucket_ = EvalCacheHash(cx, str); + bucket_ = cx->runtime->evalCache.bucket(str); } ~EvalScriptGuard() {