зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3d079626e8
Коммит
092cdf9c83
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче