Bug 412866 - Reuse regexp arena, original patch by Robin Bate Boerop <moz@shorestreet.com>, refreshed by Ryan VanderMuelen <ryanvm@gmail.com>, r=crowder

This commit is contained in:
Robin Bate Boerop 2008-09-12 15:11:48 -07:00
Родитель 3d079626e8
Коммит 092cdf9c83
5 изменённых файлов: 66 добавлений и 35 удалений

Просмотреть файл

@ -2577,7 +2577,7 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
rt->gcMaxMallocBytes = value;
break;
case JSGC_STACKPOOL_LIFESPAN:
rt->gcStackPoolLifespan = value;
rt->gcEmptyArenaPoolLifespan = value;
break;
}
}

Просмотреть файл

@ -286,8 +286,21 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
cx->version = JSVERSION_DEFAULT;
JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
&cx->scriptStackQuota);
JS_INIT_ARENA_POOL(&cx->tempPool, "temp", 1024, sizeof(jsdouble),
&cx->scriptStackQuota);
JS_INIT_ARENA_POOL(&cx->tempPool, "temp",
1024, /* FIXME: bug 421435 */
sizeof(jsdouble), &cx->scriptStackQuota);
/*
* To avoid multiple allocations in InitMatch() (in jsregexp.c), the arena
* size parameter should be at least as big as:
* INITIAL_BACKTRACK
* + (sizeof(REProgState) * INITIAL_STATESTACK)
* + (offsetof(REMatchState, parens) + avgParanSize * sizeof(RECapture))
*/
JS_INIT_ARENA_POOL(&cx->regexpPool, "regexp",
12 * 1024 - 40, /* FIXME: bug 421435 */
sizeof(void *), &cx->scriptStackQuota);
if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
js_DestroyContext(cx, JSDCM_NEW_FAILED);
@ -455,6 +468,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
/* Free the stuff hanging off of cx. */
JS_FinishArenaPool(&cx->stackPool);
JS_FinishArenaPool(&cx->tempPool);
JS_FinishArenaPool(&cx->regexpPool);
if (cx->lastMessage)
free(cx->lastMessage);

Просмотреть файл

@ -254,7 +254,7 @@ struct JSRuntime {
uint32 gcLastBytes;
uint32 gcMaxBytes;
uint32 gcMaxMallocBytes;
uint32 gcStackPoolLifespan;
uint32 gcEmptyArenaPoolLifespan;
uint32 gcLevel;
uint32 gcNumber;
JSTracer *gcMarkingTracer;
@ -884,6 +884,9 @@ struct JSContext {
/* Security callbacks that override any defined on the runtime. */
JSSecurityCallbacks *securityCallbacks;
/* Pinned regexp pool used for regular expressions. */
JSArenaPool regexpPool;
};
#ifdef JS_THREADSAFE

Просмотреть файл

@ -1251,7 +1251,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
* for default backward API compatibility.
*/
rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
rt->gcStackPoolLifespan = 30000;
rt->gcEmptyArenaPoolLifespan = 30000;
METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
return JS_TRUE;
@ -2783,24 +2783,36 @@ TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr)
JS_FRIEND_API(void)
js_TraceContext(JSTracer *trc, JSContext *acx)
{
JSArena *a;
int64 age;
JSStackFrame *fp, *nextChain;
JSStackHeader *sh;
JSTempValueRooter *tvr;
if (IS_GC_MARKING_TRACER(trc)) {
#define FREE_OLD_ARENAS(pool) \
JS_BEGIN_MACRO \
int64 _age; \
JSArena * _a = (pool).current; \
if (_a == (pool).first.next && \
_a->avail == _a->base + sizeof(int64)) { \
_age = JS_Now() - *(int64 *) _a->base; \
if (_age > (int64) acx->runtime->gcEmptyArenaPoolLifespan * \
1000) \
JS_FreeArenaPool(&(pool)); \
} \
JS_END_MACRO
/*
* Release stackPool here, if it has been in existence for longer than
* the limit specified by gcStackPoolLifespan.
* Release the stackPool's arenas if the stackPool has existed for
* longer than the limit specified by gcEmptyArenaPoolLifespan.
*/
a = acx->stackPool.current;
if (a == acx->stackPool.first.next &&
a->avail == a->base + sizeof(int64)) {
age = JS_Now() - *(int64 *) a->base;
if (age > (int64) acx->runtime->gcStackPoolLifespan * 1000)
JS_FinishArenaPool(&acx->stackPool);
}
FREE_OLD_ARENAS(acx->stackPool);
/*
* Release the regexpPool's arenas based on the same criterion as for
* the stackPool.
*/
FREE_OLD_ARENAS(acx->regexpPool);
/*
* Clear the double free list to release all the pre-allocated doubles.

Просмотреть файл

@ -338,10 +338,6 @@ typedef struct REGlobalData {
size_t cursz; /* size of current stack entry */
size_t backTrackCount; /* how many times we've backtracked */
size_t backTrackLimit; /* upper limit on backtrack states */
JSArenaPool pool; /* It's faster to use one malloc'd pool
than to malloc/free the three items
that are allocated from this pool */
} REGlobalData;
/*
@ -2107,7 +2103,7 @@ PushBackTrackState(REGlobalData *gData, REOp op,
JS_COUNT_OPERATION(gData->cx, JSOW_ALLOCATION);
btincr = JS_ROUNDUP(btincr, btsize);
JS_ARENA_GROW_CAST(gData->backTrackStack, REBackTrackData *,
&gData->pool, btsize, btincr);
&gData->cx->regexpPool, btsize, btincr);
if (!gData->backTrackStack) {
js_ReportOutOfScriptQuota(gData->cx);
gData->ok = JS_FALSE;
@ -2560,7 +2556,8 @@ ReallocStateStack(REGlobalData *gData)
size_t limit = gData->stateStackLimit;
size_t sz = sizeof(REProgState) * limit;
JS_ARENA_GROW_CAST(gData->stateStack, REProgState *, &gData->pool, sz, sz);
JS_ARENA_GROW_CAST(gData->stateStack, REProgState *,
&gData->cx->regexpPool, sz, sz);
if (!gData->stateStack) {
js_ReportOutOfScriptQuota(gData->cx);
gData->ok = JS_FALSE;
@ -3377,7 +3374,7 @@ InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re, size_t length)
gData->backTrackStackSize = INITIAL_BACKTRACK;
JS_ARENA_ALLOCATE_CAST(gData->backTrackStack, REBackTrackData *,
&gData->pool,
&cx->regexpPool,
INITIAL_BACKTRACK);
if (!gData->backTrackStack)
goto bad;
@ -3394,7 +3391,7 @@ InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re, size_t length)
gData->stateStackLimit = INITIAL_STATESTACK;
JS_ARENA_ALLOCATE_CAST(gData->stateStack, REProgState *,
&gData->pool,
&cx->regexpPool,
sizeof(REProgState) * INITIAL_STATESTACK);
if (!gData->stateStack)
goto bad;
@ -3405,7 +3402,7 @@ InitMatch(JSContext *cx, REGlobalData *gData, JSRegExp *re, size_t length)
gData->ok = JS_TRUE;
JS_ARENA_ALLOCATE_CAST(result, REMatchState *,
&gData->pool,
&cx->regexpPool,
offsetof(REMatchState, parens)
+ re->parenCount * sizeof(RECapture));
if (!result)
@ -3444,6 +3441,8 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
JSObject *obj;
RECapture *parsub = NULL;
void *mark;
int64 *timestamp;
/*
* It's safe to load from cp because JSStrings have a zero at the end,
@ -3459,15 +3458,18 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
gData.start = start;
gData.skipped = 0;
/*
* To avoid multiple allocations in InitMatch(), the arena size parameter
* should be at least as big as:
* INITIAL_BACKTRACK
* + (sizeof(REProgState) * INITIAL_STATESTACK)
* + (offsetof(REMatchState, parens) + avgParanSize * sizeof(RECapture))
*/
JS_INIT_ARENA_POOL(&gData.pool, "RegExpPool", 12288, 4,
&cx->scriptStackQuota);
if (!cx->regexpPool.first.next) {
/*
* The first arena in the regexpPool must have a timestamp at its base.
*/
JS_ARENA_ALLOCATE_CAST(timestamp, int64 *,
&cx->regexpPool, sizeof *timestamp);
if (!timestamp)
return JS_FALSE;
*timestamp = JS_Now();
}
mark = JS_ARENA_MARK(&cx->regexpPool);
x = InitMatch(cx, &gData, re, length);
if (!x) {
@ -3642,7 +3644,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
res->rightContext.length = gData.cpend - ep;
out:
JS_FinishArenaPool(&gData.pool);
JS_ARENA_RELEASE(&cx->regexpPool, mark);
return ok;
}