mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Fixes for bug 33390 (r=mccabe, sr=shaver)
- Optimize compile (parse+emit) operation to generate code for each top-level statement or function in turn, recycling JSParseNodes as we go for greatly reduced "long linear script" footprint. - Fix O(n**2) growth problems in bytecode and srcnote generation. - Add js_ParseTokenStream entry point to compiler, for tree-generation without code-generation. Move JSOP_EVAL instruction selection from code-generator to parser, to match other such specializations and enable js_ParseTokenStream. - Fix js_CompileTokenStream (and get it right in new js_ParseTokenStream) to respect JSOPTION_VAROBJFIX. - Clean up bracing, multi-line conditions, and overlong lines.
This commit is contained in:
parent
6079447d19
commit
bb40b036ad
@ -77,7 +77,7 @@ JS_InitArenaPool(JSArenaPool *pool, const char *name, JSUint32 size, JSUint32 al
|
||||
pool->mask = JS_BITMASK(JS_CeilingLog2(align));
|
||||
pool->first.next = NULL;
|
||||
pool->first.base = pool->first.avail = pool->first.limit =
|
||||
(jsuword)JS_ARENA_ALIGN(pool, &pool->first + 1);
|
||||
JS_ARENA_ALIGN(pool, &pool->first + 1);
|
||||
pool->current = &pool->first;
|
||||
pool->arenasize = size;
|
||||
#ifdef JS_ARENAMETER
|
||||
@ -131,7 +131,7 @@ JS_ArenaAllocate(JSArenaPool *pool, JSUint32 nb)
|
||||
JS_COUNT_ARENA(pool,++);
|
||||
COUNT(pool, nmallocs);
|
||||
claim:
|
||||
a->base = a->avail = (jsuword)JS_ARENA_ALIGN(pool, a + 1);
|
||||
a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1);
|
||||
continue;
|
||||
}
|
||||
a = a->next; /* move to next arena */
|
||||
@ -141,6 +141,34 @@ JS_ArenaAllocate(JSArenaPool *pool, JSUint32 nb)
|
||||
return p;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaRealloc(JSArenaPool *pool, void *p, JSUint32 size, JSUint32 incr)
|
||||
{
|
||||
JSArena **ap, *a;
|
||||
jsuword aoff;
|
||||
|
||||
ap = &pool->first.next;
|
||||
while ((a = *ap) != pool->current)
|
||||
ap = &a->next;
|
||||
JS_ASSERT(a->base == (jsuword)p);
|
||||
size += incr;
|
||||
aoff = size;
|
||||
JS_ASSERT(size > pool->arenasize);
|
||||
size += sizeof *a + pool->mask; /* header and alignment slop */
|
||||
a = (JSArena *) realloc(a, size);
|
||||
if (!a)
|
||||
return NULL;
|
||||
*ap = a;
|
||||
pool->current = a;
|
||||
#ifdef JS_ARENAMETER
|
||||
pool->stats.nreallocs++;
|
||||
#endif
|
||||
a->base = JS_ARENA_ALIGN(pool, a + 1);
|
||||
a->limit = (jsuword)a + size;
|
||||
a->avail = JS_ARENA_ALIGN(pool, a->base + aoff);
|
||||
return (void *)a->base;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaGrow(JSArenaPool *pool, void *p, JSUint32 size, JSUint32 incr)
|
||||
{
|
||||
@ -204,7 +232,7 @@ JS_ArenaRelease(JSArenaPool *pool, char *mark)
|
||||
|
||||
for (a = &pool->first; a; a = a->next) {
|
||||
if (JS_UPTRDIFF(mark, a->base) <= JS_UPTRDIFF(a->avail, a->base)) {
|
||||
a->avail = (jsuword)JS_ARENA_ALIGN(pool, mark);
|
||||
a->avail = JS_ARENA_ALIGN(pool, mark);
|
||||
FreeArenaList(pool, a, JS_TRUE);
|
||||
return;
|
||||
}
|
||||
@ -328,14 +356,22 @@ JS_PUBLIC_API(void)
|
||||
JS_DumpArenaStats(FILE *fp)
|
||||
{
|
||||
JSArenaStats *stats;
|
||||
double mean, variance;
|
||||
uint32 nallocs, nbytes;
|
||||
double mean, variance, sigma;
|
||||
|
||||
for (stats = arena_stats_list; stats; stats = stats->next) {
|
||||
if (stats->nallocs != 0) {
|
||||
mean = (double)stats->nbytes / stats->nallocs;
|
||||
variance = fabs(stats->variance / stats->nallocs - mean * mean);
|
||||
nallocs = stats->nallocs;
|
||||
if (nallocs != 0) {
|
||||
nbytes = stats->nbytes;
|
||||
mean = (double)nbytes / nallocs;
|
||||
variance = stats->variance * nallocs - nbytes * nbytes;
|
||||
if (variance < 0 || nallocs == 1)
|
||||
variance = 0;
|
||||
else
|
||||
variance /= nallocs * (nallocs - 1);
|
||||
sigma = sqrt(variance);
|
||||
} else {
|
||||
mean = variance = 0;
|
||||
mean = variance = sigma = 0;
|
||||
}
|
||||
|
||||
fprintf(fp, "\n%s allocation statistics:\n", stats->name);
|
||||
@ -346,11 +382,12 @@ JS_DumpArenaStats(FILE *fp)
|
||||
fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs);
|
||||
fprintf(fp, " number of allocation growths: %u\n", stats->ngrows);
|
||||
fprintf(fp, " number of in-place growths: %u\n", stats->ninplace);
|
||||
fprintf(fp, " number of realloc'ing growths: %u\n", stats->nreallocs);
|
||||
fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
|
||||
fprintf(fp, " number of fast releases: %u\n", stats->nfastrels);
|
||||
fprintf(fp, " total bytes allocated: %u\n", stats->nbytes);
|
||||
fprintf(fp, " mean allocation size: %g\n", mean);
|
||||
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
|
||||
fprintf(fp, " standard deviation: %g\n", sigma);
|
||||
fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc);
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ struct JSArenaStats {
|
||||
uint32 ndeallocs; /* number of lifetime deallocations */
|
||||
uint32 ngrows; /* number of JS_ARENA_GROW() calls */
|
||||
uint32 ninplace; /* number of in-place growths */
|
||||
uint32 nreallocs; /* number of arena grow extending reallocs */
|
||||
uint32 nreleases; /* number of JS_ARENA_RELEASE() calls */
|
||||
uint32 nfastrels; /* number of "fast path" releases */
|
||||
size_t nbytes; /* total bytes allocated */
|
||||
@ -94,8 +95,8 @@ struct JSArenaPool {
|
||||
* per ALLOCATE and GROW.
|
||||
*/
|
||||
#ifdef JS_ARENA_CONST_ALIGN_MASK
|
||||
#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + JS_ARENA_CONST_ALIGN_MASK) \
|
||||
& ~JS_ARENA_CONST_ALIGN_MASK)
|
||||
#define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + JS_ARENA_CONST_ALIGN_MASK) \
|
||||
& ~(jsuword)JS_ARENA_CONST_ALIGN_MASK)
|
||||
|
||||
#define JS_INIT_ARENA_POOL(pool, name, size) \
|
||||
JS_InitArenaPool(pool, name, size, JS_ARENA_CONST_ALIGN_MASK + 1)
|
||||
@ -128,48 +129,53 @@ struct JSArenaPool {
|
||||
|
||||
#define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSArena *_a = (pool)->current; \
|
||||
size_t _incr = JS_ARENA_ALIGN(pool, incr); \
|
||||
jsuword _p = _a->avail; \
|
||||
jsuword _q = _p + _incr; \
|
||||
if (_p == (jsuword)(p) + JS_ARENA_ALIGN(pool, size) && \
|
||||
_q <= _a->limit) { \
|
||||
_a->avail = _q; \
|
||||
JS_ArenaCountInplaceGrowth(pool, size, incr); \
|
||||
} else { \
|
||||
p = (type) JS_ArenaGrow(pool, p, size, incr); \
|
||||
} \
|
||||
JS_ArenaCountGrowth(pool, size, incr); \
|
||||
JSArena *_a = (pool)->current; \
|
||||
size_t _incr = JS_ARENA_ALIGN(pool, incr); \
|
||||
jsuword _p = _a->avail; \
|
||||
jsuword _q = _p + _incr; \
|
||||
if (_p == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \
|
||||
if (_q <= _a->limit) { \
|
||||
_a->avail = _q; \
|
||||
JS_ArenaCountInplaceGrowth(pool, size, incr); \
|
||||
} else if ((jsuword)(p) == _a->base) { \
|
||||
p = (type) JS_ArenaRealloc(pool, p, size, incr); \
|
||||
} else { \
|
||||
p = (type) JS_ArenaGrow(pool, p, size, incr); \
|
||||
} \
|
||||
} else { \
|
||||
p = (type) JS_ArenaGrow(pool, p, size, incr); \
|
||||
} \
|
||||
JS_ArenaCountGrowth(pool, size, incr); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail)
|
||||
#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q))
|
||||
#define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define JS_FREE_PATTERN 0xDA
|
||||
#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \
|
||||
memset((void*)(a)->avail, JS_FREE_PATTERN, \
|
||||
(a)->limit - (a)->avail))
|
||||
#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \
|
||||
memset((void*)(a)->avail, JS_FREE_PATTERN, \
|
||||
(a)->limit - (a)->avail))
|
||||
#define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \
|
||||
(a)->limit - (jsuword)(a))
|
||||
(a)->limit - (jsuword)(a))
|
||||
#else
|
||||
#define JS_CLEAR_UNUSED(a) /* nothing */
|
||||
#define JS_CLEAR_UNUSED(a) /* nothing */
|
||||
#define JS_CLEAR_ARENA(a) /* nothing */
|
||||
#endif
|
||||
|
||||
#define JS_ARENA_RELEASE(pool, mark) \
|
||||
JS_BEGIN_MACRO \
|
||||
char *_m = (char *)(mark); \
|
||||
JSArena *_a = (pool)->current; \
|
||||
if (_a != &(pool)->first && \
|
||||
JS_UPTRDIFF(_m, _a->base) <= JS_UPTRDIFF(_a->avail, _a->base)) { \
|
||||
_a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \
|
||||
JS_CLEAR_UNUSED(_a); \
|
||||
JS_ArenaCountRetract(pool, _m); \
|
||||
} else { \
|
||||
JS_ArenaRelease(pool, _m); \
|
||||
} \
|
||||
JS_ArenaCountRelease(pool, _m); \
|
||||
char *_m = (char *)(mark); \
|
||||
JSArena *_a = (pool)->current; \
|
||||
if (_a != &(pool)->first && \
|
||||
JS_UPTRDIFF(_m, _a->base) <= JS_UPTRDIFF(_a->avail, _a->base)) { \
|
||||
_a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \
|
||||
JS_CLEAR_UNUSED(_a); \
|
||||
JS_ArenaCountRetract(pool, _m); \
|
||||
} else { \
|
||||
JS_ArenaRelease(pool, _m); \
|
||||
} \
|
||||
JS_ArenaCountRelease(pool, _m); \
|
||||
JS_END_MACRO
|
||||
|
||||
#ifdef JS_ARENAMETER
|
||||
@ -180,12 +186,12 @@ struct JSArenaPool {
|
||||
|
||||
#define JS_ARENA_DESTROY(pool, a, pnext) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_COUNT_ARENA(pool,--); \
|
||||
if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
|
||||
*(pnext) = (a)->next; \
|
||||
JS_CLEAR_ARENA(a); \
|
||||
free(a); \
|
||||
(a) = NULL; \
|
||||
JS_COUNT_ARENA(pool,--); \
|
||||
if ((pool)->current == (a)) (pool)->current = &(pool)->first; \
|
||||
*(pnext) = (a)->next; \
|
||||
JS_CLEAR_ARENA(a); \
|
||||
free(a); \
|
||||
(a) = NULL; \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
@ -194,7 +200,7 @@ struct JSArenaPool {
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_InitArenaPool(JSArenaPool *pool, const char *name, JSUint32 size,
|
||||
JSUint32 align);
|
||||
JSUint32 align);
|
||||
|
||||
/*
|
||||
* Free the arenas in pool. The user may continue to allocate from pool
|
||||
@ -243,6 +249,9 @@ JS_ArenaShutDown(void);
|
||||
extern JS_PUBLIC_API(void *)
|
||||
JS_ArenaAllocate(JSArenaPool *pool, JSUint32 nb);
|
||||
|
||||
extern JS_PUBLIC_API(void *)
|
||||
JS_ArenaRealloc(JSArenaPool *pool, void *p, JSUint32 size, JSUint32 incr);
|
||||
|
||||
extern JS_PUBLIC_API(void *)
|
||||
JS_ArenaGrow(JSArenaPool *pool, void *p, JSUint32 size, JSUint32 incr);
|
||||
|
||||
@ -260,7 +269,7 @@ extern JS_PUBLIC_API(void)
|
||||
JS_ArenaCountInplaceGrowth(JSArenaPool *pool, JSUint32 size, JSUint32 incr);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ArenaCountGrowth(JSArenaPool *pool, JSUint32 size, JSUint32incr);
|
||||
JS_ArenaCountGrowth(JSArenaPool *pool, JSUint32 size, JSUint32 incr);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ArenaCountRelease(JSArenaPool *pool, char *mark);
|
||||
|
@ -816,7 +816,7 @@ JS_FRIEND_API(void)
|
||||
js_FreeAtomMap(JSContext *cx, JSAtomMap *map)
|
||||
{
|
||||
if (map->vector) {
|
||||
free(map->vector);
|
||||
JS_free(cx, map->vector);
|
||||
map->vector = NULL;
|
||||
}
|
||||
map->length = 0;
|
||||
|
@ -81,12 +81,12 @@ struct JSAtomListElement {
|
||||
|
||||
#define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key)
|
||||
#define ALE_INDEX(ale) ((jsatomid) (ale)->entry.value)
|
||||
#define ALE_NODE(ale) ((JSParseNode *) (ale)->entry.value)
|
||||
#define ALE_JSOP(ale) ((JSOp) (ale)->entry.value)
|
||||
#define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next)
|
||||
|
||||
#define ALE_SET_ATOM(ale,atom) ((ale)->entry.key = (const void *)(atom))
|
||||
#define ALE_SET_INDEX(ale,index)((ale)->entry.value = (void *)(index))
|
||||
#define ALE_SET_NODE(ale,pn) ((ale)->entry.value = (void *)(pn))
|
||||
#define ALE_SET_JSOP(ale,op) ((ale)->entry.value = (void *)(op))
|
||||
#define ALE_SET_NEXT(ale,link) ((ale)->entry.next = (JSHashEntry *)(link))
|
||||
|
||||
struct JSAtomList {
|
||||
|
105
js/src/jsemit.c
105
js/src/jsemit.c
@ -43,8 +43,10 @@
|
||||
#include "jstypes.h"
|
||||
#include "jsarena.h" /* Added by JSIFY */
|
||||
#include "jsutil.h" /* Added by JSIFY */
|
||||
#include "jsbit.h"
|
||||
#include "jsprf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
#include "jsemit.h"
|
||||
@ -56,13 +58,15 @@
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#define CGINCR 256 /* code allocation increment */
|
||||
#define SNINCR 64 /* srcnote allocation increment */
|
||||
#define TNINCR 64 /* trynote allocation increment */
|
||||
/* Allocation grain counts, must be powers of two in general. */
|
||||
#define BYTECODE_GRAIN 256 /* code allocation increment */
|
||||
#define SRCNOTE_GRAIN 64 /* initial srcnote allocation increment */
|
||||
#define TRYNOTE_GRAIN 64 /* trynote allocation increment */
|
||||
|
||||
#define CGINCR_SIZE (CGINCR * sizeof(jsbytecode))
|
||||
#define SNINCR_SIZE (SNINCR * sizeof(jssrcnote))
|
||||
#define TNINCR_SIZE (TNINCR * sizeof(JSTryNote))
|
||||
/* Macros to compute byte sizes from typed element counts. */
|
||||
#define BYTECODE_SIZE(n) ((n) * sizeof(jsbytecode))
|
||||
#define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote))
|
||||
#define TRYNOTE_SIZE(n) ((n) * sizeof(JSTryNote))
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
|
||||
@ -70,6 +74,8 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
|
||||
JSPrincipals *principals)
|
||||
{
|
||||
memset(cg, 0, sizeof *cg);
|
||||
TREE_CONTEXT_INIT(&cg->treeContext);
|
||||
cg->treeContext.flags |= TCF_COMPILING;
|
||||
cg->codeMark = JS_ARENA_MARK(&cx->codePool);
|
||||
cg->noteMark = JS_ARENA_MARK(&cx->notePool);
|
||||
cg->tempMark = JS_ARENA_MARK(&cx->tempPool);
|
||||
@ -77,18 +83,18 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
|
||||
cg->filename = filename;
|
||||
cg->firstLine = cg->currentLine = lineno;
|
||||
cg->principals = principals;
|
||||
TREE_CONTEXT_INIT(&cg->treeContext);
|
||||
ATOM_LIST_INIT(&cg->atomList);
|
||||
cg->noteMask = SRCNOTE_GRAIN - 1;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
TREE_CONTEXT_FINISH(&cg->treeContext);
|
||||
JS_ARENA_RELEASE(&cx->codePool, cg->codeMark);
|
||||
JS_ARENA_RELEASE(&cx->notePool, cg->noteMark);
|
||||
JS_ARENA_RELEASE(&cx->tempPool, cg->tempMark);
|
||||
TREE_CONTEXT_FREE(&cg->treeContext);
|
||||
}
|
||||
|
||||
static ptrdiff_t
|
||||
@ -96,29 +102,31 @@ EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
|
||||
{
|
||||
jsbytecode *base, *limit, *next;
|
||||
ptrdiff_t offset, length;
|
||||
size_t cgincr, cgsize;
|
||||
size_t incr, size;
|
||||
|
||||
base = CG_BASE(cg);
|
||||
next = CG_NEXT(cg);
|
||||
limit = CG_LIMIT(cg);
|
||||
offset = PTRDIFF(next, base, jsbytecode);
|
||||
if ((jsuword)(next + delta) > (jsuword)limit) {
|
||||
length = PTRDIFF(limit, base, jsbytecode);
|
||||
delta = JS_ROUNDUP(delta, CGINCR);
|
||||
cgincr = delta * sizeof(jsbytecode);
|
||||
if (base) {
|
||||
cgsize = length * sizeof(jsbytecode);
|
||||
JS_ARENA_GROW_CAST(base, jsbytecode *, &cx->codePool, cgsize,
|
||||
cgincr);
|
||||
length = offset + delta;
|
||||
length = (length <= BYTECODE_GRAIN)
|
||||
? BYTECODE_GRAIN
|
||||
: JS_BIT(JS_CeilingLog2(length));
|
||||
incr = BYTECODE_SIZE(length);
|
||||
if (!base) {
|
||||
JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, &cx->codePool, incr);
|
||||
} else {
|
||||
JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, &cx->codePool, cgincr);
|
||||
size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));
|
||||
incr -= size;
|
||||
JS_ARENA_GROW_CAST(base, jsbytecode *, &cx->codePool, size, incr);
|
||||
}
|
||||
if (!base) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return -1;
|
||||
}
|
||||
CG_BASE(cg) = base;
|
||||
CG_LIMIT(cg) = base + length + delta;
|
||||
CG_LIMIT(cg) = base + length;
|
||||
CG_NEXT(cg) = base + offset;
|
||||
}
|
||||
return offset;
|
||||
@ -287,8 +295,6 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
|
||||
stmt->label = NULL;
|
||||
stmt->down = tc->topStmt;
|
||||
tc->topStmt = stmt;
|
||||
if (!stmt->down)
|
||||
tc->flags &= ~TCF_TOP_LEVEL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -422,11 +428,7 @@ js_EmitContinue(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *stmt,
|
||||
extern void
|
||||
js_PopStatement(JSTreeContext *tc)
|
||||
{
|
||||
JSStmtInfo *stmt = tc->topStmt;
|
||||
|
||||
tc->topStmt = stmt->down;
|
||||
if (!stmt->down)
|
||||
tc->flags |= TCF_TOP_LEVEL;
|
||||
tc->topStmt = tc->topStmt->down;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -2436,15 +2438,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* First, emit code for the left operand to evaluate the callable or
|
||||
* constructable object expression.
|
||||
*/
|
||||
op = pn->pn_op;
|
||||
pn2 = pn->pn_head;
|
||||
if (pn2->pn_op == JSOP_NAME &&
|
||||
pn2->pn_atom == cx->runtime->atomState.evalAtom) {
|
||||
if (JSVERSION_IS_ECMA(cx->version))
|
||||
op = JSOP_EVAL;
|
||||
cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
|
||||
if (!js_EmitTree(cx, cg, pn2))
|
||||
return JS_FALSE;
|
||||
|
||||
@ -2470,7 +2464,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
|
||||
return JS_FALSE;
|
||||
argc = pn->pn_count - 1;
|
||||
if (js_Emit3(cx, cg, op, ARGC_HI(argc), ARGC_LO(argc)) < 0)
|
||||
if (js_Emit3(cx, cg, pn->pn_op, ARGC_HI(argc), ARGC_LO(argc)) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
@ -2743,17 +2737,20 @@ AllocSrcNote(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
intN index;
|
||||
JSArenaPool *pool;
|
||||
size_t incr, size;
|
||||
size_t size;
|
||||
|
||||
index = cg->noteCount;
|
||||
if ((uintN)index % SNINCR == 0) {
|
||||
if (((uintN)index & cg->noteMask) == 0) {
|
||||
pool = &cx->notePool;
|
||||
incr = SNINCR_SIZE;
|
||||
size = SRCNOTE_SIZE(cg->noteMask + 1);
|
||||
if (!cg->notes) {
|
||||
JS_ARENA_ALLOCATE_CAST(cg->notes, jssrcnote *, pool, incr);
|
||||
/* Allocate the first note array lazily; leave noteMask alone. */
|
||||
JS_ARENA_ALLOCATE_CAST(cg->notes, jssrcnote *, pool, size);
|
||||
} else {
|
||||
size = cg->noteCount * sizeof(jssrcnote);
|
||||
JS_ARENA_GROW_CAST(cg->notes, jssrcnote *, pool, size, incr);
|
||||
/* Grow by doubling note array size; update noteMask on success. */
|
||||
JS_ARENA_GROW_CAST(cg->notes, jssrcnote *, pool, size, size);
|
||||
if (cg->notes)
|
||||
cg->noteMask = (cg->noteMask << 1) | 1;
|
||||
}
|
||||
if (!cg->notes) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
@ -2845,17 +2842,17 @@ static JSBool
|
||||
GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
JSArenaPool *pool;
|
||||
size_t incr, size;
|
||||
size_t size;
|
||||
|
||||
/* Grow by doubling note array size; update noteMask on success. */
|
||||
pool = &cx->notePool;
|
||||
incr = SNINCR_SIZE;
|
||||
size = cg->noteCount * sizeof(jssrcnote);
|
||||
size = JS_ROUNDUP(size, incr);
|
||||
JS_ARENA_GROW_CAST(cg->notes, jssrcnote *, pool, size, incr);
|
||||
size = SRCNOTE_SIZE(cg->noteMask + 1);
|
||||
JS_ARENA_GROW_CAST(cg->notes, jssrcnote *, pool, size, size);
|
||||
if (!cg->notes) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
cg->noteMask = (cg->noteMask << 1) | 1;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -2923,7 +2920,7 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
|
||||
* accomodate either the first or second byte of additional storage
|
||||
* required by this 3-byte offset.
|
||||
*/
|
||||
if ((cg->noteCount + 1) % SNINCR <= 1) {
|
||||
if (((cg->noteCount + 1) & cg->noteMask) <= 1) {
|
||||
if (!GrowSrcNotes(cx, cg))
|
||||
return JS_FALSE;
|
||||
sn = cg->notes + index;
|
||||
@ -2933,7 +2930,7 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
|
||||
diff = cg->noteCount - (index + 3);
|
||||
JS_ASSERT(diff >= 0);
|
||||
if (diff > 0)
|
||||
memmove(sn + 3, sn + 1, diff * sizeof(jssrcnote));
|
||||
memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
|
||||
}
|
||||
*sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
|
||||
*sn++ = (jssrcnote)(offset >> 8);
|
||||
@ -2950,10 +2947,10 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
|
||||
count = cg->noteCount;
|
||||
tmp = cg->notes;
|
||||
final = (jssrcnote *) JS_malloc(cx, (count + 1) * sizeof(jssrcnote));
|
||||
final = (jssrcnote *) JS_malloc(cx, SRCNOTE_SIZE(count + 1));
|
||||
if (!final)
|
||||
return NULL;
|
||||
memcpy(final, tmp, count * sizeof(jssrcnote));
|
||||
memcpy(final, tmp, SRCNOTE_SIZE(count));
|
||||
SN_MAKE_TERMINATOR(&final[count]);
|
||||
return final;
|
||||
}
|
||||
@ -2964,7 +2961,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
size_t size, incr;
|
||||
ptrdiff_t delta;
|
||||
|
||||
size = cg->treeContext.tryCount * sizeof(JSTryNote);
|
||||
size = TRYNOTE_SIZE(cg->treeContext.tryCount);
|
||||
if (size <= cg->tryNoteSpace)
|
||||
return JS_TRUE;
|
||||
|
||||
@ -2974,7 +2971,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
* in-place growth, and we never recycle old free space in an arena.
|
||||
*/
|
||||
if (!cg->tryBase) {
|
||||
size = JS_ROUNDUP(size, TNINCR_SIZE);
|
||||
size = JS_ROUNDUP(size, TRYNOTE_SIZE(TRYNOTE_GRAIN));
|
||||
JS_ARENA_ALLOCATE_CAST(cg->tryBase, JSTryNote *, &cx->tempPool, size);
|
||||
if (!cg->tryBase)
|
||||
return JS_FALSE;
|
||||
@ -2983,7 +2980,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
} else {
|
||||
delta = PTRDIFF((char *)cg->tryNext, (char *)cg->tryBase, char);
|
||||
incr = size - cg->tryNoteSpace;
|
||||
incr = JS_ROUNDUP(incr, TNINCR_SIZE);
|
||||
incr = JS_ROUNDUP(incr, TRYNOTE_SIZE(TRYNOTE_GRAIN));
|
||||
size = cg->tryNoteSpace;
|
||||
JS_ARENA_GROW_CAST(cg->tryBase, JSTryNote *, &cx->tempPool, size, incr);
|
||||
if (!cg->tryBase)
|
||||
@ -3022,12 +3019,12 @@ js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote **tryp)
|
||||
}
|
||||
|
||||
tmp = cg->tryBase;
|
||||
final = (JSTryNote *) JS_malloc(cx, (count + 1) * sizeof(JSTryNote));
|
||||
final = (JSTryNote *) JS_malloc(cx, TRYNOTE_SIZE(count + 1));
|
||||
if (!final) {
|
||||
*tryp = NULL;
|
||||
return JS_FALSE;
|
||||
}
|
||||
memcpy(final, tmp, count * sizeof(JSTryNote));
|
||||
memcpy(final, tmp, TRYNOTE_SIZE(count));
|
||||
final[count].start = 0;
|
||||
final[count].length = CG_OFFSET(cg);
|
||||
final[count].catchStart = 0;
|
||||
|
@ -88,9 +88,10 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
uint32 tryCount; /* total count of try statements parsed */
|
||||
JSStmtInfo *topStmt; /* top of statement info stack */
|
||||
JSAtomList decls; /* function, const, and var declarations */
|
||||
JSParseNode *nodeList; /* list of recyclable parse-node structs */
|
||||
};
|
||||
|
||||
#define TCF_TOP_LEVEL 0x01 /* at TL of program or function body */
|
||||
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
|
||||
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
|
||||
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
|
||||
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
|
||||
@ -100,13 +101,14 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
#define TCF_FUN_FLAGS 0x60 /* flags to propagate from FunctionBody */
|
||||
|
||||
#define TREE_CONTEXT_INIT(tc) \
|
||||
((tc)->flags = TCF_TOP_LEVEL, (tc)->tryCount = 0, (tc)->topStmt = NULL, \
|
||||
ATOM_LIST_INIT(&(tc)->decls))
|
||||
((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL, \
|
||||
ATOM_LIST_INIT(&(tc)->decls), (tc)->nodeList = NULL)
|
||||
|
||||
#define TREE_CONTEXT_FREE(tc) \
|
||||
#define TREE_CONTEXT_FINISH(tc) \
|
||||
((void)0)
|
||||
|
||||
struct JSCodeGenerator {
|
||||
JSTreeContext treeContext; /* base state: statement info stack, etc. */
|
||||
void *codeMark; /* low watermark in cx->codePool */
|
||||
void *noteMark; /* low watermark in cx->notePool */
|
||||
void *tempMark; /* low watermark in cx->tempPool */
|
||||
@ -119,12 +121,12 @@ struct JSCodeGenerator {
|
||||
uintN firstLine; /* first line, for js_NewScriptFromCG */
|
||||
uintN currentLine; /* line number for tree-based srcnote gen */
|
||||
JSPrincipals *principals; /* principals for constant folding eval */
|
||||
JSTreeContext treeContext; /* for break/continue code generation */
|
||||
JSAtomList atomList; /* literals indexed for mapping */
|
||||
intN stackDepth; /* current stack depth in script frame */
|
||||
uintN maxStackDepth; /* maximum stack depth so far */
|
||||
jssrcnote *notes; /* source notes, see below */
|
||||
uintN noteCount; /* number of source notes so far */
|
||||
uintN noteMask; /* growth increment for notes */
|
||||
ptrdiff_t lastNoteOffset; /* code offset for last source note */
|
||||
JSTryNote *tryBase; /* first exception handling note */
|
||||
JSTryNote *tryNext; /* next available note */
|
||||
|
414
js/src/jsparse.c
414
js/src/jsparse.c
File diff suppressed because it is too large
Load Diff
@ -282,6 +282,15 @@ struct JSParseNode {
|
||||
(list)->pn_count++; \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*
|
||||
* The caller must prevent the GC from running while this function is active,
|
||||
* because atoms and function newborns are not rooted yet.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSParseNode *)
|
||||
js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts);
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
JSCodeGenerator *cg);
|
||||
@ -289,9 +298,8 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,
|
||||
extern JSBool
|
||||
js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun);
|
||||
|
||||
/* XXXbe expose js_Parse{TokenStream,FunctionBody} that return trees? */
|
||||
extern JSBool
|
||||
js_FoldConstants(JSContext *cx, JSParseNode *pn);
|
||||
js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user