60 |
#include "jsparse.h" |
#include "jsparse.h" |
61 |
#include "jsscope.h" |
#include "jsscope.h" |
62 |
#include "jsscript.h" |
#include "jsscript.h" |
63 |
|
#include "jstracer.h" |
64 |
#if JS_HAS_XDR |
#if JS_HAS_XDR |
65 |
#include "jsxdrapi.h" |
#include "jsxdrapi.h" |
66 |
#endif |
#endif |
231 |
} |
} |
232 |
|
|
233 |
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */ |
/* Compile using the caller's scope chain, which js_Invoke passes to fp. */ |
234 |
caller = JS_GetScriptedCaller(cx, cx->fp); |
caller = js_GetScriptedCaller(cx, NULL); |
235 |
JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain); |
JS_ASSERT(!caller || cx->fp->scopeChain == caller->scopeChain); |
236 |
|
|
237 |
if (caller) { |
if (caller) { |
263 |
* jsparse.c to optimize based on identity of run- and compile-time scope. |
* jsparse.c to optimize based on identity of run- and compile-time scope. |
264 |
*/ |
*/ |
265 |
tcflags = 0; |
tcflags = 0; |
266 |
script = js_CompileScript(cx, scopeobj, NULL, principals, tcflags, |
script = JSCompiler::compileScript(cx, scopeobj, NULL, principals, tcflags, |
267 |
JSSTRING_CHARS(str), JSSTRING_LENGTH(str), |
JSSTRING_CHARS(str), JSSTRING_LENGTH(str), |
268 |
NULL, file, line); |
NULL, file, line); |
269 |
if (!script) |
if (!script) |
270 |
return JS_FALSE; |
return JS_FALSE; |
271 |
|
|
311 |
script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, |
312 |
jsval *rval) |
jsval *rval) |
313 |
{ |
{ |
314 |
JSObject *scopeobj, *parent; |
JSObject *scopeobj; |
315 |
JSStackFrame *fp, *caller; |
JSStackFrame *caller; |
316 |
JSPrincipals *principals; |
JSPrincipals *principals; |
317 |
JSScript *script; |
JSScript *script; |
318 |
JSBool ok; |
JSBool ok; |
339 |
* a lightweight function, we will need to get a Call object representing |
* a lightweight function, we will need to get a Call object representing |
340 |
* its frame, to act as the var object and scope chain head. |
* its frame, to act as the var object and scope chain head. |
341 |
*/ |
*/ |
342 |
fp = cx->fp; |
caller = js_GetScriptedCaller(cx, NULL); |
|
caller = JS_GetScriptedCaller(cx, fp); |
|
343 |
if (caller && !caller->varobj) { |
if (caller && !caller->varobj) { |
344 |
/* Called from a lightweight function. */ |
/* Called from a lightweight function. */ |
345 |
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags)); |
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags)); |
346 |
|
|
347 |
/* Scope chain links from Call object to callee's parent. */ |
/* Scope chain links from Call object to caller's scope chain. */ |
348 |
parent = OBJ_GET_PARENT(cx, caller->callee); |
if (!js_GetCallObject(cx, caller)) |
|
if (!js_GetCallObject(cx, caller, parent)) |
|
349 |
return JS_FALSE; |
return JS_FALSE; |
350 |
} |
} |
351 |
|
|
362 |
} else { |
} else { |
363 |
/* |
/* |
364 |
* Called from native code, so we don't know what scope object to |
* Called from native code, so we don't know what scope object to |
365 |
* use. We could use parent (see above), but Script.prototype.exec |
* use. We could use the caller's scope chain (see above), but Script.prototype.exec |
366 |
* might be a shared/sealed "superglobal" method. A more general |
* might be a shared/sealed "superglobal" method. A more general |
367 |
* approach would use cx->globalObject, which will be the same as |
* approach would use cx->globalObject, which will be the same as |
368 |
* exec.__parent__ in the non-superglobal case. In the superglobal |
* exec.__parent__ in the non-superglobal case. In the superglobal |
457 |
version = (uint32)script->version | (script->nfixed << 16); |
version = (uint32)script->version | (script->nfixed << 16); |
458 |
lineno = (uint32)script->lineno; |
lineno = (uint32)script->lineno; |
459 |
nslots = (uint32)script->nslots; |
nslots = (uint32)script->nslots; |
460 |
nslots = (uint32)((script->staticDepth << 16) | script->nslots); |
nslots = (uint32)((script->staticLevel << 16) | script->nslots); |
461 |
natoms = (uint32)script->atomMap.length; |
natoms = (uint32)script->atomMap.length; |
462 |
|
|
463 |
/* Count the srcnotes, keeping notes pointing at the first one. */ |
/* Count the srcnotes, keeping notes pointing at the first one. */ |
508 |
return JS_FALSE; |
return JS_FALSE; |
509 |
|
|
510 |
script->main += prologLength; |
script->main += prologLength; |
511 |
script->version = (JSVersion) (version & 0xffff); |
script->version = JSVersion(version & 0xffff); |
512 |
script->nfixed = (uint16) (version >> 16); |
script->nfixed = uint16(version >> 16); |
513 |
|
|
514 |
/* If we know nsrcnotes, we allocated space for notes in script. */ |
/* If we know nsrcnotes, we allocated space for notes in script. */ |
515 |
notes = SCRIPT_NOTES(script); |
notes = SCRIPT_NOTES(script); |
582 |
} |
} |
583 |
script->lineno = (uintN)lineno; |
script->lineno = (uintN)lineno; |
584 |
script->nslots = (uint16)nslots; |
script->nslots = (uint16)nslots; |
585 |
script->staticDepth = nslots >> 16; |
script->staticLevel = (uint16)(nslots >> 16); |
586 |
} |
} |
587 |
|
|
588 |
for (i = 0; i != natoms; ++i) { |
for (i = 0; i != natoms; ++i) { |
593 |
/* |
/* |
594 |
* Here looping from 0-to-length to xdr objects is essential. It ensures |
* Here looping from 0-to-length to xdr objects is essential. It ensures |
595 |
* that block objects from the script->objects array will be written and |
* that block objects from the script->objects array will be written and |
596 |
* restored in the outer-to-inner order. block_xdrObject relies on this to |
* restored in the outer-to-inner order. js_XDRBlockObject relies on this |
597 |
* restore the parent chain. |
* to restore the parent chain. |
598 |
*/ |
*/ |
599 |
for (i = 0; i != nobjects; ++i) { |
for (i = 0; i != nobjects; ++i) { |
600 |
if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i])) |
JSObject **objp = &JS_SCRIPT_OBJECTS(script)->vector[i]; |
601 |
|
uint32 isBlock; |
602 |
|
if (xdr->mode == JSXDR_ENCODE) { |
603 |
|
JSClass *clasp = STOBJ_GET_CLASS(*objp); |
604 |
|
JS_ASSERT(clasp == &js_FunctionClass || |
605 |
|
clasp == &js_BlockClass); |
606 |
|
isBlock = (clasp == &js_BlockClass) ? 1 : 0; |
607 |
|
} |
608 |
|
if (!JS_XDRUint32(xdr, &isBlock)) |
609 |
goto error; |
goto error; |
610 |
|
if (isBlock == 0) { |
611 |
|
if (!js_XDRFunctionObject(xdr, objp)) |
612 |
|
goto error; |
613 |
|
} else { |
614 |
|
JS_ASSERT(isBlock == 1); |
615 |
|
if (!js_XDRBlockObject(xdr, objp)) |
616 |
|
goto error; |
617 |
|
} |
618 |
} |
} |
619 |
for (i = 0; i != nupvars; ++i) { |
for (i = 0; i != nupvars; ++i) { |
620 |
if (!JS_XDRUint32(xdr, &JS_SCRIPT_UPVARS(script)->vector[i])) |
if (!JS_XDRUint32(xdr, &JS_SCRIPT_UPVARS(script)->vector[i])) |
621 |
goto error; |
goto error; |
622 |
} |
} |
623 |
for (i = 0; i != nregexps; ++i) { |
for (i = 0; i != nregexps; ++i) { |
624 |
if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i])) |
if (!js_XDRRegExpObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i])) |
625 |
goto error; |
goto error; |
626 |
} |
} |
627 |
|
|
918 |
Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) |
919 |
{ |
{ |
920 |
/* If not constructing, replace obj with a new Script object. */ |
/* If not constructing, replace obj with a new Script object. */ |
921 |
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { |
if (!JS_IsConstructing(cx)) { |
922 |
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); |
obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0); |
923 |
if (!obj) |
if (!obj) |
924 |
return JS_FALSE; |
return JS_FALSE; |
999 |
} |
} |
1000 |
|
|
1001 |
static void |
static void |
1002 |
js_free_table_space(void *priv, void *item) |
js_free_table_space(void *priv, void *item, size_t size) |
1003 |
{ |
{ |
1004 |
free(item); |
free(item); |
1005 |
} |
} |
1161 |
sfp->flags |= flags; |
sfp->flags |= flags; |
1162 |
} |
} |
1163 |
|
|
1164 |
|
#ifdef JS_FUNCTION_METERING |
1165 |
|
size_t len = strlen(sfe->filename); |
1166 |
|
if (len >= sizeof rt->lastScriptFilename) |
1167 |
|
len = sizeof rt->lastScriptFilename - 1; |
1168 |
|
memcpy(rt->lastScriptFilename, sfe->filename, len); |
1169 |
|
rt->lastScriptFilename[len] = '\0'; |
1170 |
|
#endif |
1171 |
|
|
1172 |
return sfe; |
return sfe; |
1173 |
} |
} |
1174 |
|
|
1495 |
script->main += prologLength; |
script->main += prologLength; |
1496 |
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode)); |
memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode)); |
1497 |
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode)); |
memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode)); |
1498 |
nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION) |
nfixed = (cg->flags & TCF_IN_FUNCTION) |
1499 |
? cg->treeContext.u.fun->u.i.nvars |
? cg->fun->u.i.nvars |
1500 |
: cg->treeContext.ngvars + cg->regexpList.length; |
: cg->ngvars + cg->regexpList.length; |
1501 |
JS_ASSERT(nfixed < SLOTNO_LIMIT); |
JS_ASSERT(nfixed < SLOTNO_LIMIT); |
1502 |
script->nfixed = (uint16) nfixed; |
script->nfixed = (uint16) nfixed; |
1503 |
js_InitAtomMap(cx, &script->atomMap, &cg->atomList); |
js_InitAtomMap(cx, &script->atomMap, &cg->atomList); |
1504 |
|
|
1505 |
filename = cg->treeContext.parseContext->tokenStream.filename; |
filename = cg->compiler->tokenStream.filename; |
1506 |
if (filename) { |
if (filename) { |
1507 |
script->filename = js_SaveScriptFilename(cx, filename); |
script->filename = js_SaveScriptFilename(cx, filename); |
1508 |
if (!script->filename) |
if (!script->filename) |
1515 |
goto bad; |
goto bad; |
1516 |
} |
} |
1517 |
script->nslots = script->nfixed + cg->maxStackDepth; |
script->nslots = script->nfixed + cg->maxStackDepth; |
1518 |
script->staticDepth = cg->staticDepth; |
script->staticLevel = cg->staticLevel; |
1519 |
script->principals = cg->treeContext.parseContext->principals; |
script->principals = cg->compiler->principals; |
1520 |
if (script->principals) |
if (script->principals) |
1521 |
JSPRINCIPALS_HOLD(cx, script->principals); |
JSPRINCIPALS_HOLD(cx, script->principals); |
1522 |
|
|
1525 |
if (cg->ntrynotes != 0) |
if (cg->ntrynotes != 0) |
1526 |
js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script)); |
js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script)); |
1527 |
if (cg->objectList.length != 0) |
if (cg->objectList.length != 0) |
1528 |
FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script)); |
cg->objectList.finish(JS_SCRIPT_OBJECTS(script)); |
1529 |
if (cg->regexpList.length != 0) |
if (cg->regexpList.length != 0) |
1530 |
FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script)); |
cg->regexpList.finish(JS_SCRIPT_REGEXPS(script)); |
1531 |
if (cg->treeContext.flags & TCF_NO_SCRIPT_RVAL) |
if (cg->flags & TCF_NO_SCRIPT_RVAL) |
1532 |
script->flags |= JSSF_NO_SCRIPT_RVAL; |
script->flags |= JSSF_NO_SCRIPT_RVAL; |
1533 |
|
|
1534 |
if (cg->upvarList.count != 0) { |
if (cg->upvarList.count != 0) { |
1535 |
JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length); |
JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length); |
1536 |
memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector, |
memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector, |
1537 |
cg->upvarList.count * sizeof(uint32)); |
cg->upvarList.count * sizeof(uint32)); |
1538 |
ATOM_LIST_INIT(&cg->upvarList); |
cg->upvarList.clear(); |
1539 |
JS_free(cx, cg->upvarMap.vector); |
JS_free(cx, cg->upvarMap.vector); |
1540 |
cg->upvarMap.vector = NULL; |
cg->upvarMap.vector = NULL; |
1541 |
} |
} |
1545 |
* so that the debugger has a valid FUN_SCRIPT(fun). |
* so that the debugger has a valid FUN_SCRIPT(fun). |
1546 |
*/ |
*/ |
1547 |
fun = NULL; |
fun = NULL; |
1548 |
if (cg->treeContext.flags & TCF_IN_FUNCTION) { |
if (cg->flags & TCF_IN_FUNCTION) { |
1549 |
fun = cg->treeContext.u.fun; |
fun = cg->fun; |
1550 |
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun)); |
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun)); |
1551 |
JS_ASSERT_IF(script->upvarsOffset != 0, |
JS_ASSERT_IF(script->upvarsOffset != 0, |
1552 |
JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars); |
JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars); |
1556 |
#ifdef CHECK_SCRIPT_OWNER |
#ifdef CHECK_SCRIPT_OWNER |
1557 |
script->owner = NULL; |
script->owner = NULL; |
1558 |
#endif |
#endif |
1559 |
if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) |
if (cg->flags & TCF_FUN_HEAVYWEIGHT) |
1560 |
fun->flags |= JSFUN_HEAVYWEIGHT; |
fun->flags |= JSFUN_HEAVYWEIGHT; |
1561 |
} |
} |
1562 |
|
|
1603 |
JSPRINCIPALS_DROP(cx, script->principals); |
JSPRINCIPALS_DROP(cx, script->principals); |
1604 |
|
|
1605 |
if (JS_GSN_CACHE(cx).code == script->code) |
if (JS_GSN_CACHE(cx).code == script->code) |
1606 |
JS_CLEAR_GSN_CACHE(cx); |
JS_PURGE_GSN_CACHE(cx); |
1607 |
|
|
1608 |
/* |
/* |
1609 |
* The GC flushes all property caches, so no need to purge just the |
* The GC flushes all property caches, so no need to purge just the |
1610 |
* entries for this script. |
* entries for this script. |
1611 |
* |
* |
1612 |
* JS_THREADSAFE note: js_FlushPropertyCacheForScript flushes only the |
* JS_THREADSAFE note: js_PurgePropertyCacheForScript purges only the |
1613 |
* current thread's property cache, so a script not owned by a function |
* current thread's property cache, so a script not owned by a function |
1614 |
* or object, which hands off lifetime management for that script to the |
* or object, which hands off lifetime management for that script to the |
1615 |
* GC, must be used by only one thread over its lifetime. |
* GC, must be used by only one thread over its lifetime. |
1624 |
#endif |
#endif |
1625 |
|
|
1626 |
if (!cx->runtime->gcRunning) { |
if (!cx->runtime->gcRunning) { |
1627 |
if (!(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) { |
JSStackFrame *fp = js_GetTopStackFrame(cx); |
1628 |
|
|
1629 |
|
if (!(fp && (fp->flags & JSFRAME_EVAL))) { |
1630 |
#ifdef CHECK_SCRIPT_OWNER |
#ifdef CHECK_SCRIPT_OWNER |
1631 |
JS_ASSERT(script->owner == cx->thread); |
JS_ASSERT(script->owner == cx->thread); |
1632 |
#endif |
#endif |
1633 |
js_FlushPropertyCacheForScript(cx, script); |
js_PurgePropertyCacheForScript(cx, script); |
1634 |
|
#ifdef JS_TRACER |
1635 |
|
js_PurgeScriptFragments(cx, script); |
1636 |
|
#endif |
1637 |
} |
} |
1638 |
} |
} |
1639 |
|
|
1701 |
|
|
1702 |
#define GSN_CACHE_THRESHOLD 100 |
#define GSN_CACHE_THRESHOLD 100 |
1703 |
|
|
1704 |
|
void |
1705 |
|
js_PurgeGSNCache(JSGSNCache *cache) |
1706 |
|
{ |
1707 |
|
cache->code = NULL; |
1708 |
|
if (cache->table.ops) { |
1709 |
|
JS_DHashTableFinish(&cache->table); |
1710 |
|
cache->table.ops = NULL; |
1711 |
|
} |
1712 |
|
GSN_CACHE_METER(cache, purges); |
1713 |
|
} |
1714 |
|
|
1715 |
jssrcnote * |
jssrcnote * |
1716 |
js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc) |
js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc) |
1717 |
{ |
{ |
1749 |
|
|
1750 |
if (JS_GSN_CACHE(cx).code != script->code && |
if (JS_GSN_CACHE(cx).code != script->code && |
1751 |
script->length >= GSN_CACHE_THRESHOLD) { |
script->length >= GSN_CACHE_THRESHOLD) { |
1752 |
JS_CLEAR_GSN_CACHE(cx); |
JS_PURGE_GSN_CACHE(cx); |
1753 |
nsrcnotes = 0; |
nsrcnotes = 0; |
1754 |
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); |
for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); |
1755 |
sn = SN_NEXT(sn)) { |
sn = SN_NEXT(sn)) { |
1790 |
uintN |
uintN |
1791 |
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) |
js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) |
1792 |
{ |
{ |
1793 |
|
JSOp op; |
1794 |
JSFunction *fun; |
JSFunction *fun; |
1795 |
uintN lineno; |
uintN lineno; |
1796 |
ptrdiff_t offset, target; |
ptrdiff_t offset, target; |
1805 |
* Special case: function definition needs no line number note because |
* Special case: function definition needs no line number note because |
1806 |
* the function's script contains its starting line number. |
* the function's script contains its starting line number. |
1807 |
*/ |
*/ |
1808 |
if (js_CodeSpec[*pc].format & JOF_INDEXBASE) |
op = js_GetOpcode(cx, script, pc); |
1809 |
pc += js_CodeSpec[*pc].length; |
if (js_CodeSpec[op].format & JOF_INDEXBASE) |
1810 |
|
pc += js_CodeSpec[op].length; |
1811 |
if (*pc == JSOP_DEFFUN) { |
if (*pc == JSOP_DEFFUN) { |
1812 |
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); |
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun); |
1813 |
return fun->u.i.script->lineno; |
return fun->u.i.script->lineno; |