Bug 398609: Backing out due to mochi test failure.

This commit is contained in:
igor@mir2.org 2007-11-13 07:47:28 -08:00
parent 3e86d8ae61
commit 837c046912
20 changed files with 1024 additions and 791 deletions

View File

@ -1239,7 +1239,7 @@ SrcNotes(JSContext *cx, JSScript *script)
index = js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_OBJECT(script, index, obj);
fun = (JSFunction *) JS_GetPrivate(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
bytes = str ? JS_GetStringBytes(str) : "N/A";
fprintf(gOutFile, " function %u (%s)", index, bytes);

View File

@ -4663,20 +4663,26 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
goto out;
}
}
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
if (!fun)
goto out;
if (nargs) {
for (i = 0; i < nargs; i++) {
argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
if (!argAtom) {
fun = NULL;
goto out;
}
if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
js_GetArgument, js_SetArgument,
SPROP_INVALID_SLOT,
JSPROP_PERMANENT | JSPROP_SHARED,
SPROP_HAS_SHORTID, i)) {
fun = NULL;
goto out;
}
}
}
ok = js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno);
if (ok) {
@ -4710,7 +4716,7 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
JSString *str;
CHECK_REQUEST(cx);
jp = JS_NEW_PRINTER(cx, name, NULL,
jp = JS_NEW_PRINTER(cx, name,
indent & ~JS_DONT_PRETTY_PRINT,
!(indent & JS_DONT_PRETTY_PRINT));
if (!jp)
@ -4730,12 +4736,12 @@ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
JSString *str;
CHECK_REQUEST(cx);
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction", fun,
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction",
indent & ~JS_DONT_PRETTY_PRINT,
!(indent & JS_DONT_PRETTY_PRINT));
if (!jp)
return NULL;
if (js_DecompileFunction(jp))
if (js_DecompileFunction(jp, fun))
str = js_GetPrinterOutput(jp);
else
str = NULL;
@ -4750,12 +4756,12 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
JSString *str;
CHECK_REQUEST(cx);
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody", fun,
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody",
indent & ~JS_DONT_PRETTY_PRINT,
!(indent & JS_DONT_PRETTY_PRINT));
if (!jp)
return NULL;
if (js_DecompileFunctionBody(jp))
if (js_DecompileFunctionBody(jp, fun))
str = js_GetPrinterOutput(jp);
else
str = NULL;

View File

@ -563,7 +563,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
closure = (JSObject *) wp->closure;
clasp = OBJ_GET_CLASS(cx, closure);
if (clasp == &js_FunctionClass) {
fun = GET_FUNCTION_PRIVATE(cx, closure);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, closure);
script = FUN_SCRIPT(fun);
} else if (clasp == &js_ScriptClass) {
fun = NULL;
@ -653,7 +653,7 @@ js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
funobj = JSVAL_TO_OBJECT(argv[-2]);
JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
wrapper = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj);
userid = ATOM_KEY(wrapper->atom);
*rval = argv[0];
return js_watch_set(cx, obj, userid, rval);
@ -1326,12 +1326,9 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
pd->flags |= ((sprop->attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0)
| ((sprop->attrs & JSPROP_READONLY) ? JSPD_READONLY : 0)
| ((sprop->attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0)
| ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0);
if (JSID_IS_HIDDEN(sprop->id)) {
pd->flags |= (getter == JS_HIDDEN_ARG_GETTER)
? JSPD_ARGUMENT
: JSPD_VARIABLE;
}
| ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0)
| ((getter == js_GetArgument) ? JSPD_ARGUMENT : 0)
| ((getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0);
/* for Call Object 'real' getter isn't passed in to us */
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&

View File

@ -1233,7 +1233,8 @@ js_IsGlobalReference(JSTreeContext *tc, JSAtom *atom, JSBool *loopyp)
continue;
}
if (stmt->flags & SIF_SCOPE) {
JS_ASSERT(STOBJ_GET_CLASS(stmt->u.blockObj) == &js_BlockClass);
JS_ASSERT(LOCKED_OBJ_GET_CLASS(stmt->u.blockObj) ==
&js_BlockClass);
scope = OBJ_SCOPE(stmt->u.blockObj);
if (SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom)))
return JS_FALSE;
@ -1645,10 +1646,26 @@ js_LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
* with object or catch variable; nor can prop's value be changed,
* nor can prop be deleted.
*/
prop = NULL;
if (OBJ_GET_CLASS(cx, obj) == &js_FunctionClass) {
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, obj));
if (js_LookupLocal(cx, fp->fun, atom, NULL) != JSLOCAL_NONE)
ok = js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
&pobj, &prop);
if (!ok)
break;
if (prop) {
#ifdef DEBUG
JSScopeProperty *sprop = (JSScopeProperty *)prop;
/*
* Any hidden property must be a formal arg or local var,
* which will shadow a global const of the same name.
*/
JS_ASSERT(sprop->getter == js_GetArgument ||
sprop->getter == js_GetLocalVariable);
#endif
OBJ_DROP_PROPERTY(cx, pobj, prop);
break;
}
}
ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop);
@ -1818,7 +1835,7 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
* pn->pn_op. If pn->pn_slot is still -1 on return, pn->pn_op nevertheless
* may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS. Whether
* or not pn->pn_op was modified, if this function finds an argument or local
* variable name, pn->pn_const will be true for const properties after a
* variable name, pn->pn_attrs will contain the property's attributes after a
* successful return.
*
* NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
@ -1834,10 +1851,14 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
jsint slot;
JSOp op;
JSStackFrame *fp;
JSObject *obj, *pobj;
JSClass *clasp;
JSLocalKind localKind;
uintN index;
JSBool optimizeGlobals;
JSPropertyOp getter;
uintN attrs;
JSAtomListElement *ale;
JSProperty *prop;
JSScopeProperty *sprop;
JS_ASSERT(pn->pn_type == TOK_NAME);
if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS)
@ -1901,32 +1922,42 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
return JS_TRUE;
/*
* We can't optimize if we are in an eval called inside a with statement.
* We can't optimize if we're not compiling a function body, whether via
* eval, or directly when compiling a function statement or expression.
*/
if (fp->scopeChain != fp->varobj)
return JS_TRUE;
clasp = OBJ_GET_CLASS(cx, fp->varobj);
obj = fp->varobj;
clasp = OBJ_GET_CLASS(cx, obj);
if (clasp != &js_FunctionClass && clasp != &js_CallClass) {
/*
* We cannot optimize the name access when compiling with an eval or
* debugger frame.
*/
/* Check for an eval or debugger frame. */
if (fp->flags & JSFRAME_SPECIAL)
return JS_TRUE;
/*
* We are compiling a top-level script. Optimize global variable
* accesses if there are at least 100 uses in unambiguous contexts,
* or failing that, if least half of all the uses of global
* vars/consts/functions are in loops.
* Optimize global variable accesses if there are at least 100 uses
* in unambiguous contexts, or failing that, if least half of all the
* uses of global vars/consts/functions are in loops.
*/
if (!(tc->globalUses >= 100 ||
optimizeGlobals = (tc->globalUses >= 100 ||
(tc->loopyGlobalUses &&
tc->loopyGlobalUses >= tc->globalUses / 2))) {
tc->loopyGlobalUses >= tc->globalUses / 2));
if (!optimizeGlobals)
return JS_TRUE;
} else {
optimizeGlobals = JS_FALSE;
}
/*
* We can't optimize if we are in an eval called inside a with statement.
*/
if (fp->scopeChain != obj)
return JS_TRUE;
op = PN_OP(pn);
getter = NULL;
#ifdef __GNUC__
attrs = slot = 0; /* quell GCC overwarning */
#endif
if (optimizeGlobals) {
/*
* We are optimizing global variables, and there is no pre-existing
* global property named atom. If atom was declared via const or var,
@ -1938,6 +1969,10 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
return JS_TRUE;
}
attrs = (ALE_JSOP(ale) == JSOP_DEFCONST)
? JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
/* Index atom so we can map fast global number to name. */
JS_ASSERT(tc->flags & TCF_COMPILING);
ale = js_IndexAtom(cx, atom, &((JSCodeGenerator *) tc)->atomList);
@ -1951,8 +1986,29 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
if ((uint16)(slot + 1) > tc->ngvars)
tc->ngvars = (uint16)(slot + 1);
} else {
/*
* We may be able to optimize name to stack slot. Look for an argument
* or variable property in the function, or its call object, not found
* in any prototype object. Rewrite pn_op and update pn accordingly.
* NB: We know that JSOP_DELNAME on an argument or variable evaluates
* to false, due to JSPROP_PERMANENT.
*/
if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
return JS_FALSE;
sprop = (JSScopeProperty *) prop;
if (sprop) {
if (pobj == obj) {
getter = sprop->getter;
attrs = sprop->attrs;
slot = (sprop->flags & SPROP_HAS_SHORTID) ? sprop->shortid : -1;
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
}
op = PN_OP(pn);
if (optimizeGlobals || getter) {
if (optimizeGlobals) {
switch (op) {
case JSOP_NAME: op = JSOP_GETGVAR; break;
case JSOP_SETNAME: op = JSOP_SETGVAR; break;
@ -1965,40 +2021,8 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
case JSOP_DELNAME: /* NB: no change */ break;
default: JS_ASSERT(0);
}
pn->pn_const = (ALE_JSOP(ale) == JSOP_DEFCONST);
if (op != pn->pn_op) {
pn->pn_op = op;
pn->pn_slot = slot;
}
return JS_TRUE;
}
if (clasp == &js_FunctionClass) {
/*
* We are compiling a function body and may be able to optimize name
* to stack slot. Look for an argument or variable in the function and
* rewrite pn_op and update pn accordingly.
*/
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->varobj));
localKind = js_LookupLocal(cx, fp->fun, atom, &index);
if (localKind != JSLOCAL_NONE) {
op = PN_OP(pn);
if (localKind == JSLOCAL_ARG) {
switch (op) {
case JSOP_NAME: op = JSOP_GETARG; break;
case JSOP_SETNAME: op = JSOP_SETARG; break;
case JSOP_INCNAME: op = JSOP_INCARG; break;
case JSOP_NAMEINC: op = JSOP_ARGINC; break;
case JSOP_DECNAME: op = JSOP_DECARG; break;
case JSOP_NAMEDEC: op = JSOP_ARGDEC; break;
case JSOP_FORNAME: op = JSOP_FORARG; break;
case JSOP_DELNAME: op = JSOP_FALSE; break;
default: JS_ASSERT(0);
}
pn->pn_const = JS_FALSE;
} else {
JS_ASSERT(localKind == JSLOCAL_VAR ||
localKind == JSLOCAL_CONST);
} else if (getter == js_GetLocalVariable ||
getter == js_GetCallVariable) {
switch (op) {
case JSOP_NAME: op = JSOP_GETVAR; break;
case JSOP_SETNAME: op = JSOP_SETVAR; break;
@ -2011,19 +2035,31 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
case JSOP_DELNAME: op = JSOP_FALSE; break;
default: JS_ASSERT(0);
}
pn->pn_const = (localKind == JSLOCAL_CONST);
} else if (getter == js_GetArgument ||
(getter == js_CallClass.getProperty &&
fp->fun && (uintN) slot < fp->fun->nargs)) {
switch (op) {
case JSOP_NAME: op = JSOP_GETARG; break;
case JSOP_SETNAME: op = JSOP_SETARG; break;
case JSOP_INCNAME: op = JSOP_INCARG; break;
case JSOP_NAMEINC: op = JSOP_ARGINC; break;
case JSOP_DECNAME: op = JSOP_DECARG; break;
case JSOP_NAMEDEC: op = JSOP_ARGDEC; break;
case JSOP_FORNAME: op = JSOP_FORARG; break;
case JSOP_DELNAME: op = JSOP_FALSE; break;
default: JS_ASSERT(0);
}
}
if (op != pn->pn_op) {
pn->pn_op = op;
pn->pn_slot = index;
return JS_TRUE;
pn->pn_slot = slot;
}
pn->pn_attrs = attrs;
}
if (pn->pn_slot < 0) {
/*
* Here we either compiling a function body or an eval script inside a
* function and couldn't optimize pn, so it's not a global or local slot
* name.
*
* We couldn't optimize pn, so it's not a global or local slot name.
* Now we must check for the predefined arguments variable. It may be
* overridden by assignment, in which case the function is heavyweight
* and the interpreter will look up 'arguments' in the function's call
@ -2034,7 +2070,9 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
pn->pn_op = JSOP_ARGUMENTS;
return JS_TRUE;
}
tc->flags |= TCF_FUN_USES_NONLOCALS;
}
return JS_TRUE;
}
@ -2071,7 +2109,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
* name in that scope object. See comments at case JSOP_NAMEDFUNOBJ:
* in jsinterp.c.
*/
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object);
if (fun->atom)
*answer = JS_TRUE;
break;
@ -2132,7 +2170,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
if (!*answer &&
(pn->pn_op != JSOP_NOP ||
pn2->pn_slot < 0 ||
!pn2->pn_const)) {
!(pn2->pn_attrs & JSPROP_READONLY))) {
*answer = JS_TRUE;
}
}
@ -3996,7 +4034,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
pn->pn_pos.begin.lineno);
cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);
cg2->parent = cg;
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object);
if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))
return JS_FALSE;
@ -4049,22 +4087,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if ((cg->treeContext.flags & TCF_IN_FUNCTION) ||
((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun)) {
JSFunction *parentFun;
JSLocalKind localKind;
JSObject *obj, *pobj;
JSProperty *prop;
JSScopeProperty *sprop;
if (cg->treeContext.flags & TCF_IN_FUNCTION) {
JS_ASSERT(OBJ_GET_CLASS(cx, OBJ_GET_PARENT(cx, fun->object)) ==
&js_FunctionClass);
parentFun =
GET_FUNCTION_PRIVATE(cx, OBJ_GET_PARENT(cx, fun->object));
} else {
parentFun = cx->fp->fun;
obj = (cg->treeContext.flags & TCF_IN_FUNCTION)
? OBJ_GET_PARENT(cx, fun->object)
: cx->fp->fun->object;
if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(fun->atom),
&pobj, &prop)) {
return JS_FALSE;
}
localKind = js_LookupLocal(cx, parentFun, fun->atom, &slot);
if (localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST)
if (prop) {
if (pobj == obj) {
sprop = (JSScopeProperty *) prop;
if (sprop->getter == js_GetLocalVariable) {
slot = sprop->shortid;
op = JSOP_DEFLOCALFUN;
else
JS_ASSERT(!(cg->treeContext.flags & TCF_IN_FUNCTION));
}
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
JS_ASSERT(op == JSOP_DEFLOCALFUN ||
!(cg->treeContext.flags & TCF_IN_FUNCTION));
/*
* If this local function is declared in a body block induced
@ -4076,9 +4123,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (stmt && stmt->type == STMT_BLOCK &&
stmt->down && stmt->down->type == STMT_BLOCK &&
(stmt->down->flags & SIF_SCOPE)) {
JS_ASSERT(STOBJ_GET_CLASS(stmt->down->u.blockObj) ==
&js_BlockClass);
OBJ_SET_PARENT(cx, fun->object, stmt->down->u.blockObj);
obj = stmt->down->u.blockObj;
JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
OBJ_SET_PARENT(cx, fun->object, obj);
}
}
@ -4436,7 +4483,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
op = PN_OP(pn3);
}
if (pn3->pn_slot >= 0) {
if (pn3->pn_const) {
if (pn3->pn_attrs & JSPROP_READONLY) {
JS_ASSERT(op == JSOP_FORVAR);
op = JSOP_FORCONST;
}
@ -5439,12 +5486,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
/*
* Take care to avoid SRC_ASSIGNOP if the left-hand side is a
* const declared in a function (i.e., with non-negative pn_slot
* and when pn_const is true), as in this case (just a bit further
* below) we will avoid emitting the assignment op.
* and JSPROP_READONLY in pn_attrs), as in this case (just a bit
* further below) we will avoid emitting the assignment op.
*/
if (pn2->pn_type != TOK_NAME ||
pn2->pn_slot < 0 ||
!pn2->pn_const) {
!(pn2->pn_attrs & JSPROP_READONLY)) {
if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
return JS_FALSE;
}
@ -5465,7 +5512,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
/* Finally, emit the specialized assignment bytecode. */
switch (pn2->pn_type) {
case TOK_NAME:
if (pn2->pn_slot < 0 || !pn2->pn_const) {
if (pn2->pn_slot < 0 || !(pn2->pn_attrs & JSPROP_READONLY)) {
if (pn2->pn_slot >= 0) {
EMIT_UINT16_IMM_OP(PN_OP(pn2), atomIndex);
} else {
@ -5710,7 +5757,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
return JS_FALSE;
op = PN_OP(pn2);
if (pn2->pn_slot >= 0) {
if (pn2->pn_const) {
if (pn2->pn_attrs & JSPROP_READONLY) {
/* Incrementing a declared const: just get its value. */
op = ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_ATOM)
? JSOP_GETGVAR

View File

@ -722,7 +722,8 @@ js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
JS_ASSERT(JSVAL_IS_INT(id));
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
/* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
if ((uintN)JSVAL_TO_INT(id) < fp->nvars)
*vp = fp->vars[JSVAL_TO_INT(id)];
}
return JS_TRUE;
@ -736,8 +737,10 @@ js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
JS_ASSERT(JSVAL_IS_INT(id));
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
fp->vars[JSVAL_TO_INT(id)] = *vp;
/* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
jsint slot = JSVAL_TO_INT(id);
if ((uintN)slot < fp->nvars)
fp->vars[slot] = *vp;
}
return JS_TRUE;
}
@ -749,6 +752,7 @@ call_enumerate(JSContext *cx, JSObject *obj)
JSObject *funobj, *pobj;
JSScope *scope;
JSScopeProperty *sprop, *cprop;
JSPropertyOp getter;
jsval *vec;
jsid id;
JSProperty *prop;
@ -780,9 +784,13 @@ call_enumerate(JSContext *cx, JSObject *obj)
*/
scope = OBJ_SCOPE(funobj);
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
if (!JSID_IS_HIDDEN(sprop->id))
getter = sprop->getter;
if (getter == js_GetArgument)
vec = fp->argv;
else if (getter == js_GetLocalVariable)
vec = fp->vars;
else
continue;
vec = (sprop->getter == JS_HIDDEN_ARG_GETTER) ? fp->argv : fp->vars;
/* Trigger reflection by looking up the unhidden atom for sprop->id. */
id = JSID_UNHIDE_NAME(sprop->id);
@ -813,12 +821,16 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
JSStackFrame *fp;
JSObject *funobj;
JSString *str;
JSAtom *atom;
JSLocalKind localKind;
JSObject *obj2;
JSProperty *prop;
JSScopeProperty *sprop;
JSPropertyOp getter, setter;
uintN slot, attrs, spflags;
jsval value;
uintN attrs, slot, nslots, spflags;
jsval *vp, value;
intN shortid;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
@ -828,42 +840,61 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
if (!fp->callee)
funobj = fp->callee;
if (!funobj)
return JS_TRUE;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
JS_ASSERT((JSFunction *) OBJ_GET_PRIVATE(cx, funobj) == fp->fun);
str = JSVAL_TO_STRING(id);
atom = js_AtomizeString(cx, str, 0);
if (!atom)
return JS_FALSE;
if (!js_LookupHiddenProperty(cx, funobj, ATOM_TO_JSID(atom), &obj2, &prop))
return JS_FALSE;
localKind = js_LookupLocal(cx, fp->fun, atom, &slot);
if (localKind != JSLOCAL_NONE) {
if (localKind == JSLOCAL_ARG) {
JS_ASSERT(slot < fp->fun->nargs);
value = (slot < fp->argc) ? fp->argv[slot] : JSVAL_VOID;
if (prop) {
if (!OBJ_IS_NATIVE(obj2)) {
OBJ_DROP_PROPERTY(cx, obj2, prop);
return JS_TRUE;
}
sprop = (JSScopeProperty *) prop;
getter = sprop->getter;
attrs = sprop->attrs & ~JSPROP_SHARED;
slot = (uintN) sprop->shortid;
OBJ_DROP_PROPERTY(cx, obj2, prop);
/* Ensure we found an arg or var property for the same function. */
if ((sprop->flags & SPROP_IS_HIDDEN) &&
(obj2 == funobj ||
(JSFunction *) OBJ_GET_PRIVATE(cx, obj2) == fp->fun)) {
if (getter == js_GetArgument) {
vp = fp->argv;
nslots = JS_MAX(fp->argc, fp->fun->nargs);
getter = setter = NULL;
attrs = JSPROP_PERMANENT;
spflags = 0;
slot = 0;
} else {
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
JS_ASSERT(fp->fun->u.i.nvars == fp->nvars);
JS_ASSERT(slot < fp->nvars);
value = fp->vars[slot];
JS_ASSERT(getter == js_GetLocalVariable);
vp = fp->vars;
nslots = fp->nvars;
getter = js_GetCallVariable;
setter = js_SetCallVariable;
attrs = (localKind == JSLOCAL_CONST)
? JSPROP_PERMANENT | JSPROP_READONLY
: JSPROP_PERMANENT;
}
if (slot < nslots) {
value = vp[slot];
spflags = SPROP_HAS_SHORTID;
shortid = (intN) slot;
} else {
value = JSVAL_VOID;
spflags = 0;
shortid = 0;
}
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
getter, setter, attrs,
spflags, (int) slot, NULL)) {
spflags, shortid, NULL)) {
return JS_FALSE;
}
*objp = obj;
}
return JS_TRUE;
}
@ -1075,20 +1106,39 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
fun = GET_FUNCTION_PRIVATE(cx, obj);
JS_ASSERT(fun->object);
/* No valid function object should lack private data. */
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
JS_ASSERT(fun && fun->object);
/*
* No need to reflect fun.prototype in 'fun.prototype = ... '.
*
* This is not just an optimization, because we must not resolve when
* defining hidden properties during compilation. The setup code for the
* prototype and the lazy properties below eventually calls the property
* hooks for the function object. That in turn calls fun_reserveSlots to
* get the number of the reserved slots which is just the number of
* regular expressions literals in the function. When compiling, that
* number is not yet ready so we must make sure that fun_resolve does
* nothing until the code for the function is generated.
* Check for a hidden formal parameter or local variable binding in the
* clone-parent of obj, which would be a different, non-null fun->object.
*/
if (flags & JSRESOLVE_HIDDEN) {
if (fun->object != obj) {
JSObject *pobj;
JSProperty *prop;
atom = js_AtomizeString(cx, JSVAL_TO_STRING(id), 0);
if (!atom)
return JS_FALSE;
if (!js_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
&pobj, &prop)) {
return JS_FALSE;
}
if (prop) {
JS_ASSERT(pobj == fun->object);
*objp = pobj;
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
}
return JS_TRUE;
}
/*
* No need to reflect fun.prototype in 'fun.prototype = ...'. This test
* must come after the JSRESOLVE_HIDDEN test, since call_resolve may look
* for a hidden function object property from an assignment bytecode.
*/
if (flags & JSRESOLVE_ASSIGNING)
return JS_TRUE;
@ -1195,6 +1245,12 @@ fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
#include "jsxdrapi.h"
enum {
JSXDR_FUNARG = 1,
JSXDR_FUNVAR = 2,
JSXDR_FUNCONST = 3
};
/* XXX store parent and proto, if defined */
static JSBool
fun_xdrObject(JSXDRState *xdr, JSObject **objp)
@ -1202,15 +1258,29 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
JSContext *cx;
JSFunction *fun;
uint32 nullAtom; /* flag to indicate if fun->atom is NULL */
uintN nargs, nvars, n;
uint32 localsword; /* word to xdr argument and variable counts */
uint32 flagsword; /* originally only flags was JS_XDRUint8'd */
JSTempValueRooter tvr;
uint32 flagsword; /* originally only flags was JS_XDRUint8'd */
uint16 extraUnused; /* variable for no longer used field */
JSAtom *propAtom;
JSScopeProperty *sprop;
uint32 userid; /* NB: holds a signed int-tagged jsval */
uintN i, n, dupflag;
uint32 type;
JSBool ok;
#ifdef DEBUG
uintN nvars = 0, nargs = 0;
#endif
cx = xdr->cx;
if (xdr->mode == JSXDR_ENCODE) {
fun = GET_FUNCTION_PRIVATE(cx, *objp);
/*
* No valid function object should lack private data, but fail soft
* (return true, no error report) in case one does due to API pilot
* or internal error.
*/
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, *objp);
if (!fun)
return JS_TRUE;
if (!FUN_INTERPRETED(fun)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_NOT_SCRIPTED_FUNCTION,
@ -1218,17 +1288,12 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
return JS_FALSE;
}
nullAtom = !fun->atom;
nargs = fun->nargs;
nvars = fun->u.i.nvars;
localsword = (nargs << 16) | nvars;
flagsword = fun->flags;
extraUnused = 0;
} else {
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
if (!fun)
return JS_FALSE;
#ifdef __GNUC__
nvars = nargs = 0; /* quell GCC uninitialized warning */
#endif
}
/* From here on, control flow must flow through label out. */
@ -1239,96 +1304,128 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
goto bad;
if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))
goto bad;
if (!JS_XDRUint32(xdr, &localsword) ||
if (!JS_XDRUint16(xdr, &fun->nargs) ||
!JS_XDRUint16(xdr, &extraUnused) ||
!JS_XDRUint16(xdr, &fun->u.i.nvars) ||
!JS_XDRUint32(xdr, &flagsword)) {
goto bad;
}
if (xdr->mode == JSXDR_DECODE) {
nargs = localsword >> 16;
nvars = localsword & JS_BITMASK(16);
JS_ASSERT(flagsword | JSFUN_INTERPRETED);
fun->flags = (uint16) flagsword;
}
/* Assert that all previous writes of extraUnused were writes of 0. */
JS_ASSERT(extraUnused == 0);
/* do arguments and local vars */
if (fun->object && (n = nargs + nvars) != 0) {
void *mark;
uintN i;
uintN bitmapLength;
uint32 *bitmap;
JSAtom **names, *name;
uint32 localKind;
mark = JS_ARENA_MARK(&xdr->cx->tempPool);
/* From this point the control must flow through label release_mark. */
bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
if (fun->object) {
n = fun->nargs + fun->u.i.nvars;
if (xdr->mode == JSXDR_ENCODE) {
names = js_GetLocalNames(xdr->cx, fun, &xdr->cx->tempPool, &bitmap);
if (!names) {
ok = JS_FALSE;
goto release_mark;
}
} else {
#ifdef __GNUC__
names = NULL; /* quell GCC uninitialized warning */
#endif
JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
bitmapLength * sizeof *bitmap);
if (!bitmap) {
JS_ReportOutOfMemory(xdr->cx);
ok = JS_FALSE;
goto release_mark;
}
}
for (i = 0; i != bitmapLength; ++i) {
ok = JS_XDRUint32(xdr, &bitmap[i]);
if (!ok)
goto release_mark;
}
for (i = 0; i != n; ++i) {
if (i < nargs &&
!(bitmap[i / JS_BITS_PER_UINT32] &
JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) {
if (xdr->mode == JSXDR_DECODE) {
ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG);
if (!ok)
goto release_mark;
} else {
JS_ASSERT(!names[i]);
}
continue;
}
if (xdr->mode == JSXDR_ENCODE)
name = names[i];
ok = js_XDRStringAtom(xdr, &name);
if (!ok)
goto release_mark;
if (xdr->mode == JSXDR_DECODE) {
localKind = (i < nargs)
? JSLOCAL_ARG
: bitmap[i / JS_BITS_PER_UINT32] &
JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
? JSLOCAL_CONST
: JSLOCAL_VAR;
ok = js_AddLocal(xdr->cx, fun, name, localKind);
if (!ok)
goto release_mark;
}
}
ok = JS_TRUE;
JSScope *scope;
JSScopeProperty **spvec, *auto_spvec[8];
void *mark;
release_mark:
JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
if (!ok)
goto out;
if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) {
spvec = auto_spvec;
mark = NULL;
} else {
mark = JS_ARENA_MARK(&cx->tempPool);
JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool,
n * sizeof(JSScopeProperty *));
if (!spvec) {
JS_ReportOutOfMemory(cx);
goto bad;
}
}
scope = OBJ_SCOPE(fun->object);
for (sprop = SCOPE_LAST_PROP(scope); sprop;
sprop = sprop->parent) {
if (sprop->getter == js_GetArgument) {
JS_ASSERT(nargs++ <= fun->nargs);
spvec[sprop->shortid] = sprop;
} else if (sprop->getter == js_GetLocalVariable) {
JS_ASSERT(nvars++ <= fun->u.i.nvars);
spvec[fun->nargs + sprop->shortid] = sprop;
}
}
for (i = 0; i < n; i++) {
sprop = spvec[i];
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
type = (i < fun->nargs)
? JSXDR_FUNARG
: (sprop->attrs & JSPROP_READONLY)
? JSXDR_FUNCONST
: JSXDR_FUNVAR;
userid = INT_TO_JSVAL(sprop->shortid);
/*
* sprop->id here represents hidden names so we unhide it and
* encode as an atom. During decoding we read the atom and use
* js_AddHiddenProperty to reconstruct sprop with the hidden
* id.
*/
propAtom = JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
if (!JS_XDRUint32(xdr, &type) ||
!JS_XDRUint32(xdr, &userid) ||
!js_XDRStringAtom(xdr, &propAtom)) {
if (mark)
JS_ARENA_RELEASE(&cx->tempPool, mark);
goto bad;
}
}
if (mark)
JS_ARENA_RELEASE(&cx->tempPool, mark);
} else {
JSPropertyOp getter, setter;
for (i = n; i != 0; i--) {
uintN attrs = JSPROP_PERMANENT;
if (!JS_XDRUint32(xdr, &type) ||
!JS_XDRUint32(xdr, &userid) ||
!js_XDRStringAtom(xdr, &propAtom)) {
goto bad;
}
JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
type == JSXDR_FUNCONST);
if (type == JSXDR_FUNARG) {
getter = js_GetArgument;
setter = js_SetArgument;
JS_ASSERT(nargs++ <= fun->nargs);
} else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) {
getter = js_GetLocalVariable;
setter = js_SetLocalVariable;
if (type == JSXDR_FUNCONST)
attrs |= JSPROP_READONLY;
JS_ASSERT(nvars++ <= fun->u.i.nvars);
} else {
getter = NULL;
setter = NULL;
}
/* Flag duplicate argument if atom is bound in fun->object. */
dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object),
JSID_HIDE_NAME(
ATOM_TO_JSID(propAtom)))
? SPROP_IS_DUPLICATE
: 0;
if (!js_AddHiddenProperty(cx, fun->object,
ATOM_TO_JSID(propAtom),
getter, setter, SPROP_INVALID_SLOT,
attrs | JSPROP_SHARED,
dupflag | SPROP_HAS_SHORTID,
JSVAL_TO_INT(userid))) {
goto bad;
}
}
}
}
if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
goto bad;
if (xdr->mode == JSXDR_DECODE) {
fun->flags = (uint16) flagsword | JSFUN_INTERPRETED;
*objp = fun->object;
js_CallNewScriptHook(cx, fun->u.i.script, fun);
}
@ -1383,7 +1480,6 @@ fun_trace(JSTracer *trc, JSObject *obj)
{
JSFunction *fun;
/* A newborn function object may have a not yet initialized private slot. */
fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
if (fun) {
JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private");
@ -1401,11 +1497,6 @@ fun_reserveSlots(JSContext *cx, JSObject *obj)
{
JSFunction *fun;
/*
* We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during
* js_InitFunctionClass invocation the function is called before the
* private slot of the function object is set.
*/
fun = (JSFunction *) JS_GetPrivate(cx, obj);
return (fun && FUN_INTERPRETED(fun) &&
fun->u.i.script && fun->u.i.script->regexpsOffset != 0)
@ -1468,7 +1559,7 @@ fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
return JS_FALSE;
JS_ASSERT(JS_ObjectIsFunction(cx, obj));
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
if (!fun)
return JS_TRUE;
str = JS_DecompileFunction(cx, fun, (uintN)indent);
@ -1708,10 +1799,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSStackFrame *fp, *caller;
JSFunction *fun;
JSObject *parent;
uintN i, n, lineno;
uintN i, n, lineno, dupflag;
JSAtom *atom;
const char *filename;
JSBool ok;
JSObject *obj2;
JSProperty *prop;
JSScopeProperty *sprop;
JSString *str, *arg;
JSParseContext pc;
JSPrincipals *principals;
@ -1719,6 +1812,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
void *mark;
size_t arg_length, args_length, old_args_length;
JSTokenType tt;
JSBool ok;
fp = cx->fp;
if (!(fp->flags & JSFRAME_CONSTRUCTING)) {
@ -1727,11 +1821,6 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
}
/*
* The constructor is called before the private slot is initialized so we
* must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here.
*/
fun = (JSFunction *) JS_GetPrivate(cx, obj);
if (fun)
return JS_TRUE;
@ -1748,8 +1837,8 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
*/
parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
parent, cx->runtime->atomState.anonymousAtom);
fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent,
cx->runtime->atomState.anonymousAtom);
if (!fun)
return JS_FALSE;
@ -1873,12 +1962,24 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* we're assured at this point that it's a valid identifier.
*/
atom = CURRENT_TOKEN(&pc.tokenStream).t_atom;
if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
&obj2, &prop)) {
goto after_args;
}
sprop = (JSScopeProperty *) prop;
dupflag = 0;
if (sprop) {
ok = JS_TRUE;
if (obj2 == obj) {
const char *name = js_AtomToPrintableString(cx, atom);
/* Check for a duplicate parameter name. */
if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
const char *name;
name = js_AtomToPrintableString(cx, atom);
/*
* A duplicate parameter name. We force a duplicate
* node on the SCOPE_LAST_PROP(scope) list with the
* same id, distinguished by the SPROP_IS_DUPLICATE
* flag, and not mapped by an entry in scope.
*/
JS_ASSERT(sprop->getter == js_GetArgument);
ok = name &&
js_ReportCompileErrorNumber(cx, &pc.tokenStream,
JSREPORT_TS |
@ -1886,11 +1987,29 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSREPORT_STRICT,
JSMSG_DUPLICATE_FORMAL,
name);
dupflag = SPROP_IS_DUPLICATE;
}
OBJ_DROP_PROPERTY(cx, obj2, prop);
if (!ok)
goto after_args;
sprop = NULL;
}
if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG))
if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
js_GetArgument, js_SetArgument,
SPROP_INVALID_SLOT,
JSPROP_PERMANENT | JSPROP_SHARED,
dupflag | SPROP_HAS_SHORTID,
fun->nargs)) {
goto after_args;
}
if (fun->nargs == JS_BITMASK(16)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TOO_MANY_FUN_ARGS);
state = BAD;
goto after_args;
}
fun->nargs++;
/*
* Get the next token. Stop on end of stream. Otherwise
@ -1955,13 +2074,14 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
0);
if (!atom)
goto bad;
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
if (!fun)
goto bad;
fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0);
if (!fun->u.i.script)
goto bad;
fun->u.i.script->code[0] = JSOP_STOP;
fun->flags |= JSFUN_INTERPRETED;
return proto;
bad:
@ -2017,18 +2137,10 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
/* Initialize all function members. */
fun->object = NULL;
fun->nargs = nargs;
fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED);
if (flags & JSFUN_INTERPRETED) {
JS_ASSERT(!native);
JS_ASSERT(nargs == 0);
fun->u.i.nvars = 0;
fun->u.i.spare = 0;
fun->u.i.script = NULL;
} else {
fun->flags = flags & JSFUN_FLAGS_MASK;
fun->u.n.native = native;
fun->u.n.extra = 0;
fun->u.n.minargs = 0;
}
fun->atom = atom;
fun->clasp = NULL;
@ -2064,7 +2176,7 @@ js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
newfunobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
if (!newfunobj)
return NULL;
fun = GET_FUNCTION_PRIVATE(cx, funobj);
fun = (JSFunction *) JS_GetPrivate(cx, funobj);
if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
return NULL;
@ -2122,7 +2234,7 @@ js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
js_ReportIsNotFunction(cx, vp, flags);
return NULL;
}
return GET_FUNCTION_PRIVATE(cx, obj);
return (JSFunction *) JS_GetPrivate(cx, obj);
}
JSObject *
@ -2208,170 +2320,3 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
*vp, NULL,
name, source);
}
JSBool
js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind)
{
uint16 *indexp;
JSPropertyOp getter;
uintN readonly;
JS_ASSERT(FUN_INTERPRETED(fun));
JS_ASSERT(OBJ_IS_NATIVE(fun->object));
if (kind == JSLOCAL_ARG) {
#if JS_HAS_DESTRUCTURING
/*
* Destructuring parameter does not have name so we just update the
* number of arguments for it without adding a property.
*/
if (!atom) {
++fun->nargs;
return JS_TRUE;
}
#endif
indexp = &fun->nargs;
getter = JS_HIDDEN_ARG_GETTER;
readonly = 0;
} else {
JS_ASSERT(kind == JSLOCAL_VAR || kind == JSLOCAL_CONST);
indexp = &fun->u.i.nvars;
getter = JS_HIDDEN_VAR_GETTER;
readonly = (kind == JSLOCAL_CONST) ? JSPROP_READONLY : 0;
}
if (*indexp == JS_BITMASK(16)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
(kind == JSLOCAL_ARG)
? JSMSG_TOO_MANY_FUN_ARGS
:JSMSG_TOO_MANY_FUN_VARS);
return JS_FALSE;
}
/*
* To support duplicate parameter names we force a duplicate node on the
* SCOPE_LAST_PROP(scope) list with the same id, distinguished by the
* SPROP_ALLOW_DUPLICATE flag, and not mapped by an entry in scope. The
* flag is cleared when js_AddNativeProperty finds that the property is
* unique.
*/
if (!js_AddNativeProperty(cx, fun->object,
JSID_HIDE_NAME(ATOM_TO_JSID(atom)),
getter, NULL, SPROP_INVALID_SLOT,
JSPROP_PERMANENT | JSPROP_SHARED | readonly,
SPROP_HAS_SHORTID | SPROP_ALLOW_DUPLICATE,
*indexp)) {
return JS_FALSE;
}
/* Update the argument of variable counter. */
++*indexp;
return JS_TRUE;
}
JSLocalKind
js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp)
{
jsid id;
JSScope *scope;
JSScopeProperty *sprop;
JSLocalKind kind;
JS_ASSERT(FUN_INTERPRETED(fun));
JS_ASSERT(OBJ_IS_NATIVE(fun->object));
kind = JSLOCAL_NONE;
if (fun->nargs + fun->u.i.nvars != 0) {
id = JSID_HIDE_NAME(ATOM_TO_JSID(atom));
/*
* Inline js_LookupPropertyWithFlags to avoid prototype chain search
* and the resolve hook invocation. The former is just an optimization
* while the latter is necessary to avoid early creation of lazy slots
* in fun->objects. See comments in fun_resolve for details.
*/
JS_LOCK_OBJ(cx, fun->object);
scope = OBJ_SCOPE(fun->object);
JS_ASSERT(scope->object == fun->object);
sprop = SCOPE_GET_PROPERTY(scope, id);
if (sprop) {
JS_ASSERT(sprop->setter == NULL);
if (sprop->getter == JS_HIDDEN_ARG_GETTER) {
kind = JSLOCAL_ARG;
} else {
JS_ASSERT(sprop->getter == JS_HIDDEN_VAR_GETTER);
kind = (sprop->attrs & JSPROP_READONLY)
? JSLOCAL_CONST
: JSLOCAL_VAR;
}
if (indexp)
*indexp = (uint16) sprop->shortid;
}
JS_UNLOCK_OBJ(cx, fun->object);
}
return kind;
}
JSAtom **
js_GetLocalNames(JSContext *cx, JSFunction *fun, JSArenaPool *pool,
uint32 **bitmap)
{
uintN n, index;
size_t allocsize;
JSAtom **names;
JSScopeProperty *sprop;
JSBool setbit;
uint32 bit;
#ifdef DEBUG
uintN nvars = 0, nargs = 0;
#endif
JS_ASSERT(FUN_INTERPRETED(fun));
JS_ASSERT(OBJ_IS_NATIVE(fun->object));
n = fun->nargs + fun->u.i.nvars;
JS_ASSERT(n != 0);
allocsize = n * sizeof *names;
if (bitmap)
allocsize += JS_HOWMANY(n, JS_BITS_PER_UINT32) * sizeof(uint32);
JS_ARENA_ALLOCATE_CAST(names, JSAtom **, pool, allocsize);
if (!names) {
JS_ReportOutOfMemory(cx);
return NULL;
}
#if JS_HAS_DESTRUCTURING
/* Some parameter names can be NULL due to destructuring patterns. */
memset(names, 0, fun->nargs * sizeof *names);
#endif
if (bitmap) {
*bitmap = (uint32 *) (names + n);
memset(*bitmap, 0, JS_HOWMANY(n, JS_BITS_PER_UINT32) * sizeof(uint32));
}
for (sprop = SCOPE_LAST_PROP(OBJ_SCOPE(fun->object));
sprop; sprop = sprop->parent) {
if (!JSID_IS_HIDDEN(sprop->id))
continue;
index = (uint16) sprop->shortid;
if (sprop->getter == JS_HIDDEN_ARG_GETTER) {
JS_ASSERT(nargs++ < fun->nargs);
JS_ASSERT(index < fun->nargs);
setbit = JS_TRUE;
} else {
JS_ASSERT(sprop->getter == JS_HIDDEN_VAR_GETTER);
JS_ASSERT(nvars++ < fun->u.i.nvars);
JS_ASSERT(index < fun->u.i.nvars);
index += fun->nargs;
setbit = (sprop->attrs & JSPROP_READONLY);
}
names[index] = JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
if (bitmap && setbit) {
bit = JS_BIT(index & (JS_BITS_PER_UINT32 - 1));
JS_ASSERT(((*bitmap)[index / JS_BITS_PER_UINT32] & bit) == 0);
(*bitmap)[index / JS_BITS_PER_UINT32] |= bit;
}
}
#if !JS_HAS_DESTRUCTURING
JS_ASSERT(nargs == fun->nargs);
#endif
JS_ASSERT(nvars == fun->u.i.nvars);
return names;
}

View File

@ -98,14 +98,6 @@ extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
(!JSVAL_IS_PRIMITIVE(v) && \
OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass)
/*
* Macro to access the private slot of the function object after the slot is
* initialized.
*/
#define GET_FUNCTION_PRIVATE(cx, funobj) \
(JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass), \
(JSFunction *) OBJ_GET_PRIVATE(cx, funobj))
extern JSObject *
js_InitFunctionClass(JSContext *cx, JSObject *obj);
@ -180,49 +172,6 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
extern JSBool
js_XDRFunction(JSXDRState *xdr, JSObject **objp);
typedef enum JSLocalKind {
JSLOCAL_NONE,
JSLOCAL_ARG,
JSLOCAL_VAR,
JSLOCAL_CONST
} JSLocalKind;
extern JSBool
js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind);
/*
* Look up an argument or variable name returning its kind when found or
* JSLOCAL_NONE when no such name exists. When indexp is not null and the name
* exists, *indexp will receive the index of the corresponding argument or
* variable.
*/
extern JSLocalKind
js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp);
/*
* Get names of arguments and variables for the interpreted function.
*
* The result is an array allocated from the given pool with
* fun->nargs + fun->u.i.nvars
* elements with the names of the arguments coming first. The argument
* name is null when it corresponds to a destructive pattern.
*
* When bitmap is not null, on successful return it will contain a bit array
* where for each index below fun->nargs the bit is set when the corresponding
* argument name is not null. For indexes greater or equal fun->nargs the bit
* is set when the corresponding var is really a const.
*/
extern JSAtom **
js_GetLocalNames(JSContext *cx, JSFunction *fun, JSArenaPool *pool,
uint32 **bitmap);
/*
* Pseudo-getter function pointers to distinguish the kind of the hidden
* property.
*/
#define JS_HIDDEN_ARG_GETTER ((JSPropertyOp) sizeof(jsuword))
#define JS_HIDDEN_VAR_GETTER ((JSPropertyOp) (2 * sizeof(jsuword)))
JS_END_EXTERN_C
#endif /* jsfun_h___ */

View File

@ -388,6 +388,30 @@ js_FreeStack(JSContext *cx, void *mark)
JS_ARENA_RELEASE(&cx->stackPool, mark);
}
JSBool
js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return JS_TRUE;
}
JSBool
js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return JS_TRUE;
}
JSBool
js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return JS_TRUE;
}
JSBool
js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
return JS_TRUE;
}
JSObject *
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
{
@ -892,7 +916,7 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
key.lineno = 0;
name = "";
if (VALUE_IS_FUNCTION(cx, callee)) {
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
if (fun->atom)
name = js_AtomToPrintableString(cx, fun->atom);
if (FUN_INTERPRETED(fun)) {
@ -982,8 +1006,8 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
break;
case JSTYPE_FUNCTION:
if (VALUE_IS_FUNCTION(cx, argval)) {
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(argval));
if (fun->atom) {
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(argval));
if (fun && fun->atom) {
str = ATOM_TO_STRING(fun->atom);
break;
}
@ -1149,7 +1173,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
} else {
have_fun:
/* Get private data and set derived locals from it. */
fun = GET_FUNCTION_PRIVATE(cx, funobj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj);
nslots = FUN_MINARGS(fun);
nslots = (nslots > argc) ? nslots - argc : 0;
if (FUN_INTERPRETED(fun)) {
@ -1493,7 +1517,8 @@ js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE);
if (cx->runtime->checkObjectAccess &&
VALUE_IS_FUNCTION(cx, fval) &&
FUN_INTERPRETED(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval))) &&
FUN_INTERPRETED((JSFunction *)
JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval))) &&
!cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
&fval)) {
return JS_FALSE;
@ -1913,7 +1938,7 @@ js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
parent = OBJ_GET_PARENT(cx, obj2);
if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
funclasp = GET_FUNCTION_PRIVATE(cx, obj2)->clasp;
funclasp = ((JSFunction *) OBJ_GET_PRIVATE(cx, obj2))->clasp;
if (funclasp)
clasp = funclasp;
}
@ -3887,9 +3912,9 @@ interrupt:
SAVE_SP_AND_PC(fp);
if (VALUE_IS_FUNCTION(cx, lval)) {
obj = JSVAL_TO_OBJECT(lval);
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
if (FUN_INTERPRETED(fun)) {
if (fun->flags & JSFUN_INTERPRETED) {
uintN nframeslots, nvars, nslots, missing;
JSArena *a;
jsuword avail, nbytes;
@ -4851,7 +4876,7 @@ interrupt:
BEGIN_CASE(JSOP_DEFFUN)
LOAD_FUNCTION(0);
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
id = ATOM_TO_JSID(fun->atom);
/*
@ -5092,7 +5117,7 @@ interrupt:
* name is [fun->atom, the identifier parsed by the compiler],
* value is Result(3), and attributes are { DontDelete, ReadOnly }.
*/
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
attrs = JSFUN_GSFLAG2ATTR(fun->flags);
if (attrs) {
attrs |= JSPROP_SHARED;
@ -5166,7 +5191,7 @@ interrupt:
* unless fun is a getter or setter (in which case, obj is cast to
* a JSPropertyOp and passed accordingly).
*/
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
attrs = JSFUN_GSFLAG2ATTR(fun->flags);
if (attrs) {
attrs |= JSPROP_SHARED;
@ -5845,7 +5870,7 @@ interrupt:
/* Wrap primitive lval in object clothing if necessary. */
if (!VALUE_IS_FUNCTION(cx, rval) ||
(obj = JSVAL_TO_OBJECT(rval),
fun = GET_FUNCTION_PRIVATE(cx, obj),
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj),
!PRIMITIVE_THIS_TEST(fun, lval))) {
ok = js_PrimitiveToObject(cx, &sp[-1]);
if (!ok)

View File

@ -120,6 +120,18 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp);
extern JS_FRIEND_API(void)
js_FreeStack(JSContext *cx, void *mark);
extern JSBool
js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
extern JSBool
js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
extern JSBool
js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
extern JSBool
js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
#ifdef DUMP_CALL_TABLE
# define JSOPTION_LOGCALL_TOSOURCE JS_BIT(15)

View File

@ -2995,6 +2995,26 @@ CheckForStringIndex(jsid id, const jschar *cp, const jschar *end,
return id;
}
JSScopeProperty *
js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
uintN attrs, uintN flags, intN shortid)
{
id = JSID_HIDE_NAME(id);
flags |= SPROP_IS_HIDDEN;
return js_AddNativeProperty(cx, obj, id, getter, setter, slot, attrs,
flags, shortid);
}
JSBool
js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp)
{
id = JSID_HIDE_NAME(id);
return js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_HIDDEN,
objp, propp);
}
JSScopeProperty *
js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSPropertyOp setter, uint32 slot,

View File

@ -443,6 +443,21 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp);
extern void
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot);
/*
* Native property add and lookup variants that hide id in the hidden atom
* subspace, so as to avoid collisions between internal properties such as
* formal arguments and local variables in function objects, and externally
* set properties with the same ids.
*/
extern JSScopeProperty *
js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
uintN attrs, uintN flags, intN shortid);
extern JSBool
js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp);
/*
* Find or create a property named by id in obj's scope, with the given getter
* and setter, slot, attributes, and other members.
@ -492,11 +507,15 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
/*
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
* JSRESOLVE_HIDDEN flags hidden function param/local name lookups, just for
* internal use by fun_resolve and similar built-ins.
*/
extern JSBool
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp);
#define JSRESOLVE_HIDDEN 0x8000
extern JS_FRIEND_API(JSBool)
js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
JSProperty **propp);
@ -625,7 +644,6 @@ js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller
extern JSBool
js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
JSPrincipals *principals, JSAtom *caller);
JS_END_EXTERN_C
#endif /* jsobj_h___ */

View File

@ -649,8 +649,7 @@ struct JSPrinter {
JSPackedBool grouped; /* in parenthesized expression context */
JSScript *script; /* script being printed */
jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */
JSFunction *fun; /* interpreted function */
JSAtom **localNames; /* argument and variable names */
JSObject *object; /* interpreted function object */
#if JS_HAS_BLOCK_SCOPE
JSBraceState braceState; /* remove braces around let declaration */
ptrdiff_t spaceOffset; /* -1 or offset of space before maybe-{ */
@ -666,8 +665,7 @@ struct JSPrinter {
#define JS_IN_GROUP_CONTEXT 0x10000
JSPrinter *
JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
uintN indent, JSBool pretty)
JS_NEW_PRINTER(JSContext *cx, const char *name, uintN indent, JSBool pretty)
{
JSPrinter *jp;
@ -681,20 +679,11 @@ JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
jp->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0;
jp->script = NULL;
jp->dvgfence = NULL;
jp->object = NULL;
#if JS_HAS_BLOCK_SCOPE
jp->braceState = ALWAYS_BRACE;
jp->spaceOffset = -1;
#endif
jp->fun = fun;
if (!fun || !FUN_INTERPRETED(fun) || fun->nargs + fun->u.i.nvars == 0) {
jp->localNames = NULL;
} else {
jp->localNames = js_GetLocalNames(cx, fun, &jp->pool, NULL);
if (!jp->localNames) {
js_DestroyPrinter(jp);
return NULL;
}
}
return jp;
}
@ -1217,35 +1206,50 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
return JS_TRUE;
}
static JSAtom *
GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot)
{
JSObject *obj;
JSScopeProperty *sprop;
obj = jp->object;
while (obj) {
for (sprop = SCOPE_LAST_PROP(OBJ_SCOPE(obj)); sprop;
sprop = sprop->parent) {
if (sprop->getter != getter)
continue;
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(JSID_IS_HIDDEN(sprop->id));
if ((uintN) sprop->shortid == slot)
return JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
}
obj = OBJ_GET_PROTO(jp->sprinter.context, obj);
}
return NULL;
}
static JSBool
PushSlotAtom(SprintStack *ss, JSPropertyOp getter, uintN slot, JSOp op)
{
JSAtom *atom;
char *lval;
atom = GetSlotAtom(ss->printer, getter, slot);
if (!atom)
return JS_FALSE;
JS_ASSERT(ATOM_IS_STRING(atom));
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
if (!lval)
return JS_FALSE;
return PushOff(ss, STR2OFF(&ss->sprinter, lval), op);
}
#define LOCAL_ASSERT_RV(expr, rv) \
JS_BEGIN_MACRO \
JS_ASSERT(expr); \
if (!(expr)) return (rv); \
JS_END_MACRO
static JSAtom *
GetSlotAtom(JSPrinter *jp, JSBool argument, uintN slot)
{
JSFunction *fun;
JSAtom *name;
fun = jp->fun;
LOCAL_ASSERT_RV(jp->fun, NULL);
LOCAL_ASSERT_RV(jp->localNames, NULL);
if (argument) {
LOCAL_ASSERT_RV(slot < fun->nargs, NULL);
name = jp->localNames[slot];
#if !JS_HAS_DESTRUCTURING
LOCAL_ASSERT_RV(name, NULL);
#endif
} else {
LOCAL_ASSERT_RV(slot < fun->u.i.nvars, NULL);
name = jp->localNames[fun->nargs + slot];
LOCAL_ASSERT_RV(name, NULL);
}
return name;
}
const char *
GetLocal(SprintStack *ss, jsint i)
{
@ -1358,14 +1362,14 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
i = GET_UINT16(pc);
atom = NULL;
lval = NULL;
if (op == JSOP_SETARG || op == JSOP_SETVAR) {
atom = GetSlotAtom(jp, op == JSOP_SETARG, i);
LOCAL_ASSERT(atom);
} else if (op == JSOP_SETGVAR) {
if (op == JSOP_SETARG)
atom = GetSlotAtom(jp, js_GetArgument, i);
else if (op == JSOP_SETVAR)
atom = GetSlotAtom(jp, js_GetLocalVariable, i);
else if (op == JSOP_SETGVAR)
GET_ATOM_FROM_BYTECODE(jp->script, pc, 0, atom);
} else {
else
lval = GetLocal(ss, i);
}
if (atom)
lval = js_AtomToPrintableString(cx, atom);
LOCAL_ASSERT(lval);
@ -2081,19 +2085,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
JS_GET_SCRIPT_OBJECT(jp->script, js_GetSrcNoteOffset(sn, 0),
obj);
do_function:
js_puts(jp, "\n");
fun = GET_FUNCTION_PRIVATE(cx, obj);
jp2 = JS_NEW_PRINTER(cx, "nested_function", fun,
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
jp2 = JS_NEW_PRINTER(cx, "nested_function",
jp->indent, jp->pretty);
if (!jp2)
return NULL;
ok = js_DecompileFunction(jp2);
if (ok && jp2->sprinter.base)
jp2->object = jp->object;
js_puts(jp2, "\n");
ok = js_DecompileFunction(jp2, fun);
if (ok && jp2->sprinter.base) {
js_puts(jp, jp2->sprinter.base);
js_puts(jp, "\n");
}
js_DestroyPrinter(jp2);
if (!ok)
return NULL;
js_puts(jp, "\n\n");
js_puts(jp, "\n");
break;
case SRC_BRACE:
@ -2735,8 +2742,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
case JSOP_RETURN:
LOCAL_ASSERT(jp->fun);
fun = jp->fun;
obj = jp->object;
LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
if (fun->flags & JSFUN_EXPR_CLOSURE) {
rval = POP_STR();
js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format,
@ -3077,13 +3085,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
goto do_logical_connective;
case JSOP_FORARG:
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
LOCAL_ASSERT(atom);
goto do_fornameinloop;
case JSOP_FORVAR:
case JSOP_FORCONST:
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
LOCAL_ASSERT(atom);
goto do_fornameinloop;
@ -3313,12 +3321,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
case JSOP_SETARG:
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
LOCAL_ASSERT(atom);
goto do_setname;
case JSOP_SETVAR:
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
LOCAL_ASSERT(atom);
goto do_setname;
@ -3493,13 +3501,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_INCARG:
case JSOP_DECARG:
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
LOCAL_ASSERT(atom);
goto do_incatom;
case JSOP_INCVAR:
case JSOP_DECVAR:
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
LOCAL_ASSERT(atom);
goto do_incatom;
@ -3555,13 +3563,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_ARGINC:
case JSOP_ARGDEC:
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
LOCAL_ASSERT(atom);
goto do_atominc;
case JSOP_VARINC:
case JSOP_VARDEC:
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
LOCAL_ASSERT(atom);
goto do_atominc;
@ -3638,13 +3646,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
END_LITOPX_CASE
BEGIN_LITOPX_CASE(JSOP_GETARGPROP, ARGNO_LEN)
if (!PushSlotAtom(ss, js_GetArgument, GET_ARGNO(pc), op))
return NULL;
goto do_getprop;
BEGIN_LITOPX_CASE(JSOP_GETVARPROP, VARNO_LEN)
atom = GetSlotAtom(ss->printer, op == JSOP_GETARGPROP,
GET_UINT16(pc));
LOCAL_ASSERT(atom);
JS_ASSERT(ATOM_IS_STRING(atom));
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op))
if (!PushSlotAtom(ss, js_GetLocalVariable, GET_VARNO(pc), op))
return NULL;
goto do_getprop;
@ -3745,7 +3752,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_CALLARG:
case JSOP_GETARG:
i = GET_ARGNO(pc);
atom = GetSlotAtom(jp, JS_TRUE, i);
atom = GetSlotAtom(jp, js_GetArgument, i);
#if JS_HAS_DESTRUCTURING
if (!atom) {
todo = Sprint(&ss->sprinter, "%s[%d]", js_arguments_str, i);
@ -3758,7 +3765,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_CALLVAR:
case JSOP_GETVAR:
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
LOCAL_ASSERT(atom);
goto do_name;
@ -3821,7 +3828,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
SprintStack ss2;
LOAD_FUNCTION(0);
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
LOCAL_ASSERT(FUN_INTERPRETED(fun));
inner = fun->u.i.script;
@ -3937,7 +3944,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* parenthesization without confusing getter/setter code
* that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ.
*/
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
if (!(fun->flags & JSFUN_EXPR_CLOSURE))
indent |= JS_IN_GROUP_CONTEXT;
str = JS_DecompileFunction(cx, fun, indent);
@ -4684,35 +4691,37 @@ js_DecompileScript(JSPrinter *jp, JSScript *script)
static const char native_code_str[] = "\t[native code]\n";
JSBool
js_DecompileFunctionBody(JSPrinter *jp)
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
{
JSScript *script;
JSObject *oldobject;
JSBool ok;
JS_ASSERT(jp->fun);
JS_ASSERT(!jp->script);
if (!FUN_INTERPRETED(jp->fun)) {
if (!FUN_INTERPRETED(fun)) {
js_printf(jp, native_code_str);
return JS_TRUE;
}
script = jp->fun->u.i.script;
return js_DecompileCode(jp, script, script->code, (uintN)script->length, 0);
script = fun->u.i.script;
oldobject = jp->object;
jp->object = fun->object;
ok = js_DecompileCode(jp, script, script->code, (uintN)script->length, 0);
jp->object = oldobject;
return ok;
}
JSBool
js_DecompileFunction(JSPrinter *jp)
js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
{
JSFunction *fun;
uintN i;
JSAtom *param;
JSContext *cx;
uintN i, nargs, indent;
void *mark;
JSAtom **params;
JSObject *oldobject;
JSScopeProperty *sprop;
jsbytecode *pc, *endpc;
ptrdiff_t len;
JSBool ok;
fun = jp->fun;
JS_ASSERT(fun);
JS_ASSERT(!jp->script);
/*
* If pretty, conform to ECMA-262 Edition 3, 15.3.4.2, by decompiling a
* FunctionDeclaration. Otherwise, check the JSFUN_LAMBDA flag and force
@ -4734,19 +4743,45 @@ js_DecompileFunction(JSPrinter *jp)
return JS_FALSE;
js_puts(jp, "(");
if (!FUN_INTERPRETED(fun)) {
js_printf(jp, ") {\n");
jp->indent += 4;
js_printf(jp, native_code_str);
jp->indent -= 4;
js_printf(jp, "\t}");
} else {
if (FUN_INTERPRETED(fun) && fun->object) {
size_t paramsize;
#ifdef JS_HAS_DESTRUCTURING
SprintStack ss;
void *mark;
JSScript *oldscript;
#endif
/* Print the parameters. */
/*
* Print the parameters.
*
* This code is complicated by the need to handle duplicate parameter
* names, as required by ECMA (bah!). A duplicate parameter is stored
* as another node with the same id (the parameter name) but different
* shortid (the argument index) along the property tree ancestor line
* starting at SCOPE_LAST_PROP(scope). Only the last duplicate param
* is mapped by the scope's hash table.
*/
cx = jp->sprinter.context;
nargs = fun->nargs;
mark = JS_ARENA_MARK(&cx->tempPool);
paramsize = nargs * sizeof(JSAtom *);
JS_ARENA_ALLOCATE_CAST(params, JSAtom **, &cx->tempPool, paramsize);
if (!params) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
memset(params, 0, paramsize);
for (sprop = SCOPE_LAST_PROP(OBJ_SCOPE(fun->object)); sprop;
sprop = sprop->parent) {
if (sprop->getter != js_GetArgument)
continue;
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT((uint16) sprop->shortid < nargs);
JS_ASSERT(JSID_IS_HIDDEN(sprop->id));
params[(uint16) sprop->shortid] =
JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
}
pc = fun->u.i.script->main;
endpc = pc + fun->u.i.script->length;
ok = JS_TRUE;
@ -4757,20 +4792,20 @@ js_DecompileFunction(JSPrinter *jp)
pc += JSOP_GENERATOR_LENGTH;
ss.printer = NULL;
oldscript = jp->script;
jp->script = fun->u.i.script;
mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool);
oldobject = jp->object;
jp->object = fun->object;
#endif
for (i = 0; i < fun->nargs; i++) {
for (i = 0; i < nargs; i++) {
if (i > 0)
js_puts(jp, ", ");
param = GetSlotAtom(jp, JS_TRUE, i);
#if JS_HAS_DESTRUCTURING
#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, JS_FALSE)
if (!param) {
if (!params[i]) {
ptrdiff_t todo;
const char *lval;
@ -4778,8 +4813,7 @@ js_DecompileFunction(JSPrinter *jp)
pc += JSOP_GETARG_LENGTH;
LOCAL_ASSERT(*pc == JSOP_DUP);
if (!ss.printer) {
ok = InitSprintStack(jp->sprinter.context, &ss, jp,
fun->u.i.script->depth);
ok = InitSprintStack(cx, &ss, jp, fun->u.i.script->depth);
if (!ok)
break;
}
@ -4802,18 +4836,26 @@ js_DecompileFunction(JSPrinter *jp)
#undef LOCAL_ASSERT
#endif
if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(param), 0)) {
if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(params[i]), 0)) {
ok = JS_FALSE;
break;
}
}
#ifdef JS_HAS_DESTRUCTURING
jp->script = NULL;
JS_ARENA_RELEASE(&jp->sprinter.context->tempPool, mark);
jp->script = oldscript;
jp->object = oldobject;
#endif
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (!ok)
return JS_FALSE;
#ifdef __GNUC__
} else {
pc = NULL;
#endif
}
indent = jp->indent;
if (fun->flags & JSFUN_EXPR_CLOSURE) {
js_printf(jp, ") ");
} else {
@ -4821,20 +4863,29 @@ js_DecompileFunction(JSPrinter *jp)
jp->indent += 4;
}
if (FUN_INTERPRETED(fun) && fun->object) {
oldobject = jp->object;
jp->object = fun->object;
len = fun->u.i.script->code + fun->u.i.script->length - pc;
ok = js_DecompileCode(jp, fun->u.i.script, pc, (uintN)len, 0);
if (!ok)
jp->object = oldobject;
if (!ok) {
jp->indent = indent;
return JS_FALSE;
}
} else {
js_printf(jp, native_code_str);
}
if (!(fun->flags & JSFUN_EXPR_CLOSURE)) {
jp->indent -= 4;
js_printf(jp, "\t}");
}
}
if (!jp->pretty && !jp->grouped && (fun->flags & JSFUN_LAMBDA))
if (!jp->pretty) {
if (!jp->grouped && (fun->flags & JSFUN_LAMBDA))
js_puts(jp, ")");
}
return JS_TRUE;
}
@ -5162,8 +5213,12 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
}
name = NULL;
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", fp->fun, 0, JS_FALSE);
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", 0, JS_FALSE);
if (jp) {
if (fp->fun && fp->fun->object) {
JS_ASSERT(OBJ_IS_NATIVE(fp->fun->object));
jp->object = fp->fun->object;
}
jp->dvgfence = end;
if (js_DecompileCode(jp, script, begin, (uintN)len, (uintN)pcdepth)) {
name = (jp->sprinter.base) ? jp->sprinter.base : (char *) "";

View File

@ -273,16 +273,15 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote);
*/
#ifdef JS_ARENAMETER
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \
js_NewPrinter(cx, name, fun, indent, pretty)
# define JS_NEW_PRINTER(cx, name, indent, pretty) \
js_NewPrinter(cx, name, indent, pretty)
#else
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \
js_NewPrinter(cx, fun, indent, pretty)
# define JS_NEW_PRINTER(cx, name, indent, pretty) \
js_NewPrinter(cx, indent, pretty)
#endif
extern JSPrinter *
JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
uintN indent, JSBool pretty);
JS_NEW_PRINTER(JSContext *cx, const char *name, uintN indent, JSBool pretty);
extern void
js_DestroyPrinter(JSPrinter *jp);
@ -356,10 +355,10 @@ extern JSBool
js_DecompileScript(JSPrinter *jp, JSScript *script);
extern JSBool
js_DecompileFunctionBody(JSPrinter *jp);
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
extern JSBool
js_DecompileFunction(JSPrinter *jp);
js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
/*
* Find the source expression that resulted in v, and return a newly allocated

View File

@ -814,7 +814,6 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
uintN oldflags, firstLine;
JSParseNode *pn;
JS_ASSERT(FUN_INTERPRETED(fun));
fp = cx->fp;
funobj = fun->object;
if (!fp || fp->fun != fun || fp->varobj != funobj ||
@ -829,6 +828,12 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
cx->fp = &frame;
}
/*
* Set interpreted early so js_EmitTree can test it to decide whether to
* eliminate useless expressions.
*/
fun->flags |= JSFUN_INTERPRETED;
js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
stmtInfo.flags = SIF_BODY_BLOCK;
@ -991,7 +996,9 @@ struct BindData {
struct {
JSFunction *fun; /* this overlays u.arg.fun */
JSClass *clasp;
JSLocalKind kind;
JSPropertyOp getter;
JSPropertyOp setter;
uintN attrs;
} var;
struct {
jsuint index;
@ -1009,40 +1016,83 @@ struct BindData {
(data)->pn ? (void *)(data)->pn : (void *)(data)->ts, \
((data)->pn ? JSREPORT_PN : JSREPORT_TS) | (flags)
static JSBool
BumpFormalCount(JSContext *cx, JSFunction *fun)
{
if (fun->nargs == JS_BITMASK(16)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TOO_MANY_FUN_ARGS);
return JS_FALSE;
}
fun->nargs++;
return JS_TRUE;
}
static JSBool
BindArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
{
JSObject *obj, *pobj;
JSProperty *prop;
JSBool ok;
uintN dupflag;
JSFunction *fun;
const char *name;
/*
* Check for a duplicate parameter name, a "feature" required by ECMA-262.
*/
if (js_LookupLocal(cx, data->u.arg.fun, atom, NULL) != JSLOCAL_NONE) {
obj = data->obj;
ok = js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop);
if (!ok)
return JS_FALSE;
dupflag = 0;
if (prop) {
JS_ASSERT(pobj == obj);
name = js_AtomToPrintableString(cx, atom);
if (!name ||
!js_ReportCompileErrorNumber(cx,
/*
* A duplicate parameter name, a "feature" required by ECMA-262.
* We force a duplicate node on the SCOPE_LAST_PROP(scope) list
* with the same id, distinguished by the SPROP_IS_DUPLICATE flag,
* and not mapped by an entry in scope.
*/
ok = name &&
js_ReportCompileErrorNumber(cx,
BIND_DATA_REPORT_ARGS(data,
JSREPORT_WARNING |
JSREPORT_STRICT),
JSMSG_DUPLICATE_FORMAL,
name)) {
name);
OBJ_DROP_PROPERTY(cx, pobj, prop);
if (!ok)
return JS_FALSE;
}
dupflag = SPROP_IS_DUPLICATE;
}
return js_AddLocal(cx, data->u.arg.fun, atom, JSLOCAL_ARG);
fun = data->u.arg.fun;
if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom),
js_GetArgument, js_SetArgument,
SPROP_INVALID_SLOT,
JSPROP_PERMANENT | JSPROP_SHARED,
dupflag | SPROP_HAS_SHORTID,
fun->nargs)) {
return JS_FALSE;
}
return BumpFormalCount(cx, fun);
}
static JSBool
BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
{
JSFunction *fun;
/*
* Can't increase fun->nvars in an active frame when kind is JSFL_NONE.
* Can't increase fun->nvars in an active frame, so insist that getter is
* js_GetLocalVariable, not js_GetCallVariable or anything else.
*/
if (data->u.var.kind == JSLOCAL_NONE)
if (data->u.var.getter != js_GetLocalVariable)
return JS_TRUE;
JS_ASSERT(data->u.var.kind == JSLOCAL_VAR ||
data->u.var.kind == JSLOCAL_CONST);
/*
* Don't bind a variable with the hidden name 'arguments', per ECMA-262.
@ -1053,7 +1103,21 @@ BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
if (atom == cx->runtime->atomState.argumentsAtom)
return JS_TRUE;
return js_AddLocal(cx, data->u.var.fun, atom, data->u.var.kind);
fun = data->u.var.fun;
if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom),
data->u.var.getter, data->u.var.setter,
SPROP_INVALID_SLOT,
data->u.var.attrs | JSPROP_SHARED,
SPROP_HAS_SHORTID, fun->u.i.nvars)) {
return JS_FALSE;
}
if (fun->u.i.nvars == JS_BITMASK(16)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TOO_MANY_FUN_VARS);
return JS_FALSE;
}
fun->u.i.nvars++;
return JS_TRUE;
}
#if JS_HAS_DESTRUCTURING
@ -1069,6 +1133,9 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
JSTreeContext *tc)
{
JSAtomListElement *ale;
JSFunction *fun;
JSObject *obj, *pobj;
JSProperty *prop;
const char *name;
ATOM_LIST_SEARCH(ale, &tc->decls, atom);
@ -1079,7 +1146,13 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
ALE_SET_JSOP(ale, data->op);
}
if (js_LookupLocal(cx, data->u.var.fun, atom, NULL) != JSLOCAL_NONE) {
fun = data->u.var.fun;
obj = data->obj;
if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
return JS_FALSE;
if (prop) {
JS_ASSERT(pobj == obj && OBJ_IS_NATIVE(pobj));
name = js_AtomToPrintableString(cx, atom);
if (!name ||
!js_ReportCompileErrorNumber(cx,
@ -1090,6 +1163,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
name)) {
return JS_FALSE;
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
} else {
if (!BindLocalVariable(cx, data, atom))
return JS_FALSE;
@ -1108,8 +1182,9 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSAtom *funAtom;
JSParsedObjectBox *funpob;
JSStackFrame *fp;
JSObject *varobj;
JSObject *varobj, *pobj;
JSAtomListElement *ale;
JSProperty *prop;
JSFunction *fun;
JSTreeContext funtc;
#if JS_HAS_DESTRUCTURING
@ -1190,31 +1265,56 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
* JSOP_GETVAR bytecode).
*/
if (AT_TOP_LEVEL(tc) && (tc->flags & TCF_IN_FUNCTION)) {
JSLocalKind localKind;
JSScopeProperty *sprop;
/*
* Define a property on the outer function so that BindNameToSlot
* can properly optimize accesses. Note that we need a variable,
* not an argument, for the function statement. Thus we add a
* variable even if the parameter with the given name already
* exists.
* can properly optimize accesses.
*/
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, varobj));
localKind = js_LookupLocal(cx, fp->fun, funAtom, NULL);
if (localKind == JSLOCAL_NONE || localKind == JSLOCAL_ARG) {
if (!js_AddLocal(cx, fp->fun, funAtom, JSLOCAL_VAR))
JS_ASSERT(fp->fun == (JSFunction *) OBJ_GET_PRIVATE(cx, varobj));
if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom),
&pobj, &prop)) {
return NULL;
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
sprop = NULL;
if (!prop ||
pobj != varobj ||
(sprop = (JSScopeProperty *)prop,
sprop->getter != js_GetLocalVariable)) {
uintN sflags;
/*
* Use SPROP_IS_DUPLICATE if there is a formal argument of the
* same name, so the decompiler can find the parameter name.
*/
sflags = (sprop && sprop->getter == js_GetArgument)
? SPROP_IS_DUPLICATE | SPROP_HAS_SHORTID
: SPROP_HAS_SHORTID;
if (!js_AddHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom),
js_GetLocalVariable,
js_SetLocalVariable,
SPROP_INVALID_SLOT,
JSPROP_PERMANENT | JSPROP_SHARED,
sflags, fp->fun->u.i.nvars)) {
return NULL;
}
if (fp->fun->u.i.nvars == JS_BITMASK(16)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TOO_MANY_FUN_VARS);
return NULL;
}
fp->fun->u.i.nvars++;
}
}
}
fun = js_NewFunction(cx, NULL, NULL, 0,
JSFUN_INTERPRETED | (lambda ? JSFUN_LAMBDA : 0),
varobj, funAtom);
fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj,
funAtom);
if (!fun)
return NULL;
#if JS_HAS_GETTER_SETTER
if (op != JSOP_NOP)
fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;
@ -1222,7 +1322,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
/*
* Create wrapping box for fun->object early to protect against a
* last-ditch GC.
* last-ditch GC under js_LookupHiddenProperty.
*/
funpob = js_NewParsedObjectBox(cx, tc->parseContext, fun->object);
if (!funpob)
@ -1262,7 +1362,10 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
data.op = JSOP_DEFVAR;
data.binder = BindDestructuringArg;
data.u.var.clasp = &js_FunctionClass;
data.u.var.kind = JSLOCAL_VAR;
data.u.var.getter = js_GetLocalVariable;
data.u.var.setter = js_SetLocalVariable;
data.u.var.attrs = JSPROP_PERMANENT;
lhs = DestructuringExpr(cx, &data, &funtc, tt);
if (!lhs)
return NULL;
@ -1278,7 +1381,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
* parameter that is to be destructured.
*/
slot = fun->nargs;
if (!js_AddLocal(cx, fun, NULL, JSLOCAL_ARG))
if (!BumpFormalCount(cx, fun))
return NULL;
/*
@ -1736,8 +1839,11 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
JSOp op, prevop;
const char *name;
JSFunction *fun;
JSObject *obj;
JSLocalKind localKind;
JSObject *obj, *pobj;
JSProperty *prop;
JSBool ok;
JSPropertyOp getter, setter;
JSScopeProperty *sprop;
stmt = js_LexicalLookup(tc, atom, NULL, 0);
ATOM_LIST_SEARCH(ale, &tc->decls, atom);
@ -1779,16 +1885,84 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
fun = data->u.var.fun;
obj = data->obj;
if (!fun || OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
/*
* Don't lookup global variables or variables in an active frame at
* compile time.
*/
return JS_TRUE;
if (!fun) {
/* Don't lookup global variables at compile time. */
prop = NULL;
} else {
JS_ASSERT(OBJ_IS_NATIVE(obj));
if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
&pobj, &prop)) {
return JS_FALSE;
}
}
localKind = js_LookupLocal(cx, fun, atom, NULL);
if (localKind == JSLOCAL_NONE) {
ok = JS_TRUE;
getter = data->u.var.getter;
setter = data->u.var.setter;
if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {
sprop = (JSScopeProperty *)prop;
if (sprop->getter == js_GetArgument) {
name = js_AtomToPrintableString(cx, atom);
if (!name) {
ok = JS_FALSE;
} else if (op == JSOP_DEFCONST) {
js_ReportCompileErrorNumber(cx,
BIND_DATA_REPORT_ARGS(data,
JSREPORT_ERROR),
JSMSG_REDECLARED_PARAM,
name);
ok = JS_FALSE;
} else {
getter = js_GetArgument;
setter = js_SetArgument;
ok = js_ReportCompileErrorNumber(cx,
BIND_DATA_REPORT_ARGS(data,
JSREPORT_WARNING |
JSREPORT_STRICT),
JSMSG_VAR_HIDES_ARG,
name);
}
} else {
JS_ASSERT(getter == js_GetLocalVariable);
if (fun) {
/* Not an argument, must be a redeclared local var. */
if (data->u.var.clasp == &js_FunctionClass) {
JS_ASSERT(sprop->getter == js_GetLocalVariable);
JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
(uint16) sprop->shortid < fun->u.i.nvars);
} else if (data->u.var.clasp == &js_CallClass) {
if (sprop->getter == js_GetCallVariable) {
/*
* Referencing a name introduced by a var statement in
* the enclosing function. Check that the slot number
* we have is in range.
*/
JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&
(uint16) sprop->shortid < fun->u.i.nvars);
} else {
/*
* A variable introduced through another eval: don't
* use the special getters and setters since we can't
* allocate a slot in the frame.
*/
getter = sprop->getter;
setter = sprop->setter;
}
}
/* Override the old getter and setter, to handle eval. */
sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,
0, sprop->attrs,
getter, setter);
if (!sprop)
ok = JS_FALSE;
}
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
} else {
/*
* Property not found in current variable scope: we have not seen this
* variable before. Define a new local variable by adding a property
@ -1797,37 +1971,19 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
* bodies are handled at runtime, by script prolog JSOP_DEFVAR opcodes
* generated for slot-less vars.
*/
sprop = NULL;
if (prop) {
OBJ_DROP_PROPERTY(cx, pobj, prop);
prop = NULL;
}
if (cx->fp->scopeChain == obj &&
!js_InWithStatement(tc) &&
!BindLocalVariable(cx, data, atom)) {
return JS_FALSE;
}
} else if (localKind == JSLOCAL_ARG) {
name = js_AtomToPrintableString(cx, atom);
if (!name)
return JS_FALSE;
if (op == JSOP_DEFCONST) {
js_ReportCompileErrorNumber(cx,
BIND_DATA_REPORT_ARGS(data,
JSREPORT_ERROR),
JSMSG_REDECLARED_PARAM,
name);
return JS_FALSE;
}
if (!js_ReportCompileErrorNumber(cx,
BIND_DATA_REPORT_ARGS(data,
JSREPORT_WARNING |
JSREPORT_STRICT),
JSMSG_VAR_HIDES_ARG,
name)) {
return JS_FALSE;
}
} else {
/* Not an argument, must be a redeclared local var. */
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
}
return JS_TRUE;
return ok;
}
#if JS_HAS_DESTRUCTURING
@ -1862,7 +2018,7 @@ BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn,
pn->pn_op = (data->op == JSOP_DEFCONST)
? JSOP_SETCONST
: JSOP_SETNAME;
pn->pn_const = (data->u.var.kind == JSLOCAL_CONST);
pn->pn_attrs = data->u.var.attrs;
return JS_TRUE;
}
@ -3612,16 +3768,20 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
data.u.var.clasp = OBJ_GET_CLASS(cx, data.obj);
if (data.u.var.fun && data.u.var.clasp == &js_FunctionClass) {
/* We are compiling code inside a function */
data.u.var.kind = (data.op == JSOP_DEFCONST)
? JSLOCAL_CONST
: JSLOCAL_VAR;
data.u.var.getter = js_GetLocalVariable;
data.u.var.setter = js_SetLocalVariable;
} else if (data.u.var.fun && data.u.var.clasp == &js_CallClass) {
/* We are compiling code from an eval inside a function */
data.u.var.getter = js_GetCallVariable;
data.u.var.setter = js_SetCallVariable;
} else {
/*
* We are compiling global code or code from an eval inside a
* function
*/
data.u.var.kind = JSLOCAL_NONE;
data.u.var.getter = data.u.var.clasp->getProperty;
data.u.var.setter = data.u.var.clasp->setProperty;
}
data.u.var.attrs = (data.op == JSOP_DEFCONST)
? JSPROP_PERMANENT | JSPROP_READONLY
: JSPROP_PERMANENT;
}
do {
@ -3674,7 +3834,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn2->pn_atom = atom;
pn2->pn_slot = -1;
if (!let)
pn2->pn_const = (data.u.var.kind == JSLOCAL_CONST);
pn2->pn_attrs = data.u.var.attrs;
PN_APPEND(pn, pn2);
if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
@ -4385,10 +4545,11 @@ GeneratorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
* Make the generator function and flag it as interpreted ASAP (see the
* comment in FunctionBody).
*/
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
cx->fp->varobj, NULL);
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA, cx->fp->varobj,
NULL);
if (!fun)
return NULL;
fun->flags |= JSFUN_INTERPRETED;
/*
* This generator function is referenced by an anonymous function object

View File

@ -186,7 +186,7 @@ JS_BEGIN_EXTERN_C
* TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
* JSOP_REGEXP
* TOK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
* with pn_slot >= 0 and pn_const telling const-ness
* with pn_slot >= 0 and pn_attrs telling const-ness
* TOK_NUMBER dval pn_dval: double value of numeric literal
* TOK_PRIMARY nullary pn_op: JSOp bytecode
*
@ -306,7 +306,7 @@ struct JSParseNode {
JSAtom *atom; /* name or label atom, null if slot */
JSParseNode *expr; /* object or initializer */
jsint slot; /* -1 or arg or local var slot */
JSBool constslot; /* true for const names */
uintN attrs; /* attributes if local var or const */
} name;
struct { /* lexical scope. */
JSParsedObjectBox *pob; /* block object */
@ -345,7 +345,7 @@ struct JSParseNode {
#define pn_atom pn_u.name.atom
#define pn_expr pn_u.name.expr
#define pn_slot pn_u.name.slot
#define pn_const pn_u.name.constslot
#define pn_attrs pn_u.name.attrs
#define pn_dval pn_u.dval
#define pn_atom2 pn_u.apair.atom2
#define pn_pob pn_u.object.pob

View File

@ -89,11 +89,6 @@
(JS_ASSERT(JSID_IS_HIDDEN(id)), \
(jsid)((jsval)(id) ^ (JSVAL_BOOLEAN ^ JSVAL_STRING)))
/*
* Convenience constants.
*/
#define JS_BITS_PER_UINT32 (sizeof(uint32) * JS_BITS_PER_BYTE)
/* Scalar typedefs. */
typedef uint8 jsbytecode;
typedef uint8 jssrcnote;

View File

@ -388,7 +388,7 @@ ChangeScope(JSContext *cx, JSScope *scope, int change)
* the GC, or we are searching for a property that has not yet been flagged as
* a duplicate when making a duplicate formal parameter.
*/
#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_ALLOW_DUPLICATE)
#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_IS_DUPLICATE)
JS_STATIC_DLL_CALLBACK(JSDHashNumber)
js_HashScopeProperty(JSDHashTable *table, const void *key)
@ -955,7 +955,7 @@ CheckAncestorLine(JSScope *scope, JSBool sparse)
for (sprop = ancestorLine; sprop; sprop = sprop->parent) {
if (SCOPE_HAD_MIDDLE_DELETE(scope) &&
!SCOPE_HAS_PROPERTY(scope, sprop)) {
JS_ASSERT(sparse || (sprop->flags & SPROP_ALLOW_DUPLICATE));
JS_ASSERT(sparse || (sprop->flags & SPROP_IS_DUPLICATE));
continue;
}
ancestorCount++;
@ -1066,12 +1066,12 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
* Duplicate formal parameters require us to leave the old property
* on the ancestor line, so the decompiler can find it, even though
* its entry in scope->table is overwritten to point at a new property
* descending from the old one. The SPROP_ALLOW_DUPLICATE flag helps
* us cope with the consequent disparity between ancestor line height
* and scope->entryCount.
* descending from the old one. The SPROP_IS_DUPLICATE flag helps us
* cope with the consequent disparity between ancestor line height and
* scope->entryCount.
*/
if (flags & SPROP_ALLOW_DUPLICATE) {
sprop->flags |= SPROP_ALLOW_DUPLICATE;
if (flags & SPROP_IS_DUPLICATE) {
sprop->flags |= SPROP_IS_DUPLICATE;
} else {
/*
* If we are clearing sprop to force an existing property to be
@ -1131,7 +1131,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
* all deleted properties out of scope's ancestor line. Otherwise we
* risk adding a node with the same id as a "middle" node, violating
* the rule that properties along an ancestor line have distinct ids
* (unless flagged SPROP_ALLOW_DUPLICATE).
* (unless flagged SPROP_IS_DUPLICATE).
*/
if (SCOPE_HAD_MIDDLE_DELETE(scope)) {
JS_ASSERT(scope->table);
@ -1274,7 +1274,7 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
child.setter = setter;
child.slot = slot;
child.attrs = attrs;
child.flags = flags & ~SPROP_ALLOW_DUPLICATE;
child.flags = flags;
child.shortid = shortid;
sprop = GetPropertyTreeChild(cx, scope->lastProp, &child);
if (!sprop)

View File

@ -288,9 +288,11 @@ struct JSScopeProperty {
/* Bits stored in sprop->flags. */
#define SPROP_MARK 0x01
#define SPROP_ALLOW_DUPLICATE 0x02
#define SPROP_IS_DUPLICATE 0x02
#define SPROP_IS_ALIAS 0x04
#define SPROP_HAS_SHORTID 0x08
#define SPROP_IS_HIDDEN 0x10 /* a normally-hidden property,
e.g., function arg or var */
/*
* If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather

View File

@ -1637,7 +1637,7 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
pc += js_CodeSpec[*pc].length;
if (*pc == JSOP_DEFFUN) {
GET_FUNCTION_FROM_BYTECODE(script, pc, 0, obj);
fun = GET_FUNCTION_PRIVATE(cx, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
JS_ASSERT(FUN_INTERPRETED(fun));
return fun->u.i.script->lineno;
}

View File

@ -202,7 +202,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file.
*/
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 16)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 15)
/*
* Library-private functions.

View File

@ -5585,7 +5585,6 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
{
JSXML *xml;
JSFunction *fun;
char numBuf[12];
JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp));
@ -5605,11 +5604,14 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
}
}
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp));
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(*vp));
if (fun) {
char numBuf[12];
JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_NON_LIST_XML_METHOD,
JS_GetFunctionName(fun), numBuf);
}
return NULL;
}