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:
brendan%mozilla.org 2001-01-27 08:00:45 +00:00
parent 6079447d19
commit bb40b036ad
8 changed files with 459 additions and 232 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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