зеркало из https://github.com/mozilla/pjs.git
Bug 398609: simpler handling of hidden properties, r,a=brendan
This commit is contained in:
Родитель
66cd4cd530
Коммит
360615f7e6
|
@ -1239,7 +1239,7 @@ SrcNotes(JSContext *cx, JSScript *script)
|
|||
|
||||
index = js_GetSrcNoteOffset(sn, 0);
|
||||
JS_GET_SCRIPT_OBJECT(script, index, obj);
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = (JSFunction *) JS_GetPrivate(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);
|
||||
|
|
|
@ -4654,24 +4654,18 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, 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_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;
|
||||
}
|
||||
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)) {
|
||||
fun = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4707,7 +4701,7 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = JS_NEW_PRINTER(cx, name,
|
||||
jp = JS_NEW_PRINTER(cx, name, NULL,
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
|
@ -4727,12 +4721,12 @@ JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction",
|
||||
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction", fun,
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
return NULL;
|
||||
if (js_DecompileFunction(jp, fun))
|
||||
if (js_DecompileFunction(jp))
|
||||
str = js_GetPrinterOutput(jp);
|
||||
else
|
||||
str = NULL;
|
||||
|
@ -4747,12 +4741,12 @@ JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
|
|||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody",
|
||||
jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody", fun,
|
||||
indent & ~JS_DONT_PRETTY_PRINT,
|
||||
!(indent & JS_DONT_PRETTY_PRINT));
|
||||
if (!jp)
|
||||
return NULL;
|
||||
if (js_DecompileFunctionBody(jp, fun))
|
||||
if (js_DecompileFunctionBody(jp))
|
||||
str = js_GetPrinterOutput(jp);
|
||||
else
|
||||
str = NULL;
|
||||
|
|
|
@ -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 = (JSFunction *) OBJ_GET_PRIVATE(cx, closure);
|
||||
fun = GET_FUNCTION_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 = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj);
|
||||
wrapper = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
userid = ATOM_KEY(wrapper->atom);
|
||||
*rval = argv[0];
|
||||
return js_watch_set(cx, obj, userid, rval);
|
||||
|
@ -1326,9 +1326,12 @@ 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)
|
||||
| ((getter == js_GetArgument) ? JSPD_ARGUMENT : 0)
|
||||
| ((getter == js_GetLocalVariable) ? JSPD_VARIABLE : 0);
|
||||
| ((getter == js_GetCallVariable) ? JSPD_VARIABLE : 0);
|
||||
if (JSID_IS_HIDDEN(sprop->id)) {
|
||||
pd->flags |= (getter == JS_HIDDEN_ARG_GETTER)
|
||||
? JSPD_ARGUMENT
|
||||
: JSPD_VARIABLE;
|
||||
}
|
||||
|
||||
/* for Call Object 'real' getter isn't passed in to us */
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass &&
|
||||
|
|
287
js/src/jsemit.c
287
js/src/jsemit.c
|
@ -1235,8 +1235,7 @@ js_IsGlobalReference(JSTreeContext *tc, JSAtom *atom, JSBool *loopyp)
|
|||
continue;
|
||||
}
|
||||
if (stmt->flags & SIF_SCOPE) {
|
||||
JS_ASSERT(LOCKED_OBJ_GET_CLASS(stmt->u.blockObj) ==
|
||||
&js_BlockClass);
|
||||
JS_ASSERT(STOBJ_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;
|
||||
|
@ -1648,26 +1647,10 @@ 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) {
|
||||
ok = js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),
|
||||
&pobj, &prop);
|
||||
if (!ok)
|
||||
JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, obj));
|
||||
if (js_LookupLocal(cx, fp->fun, atom, NULL) != JSLOCAL_NONE)
|
||||
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);
|
||||
|
@ -1837,7 +1820,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_attrs will contain the property's attributes after a
|
||||
* variable name, pn->pn_const will be true for const properties after a
|
||||
* successful return.
|
||||
*
|
||||
* NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
|
||||
|
@ -1853,14 +1836,10 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
jsint slot;
|
||||
JSOp op;
|
||||
JSStackFrame *fp;
|
||||
JSObject *obj, *pobj;
|
||||
JSClass *clasp;
|
||||
JSBool optimizeGlobals;
|
||||
JSPropertyOp getter;
|
||||
uintN attrs;
|
||||
JSLocalKind localKind;
|
||||
uintN index;
|
||||
JSAtomListElement *ale;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
|
||||
JS_ASSERT(pn->pn_type == TOK_NAME);
|
||||
if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS)
|
||||
|
@ -1924,42 +1903,32 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* We can't optimize if we're not compiling a function body, whether via
|
||||
* eval, or directly when compiling a function statement or expression.
|
||||
* We can't optimize if we are in an eval called inside a with statement.
|
||||
*/
|
||||
obj = fp->varobj;
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if (fp->scopeChain != fp->varobj)
|
||||
return JS_TRUE;
|
||||
|
||||
clasp = OBJ_GET_CLASS(cx, fp->varobj);
|
||||
if (clasp != &js_FunctionClass && clasp != &js_CallClass) {
|
||||
/* Check for an eval or debugger frame. */
|
||||
/*
|
||||
* We cannot optimize the name access when compiling with an eval or
|
||||
* debugger frame.
|
||||
*/
|
||||
if (fp->flags & JSFRAME_SPECIAL)
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
optimizeGlobals = (tc->globalUses >= 100 ||
|
||||
(tc->loopyGlobalUses &&
|
||||
tc->loopyGlobalUses >= tc->globalUses / 2));
|
||||
if (!optimizeGlobals)
|
||||
if (!(tc->globalUses >= 100 ||
|
||||
(tc->loopyGlobalUses &&
|
||||
tc->loopyGlobalUses >= tc->globalUses / 2))) {
|
||||
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,
|
||||
|
@ -1971,10 +1940,6 @@ 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);
|
||||
|
@ -1988,93 +1953,90 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (optimizeGlobals || getter) {
|
||||
if (optimizeGlobals) {
|
||||
switch (op) {
|
||||
case JSOP_NAME: op = JSOP_GETGVAR; break;
|
||||
case JSOP_SETNAME: op = JSOP_SETGVAR; break;
|
||||
case JSOP_SETCONST: /* NB: no change */ break;
|
||||
case JSOP_INCNAME: op = JSOP_INCGVAR; break;
|
||||
case JSOP_NAMEINC: op = JSOP_GVARINC; break;
|
||||
case JSOP_DECNAME: op = JSOP_DECGVAR; break;
|
||||
case JSOP_NAMEDEC: op = JSOP_GVARDEC; break;
|
||||
case JSOP_FORNAME: /* NB: no change */ break;
|
||||
case JSOP_DELNAME: /* NB: no change */ break;
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
} else if (getter == js_GetLocalVariable ||
|
||||
getter == js_GetCallVariable) {
|
||||
switch (op) {
|
||||
case JSOP_NAME: op = JSOP_GETVAR; break;
|
||||
case JSOP_SETNAME: op = JSOP_SETVAR; break;
|
||||
case JSOP_SETCONST: op = JSOP_SETVAR; break;
|
||||
case JSOP_INCNAME: op = JSOP_INCVAR; break;
|
||||
case JSOP_NAMEINC: op = JSOP_VARINC; break;
|
||||
case JSOP_DECNAME: op = JSOP_DECVAR; break;
|
||||
case JSOP_NAMEDEC: op = JSOP_VARDEC; break;
|
||||
case JSOP_FORNAME: op = JSOP_FORVAR; break;
|
||||
case JSOP_DELNAME: op = JSOP_FALSE; break;
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
op = PN_OP(pn);
|
||||
switch (op) {
|
||||
case JSOP_NAME: op = JSOP_GETGVAR; break;
|
||||
case JSOP_SETNAME: op = JSOP_SETGVAR; break;
|
||||
case JSOP_SETCONST: /* NB: no change */ break;
|
||||
case JSOP_INCNAME: op = JSOP_INCGVAR; break;
|
||||
case JSOP_NAMEINC: op = JSOP_GVARINC; break;
|
||||
case JSOP_DECNAME: op = JSOP_DECGVAR; break;
|
||||
case JSOP_NAMEDEC: op = JSOP_GVARDEC; break;
|
||||
case JSOP_FORNAME: /* NB: no change */ break;
|
||||
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;
|
||||
}
|
||||
pn->pn_attrs = attrs;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (pn->pn_slot < 0) {
|
||||
if (clasp == &js_FunctionClass) {
|
||||
/*
|
||||
* 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
|
||||
* object.
|
||||
* 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.
|
||||
*/
|
||||
if (pn->pn_op == JSOP_NAME &&
|
||||
atom == cx->runtime->atomState.argumentsAtom) {
|
||||
pn->pn_op = JSOP_ARGUMENTS;
|
||||
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);
|
||||
switch (op) {
|
||||
case JSOP_NAME: op = JSOP_GETVAR; break;
|
||||
case JSOP_SETNAME: op = JSOP_SETVAR; break;
|
||||
case JSOP_SETCONST: op = JSOP_SETVAR; break;
|
||||
case JSOP_INCNAME: op = JSOP_INCVAR; break;
|
||||
case JSOP_NAMEINC: op = JSOP_VARINC; break;
|
||||
case JSOP_DECNAME: op = JSOP_DECVAR; break;
|
||||
case JSOP_NAMEDEC: op = JSOP_VARDEC; break;
|
||||
case JSOP_FORNAME: op = JSOP_FORVAR; break;
|
||||
case JSOP_DELNAME: op = JSOP_FALSE; break;
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
pn->pn_const = (localKind == JSLOCAL_CONST);
|
||||
}
|
||||
pn->pn_op = op;
|
||||
pn->pn_slot = index;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
tc->flags |= TCF_FUN_USES_NONLOCALS;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* object.
|
||||
*/
|
||||
if (pn->pn_op == JSOP_NAME &&
|
||||
atom == cx->runtime->atomState.argumentsAtom) {
|
||||
pn->pn_op = JSOP_ARGUMENTS;
|
||||
return JS_TRUE;
|
||||
}
|
||||
tc->flags |= TCF_FUN_USES_NONLOCALS;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2111,7 +2073,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
* name in that scope object. See comments at case JSOP_NAMEDFUNOBJ:
|
||||
* in jsinterp.c.
|
||||
*/
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
|
||||
if (fun->atom)
|
||||
*answer = JS_TRUE;
|
||||
break;
|
||||
|
@ -2172,7 +2134,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
if (!*answer &&
|
||||
(pn->pn_op != JSOP_NOP ||
|
||||
pn2->pn_slot < 0 ||
|
||||
!(pn2->pn_attrs & JSPROP_READONLY))) {
|
||||
!pn2->pn_const)) {
|
||||
*answer = JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -4035,7 +3997,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 = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
|
||||
if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -4088,31 +4050,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
if ((cg->treeContext.flags & TCF_IN_FUNCTION) ||
|
||||
((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun)) {
|
||||
JSObject *obj, *pobj;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
JSFunction *parentFun;
|
||||
JSLocalKind localKind;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (prop) {
|
||||
if (pobj == obj) {
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
if (sprop->getter == js_GetLocalVariable) {
|
||||
slot = sprop->shortid;
|
||||
op = JSOP_DEFLOCALFUN;
|
||||
}
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
}
|
||||
|
||||
JS_ASSERT(op == JSOP_DEFLOCALFUN ||
|
||||
!(cg->treeContext.flags & TCF_IN_FUNCTION));
|
||||
localKind = js_LookupLocal(cx, parentFun, fun->atom, &slot);
|
||||
if (localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST)
|
||||
op = JSOP_DEFLOCALFUN;
|
||||
else
|
||||
JS_ASSERT(!(cg->treeContext.flags & TCF_IN_FUNCTION));
|
||||
|
||||
/*
|
||||
* If this local function is declared in a body block induced
|
||||
|
@ -4124,9 +4077,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)) {
|
||||
obj = stmt->down->u.blockObj;
|
||||
JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
|
||||
OBJ_SET_PARENT(cx, fun->object, obj);
|
||||
JS_ASSERT(STOBJ_GET_CLASS(stmt->down->u.blockObj) ==
|
||||
&js_BlockClass);
|
||||
OBJ_SET_PARENT(cx, fun->object, stmt->down->u.blockObj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4484,7 +4437,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
op = PN_OP(pn3);
|
||||
}
|
||||
if (pn3->pn_slot >= 0) {
|
||||
if (pn3->pn_attrs & JSPROP_READONLY) {
|
||||
if (pn3->pn_const) {
|
||||
JS_ASSERT(op == JSOP_FORVAR);
|
||||
op = JSOP_FORCONST;
|
||||
}
|
||||
|
@ -5486,12 +5439,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 JSPROP_READONLY in pn_attrs), as in this case (just a bit
|
||||
* further below) we will avoid emitting the assignment op.
|
||||
* and when pn_const is true), 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_attrs & JSPROP_READONLY)) {
|
||||
!pn2->pn_const) {
|
||||
if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -5512,7 +5465,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_attrs & JSPROP_READONLY)) {
|
||||
if (pn2->pn_slot < 0 || !pn2->pn_const) {
|
||||
if (pn2->pn_slot >= 0) {
|
||||
EMIT_UINT16_IMM_OP(PN_OP(pn2), atomIndex);
|
||||
} else {
|
||||
|
@ -5757,7 +5710,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
op = PN_OP(pn2);
|
||||
if (pn2->pn_slot >= 0) {
|
||||
if (pn2->pn_attrs & JSPROP_READONLY) {
|
||||
if (pn2->pn_const) {
|
||||
/* Incrementing a declared const: just get its value. */
|
||||
op = ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_ATOM)
|
||||
? JSOP_GETGVAR
|
||||
|
|
625
js/src/jsfun.c
625
js/src/jsfun.c
|
@ -722,9 +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) {
|
||||
/* 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)];
|
||||
JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
|
||||
*vp = fp->vars[JSVAL_TO_INT(id)];
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -737,10 +736,8 @@ js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|||
JS_ASSERT(JSVAL_IS_INT(id));
|
||||
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
||||
if (fp) {
|
||||
/* 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;
|
||||
JS_ASSERT((uintN) JSVAL_TO_INT(id) < fp->nvars);
|
||||
fp->vars[JSVAL_TO_INT(id)] = *vp;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -752,7 +749,6 @@ call_enumerate(JSContext *cx, JSObject *obj)
|
|||
JSObject *funobj, *pobj;
|
||||
JSScope *scope;
|
||||
JSScopeProperty *sprop, *cprop;
|
||||
JSPropertyOp getter;
|
||||
jsval *vec;
|
||||
jsid id;
|
||||
JSProperty *prop;
|
||||
|
@ -784,13 +780,9 @@ call_enumerate(JSContext *cx, JSObject *obj)
|
|||
*/
|
||||
scope = OBJ_SCOPE(funobj);
|
||||
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
||||
getter = sprop->getter;
|
||||
if (getter == js_GetArgument)
|
||||
vec = fp->argv;
|
||||
else if (getter == js_GetLocalVariable)
|
||||
vec = fp->vars;
|
||||
else
|
||||
if (!JSID_IS_HIDDEN(sprop->id))
|
||||
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);
|
||||
|
@ -821,16 +813,12 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
JSObject **objp)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
JSObject *funobj;
|
||||
JSString *str;
|
||||
JSAtom *atom;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
JSLocalKind localKind;
|
||||
JSPropertyOp getter, setter;
|
||||
uintN attrs, slot, nslots, spflags;
|
||||
jsval *vp, value;
|
||||
intN shortid;
|
||||
uintN slot, attrs;
|
||||
jsval *vp;
|
||||
|
||||
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
||||
if (!fp)
|
||||
|
@ -840,61 +828,39 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
if (!JSVAL_IS_STRING(id))
|
||||
return JS_TRUE;
|
||||
|
||||
funobj = fp->callee;
|
||||
if (!funobj)
|
||||
if (!fp->callee)
|
||||
return JS_TRUE;
|
||||
JS_ASSERT((JSFunction *) OBJ_GET_PRIVATE(cx, funobj) == fp->fun);
|
||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == 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;
|
||||
|
||||
if (prop) {
|
||||
if (!OBJ_IS_NATIVE(obj2)) {
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
return JS_TRUE;
|
||||
localKind = js_LookupLocal(cx, fp->fun, atom, &slot);
|
||||
if (localKind != JSLOCAL_NONE) {
|
||||
if (localKind == JSLOCAL_ARG) {
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
vp = fp->argv;
|
||||
getter = setter = NULL;
|
||||
attrs = JSPROP_PERMANENT;
|
||||
} else {
|
||||
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
|
||||
JS_ASSERT(fp->fun->u.i.nvars == fp->nvars);
|
||||
JS_ASSERT(slot < fp->nvars);
|
||||
vp = fp->vars;
|
||||
getter = js_GetCallVariable;
|
||||
setter = js_SetCallVariable;
|
||||
attrs = (localKind == JSLOCAL_CONST)
|
||||
? JSPROP_PERMANENT | JSPROP_READONLY
|
||||
: JSPROP_PERMANENT;
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
JS_ASSERT(getter == js_GetLocalVariable);
|
||||
vp = fp->vars;
|
||||
nslots = fp->nvars;
|
||||
getter = js_GetCallVariable;
|
||||
setter = js_SetCallVariable;
|
||||
}
|
||||
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, shortid, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), vp[slot],
|
||||
getter, setter, attrs,
|
||||
SPROP_HAS_SHORTID, (int) slot, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1106,39 +1072,20 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
if (!JSVAL_IS_STRING(id))
|
||||
return JS_TRUE;
|
||||
|
||||
/* No valid function object should lack private data. */
|
||||
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
|
||||
JS_ASSERT(fun && fun->object);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
JS_ASSERT(fun->object);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
if (flags & JSRESOLVE_ASSIGNING)
|
||||
return JS_TRUE;
|
||||
|
@ -1245,12 +1192,6 @@ 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)
|
||||
|
@ -1258,29 +1199,15 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||
JSContext *cx;
|
||||
JSFunction *fun;
|
||||
uint32 nullAtom; /* flag to indicate if fun->atom is NULL */
|
||||
JSTempValueRooter tvr;
|
||||
uintN nargs, nvars, n;
|
||||
uint32 localsword; /* word to xdr argument and variable counts */
|
||||
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;
|
||||
JSTempValueRooter tvr;
|
||||
JSBool ok;
|
||||
#ifdef DEBUG
|
||||
uintN nvars = 0, nargs = 0;
|
||||
#endif
|
||||
|
||||
cx = xdr->cx;
|
||||
if (xdr->mode == JSXDR_ENCODE) {
|
||||
/*
|
||||
* 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;
|
||||
fun = GET_FUNCTION_PRIVATE(cx, *objp);
|
||||
if (!FUN_INTERPRETED(fun)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_NOT_SCRIPTED_FUNCTION,
|
||||
|
@ -1288,12 +1215,17 @@ 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, 0, NULL, NULL);
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, 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. */
|
||||
|
@ -1304,128 +1236,96 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
|
|||
goto bad;
|
||||
if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))
|
||||
goto bad;
|
||||
|
||||
if (!JS_XDRUint16(xdr, &fun->nargs) ||
|
||||
!JS_XDRUint16(xdr, &extraUnused) ||
|
||||
!JS_XDRUint16(xdr, &fun->u.i.nvars) ||
|
||||
if (!JS_XDRUint32(xdr, &localsword) ||
|
||||
!JS_XDRUint32(xdr, &flagsword)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Assert that all previous writes of extraUnused were writes of 0. */
|
||||
JS_ASSERT(extraUnused == 0);
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
nargs = localsword >> 16;
|
||||
nvars = localsword & JS_BITMASK(16);
|
||||
JS_ASSERT(flagsword | JSFUN_INTERPRETED);
|
||||
fun->flags = (uint16) flagsword;
|
||||
}
|
||||
|
||||
/* do arguments and local vars */
|
||||
if (fun->object) {
|
||||
n = fun->nargs + fun->u.i.nvars;
|
||||
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 (xdr->mode == JSXDR_ENCODE) {
|
||||
JSScope *scope;
|
||||
JSScopeProperty **spvec, *auto_spvec[8];
|
||||
void *mark;
|
||||
|
||||
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;
|
||||
}
|
||||
names = js_GetLocalNames(xdr->cx, fun, &xdr->cx->tempPool, &bitmap);
|
||||
if (!names) {
|
||||
ok = JS_FALSE;
|
||||
goto release_mark;
|
||||
}
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
|
||||
release_mark:
|
||||
JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1480,6 +1380,7 @@ 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");
|
||||
|
@ -1490,6 +1391,11 @@ 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)
|
||||
|
@ -1552,7 +1458,7 @@ fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
|
|||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(JS_ObjectIsFunction(cx, obj));
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
if (!fun)
|
||||
return JS_TRUE;
|
||||
str = JS_DecompileFunction(cx, fun, (uintN)indent);
|
||||
|
@ -1792,12 +1698,10 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
JSStackFrame *fp, *caller;
|
||||
JSFunction *fun;
|
||||
JSObject *parent;
|
||||
uintN i, n, lineno, dupflag;
|
||||
uintN i, n, lineno;
|
||||
JSAtom *atom;
|
||||
const char *filename;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
JSBool ok;
|
||||
JSString *str, *arg;
|
||||
JSParseContext pc;
|
||||
JSPrincipals *principals;
|
||||
|
@ -1805,7 +1709,6 @@ 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)) {
|
||||
|
@ -1814,6 +1717,11 @@ 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;
|
||||
|
@ -1830,8 +1738,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, parent,
|
||||
cx->runtime->atomState.anonymousAtom);
|
||||
fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
|
||||
parent, cx->runtime->atomState.anonymousAtom);
|
||||
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
|
@ -1955,54 +1863,23 @@ 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);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
NULL,
|
||||
JSREPORT_WARNING |
|
||||
JSREPORT_STRICT,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
name);
|
||||
/* Check for a duplicate parameter name. */
|
||||
if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
const char *name;
|
||||
|
||||
dupflag = SPROP_IS_DUPLICATE;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
ok = name &&
|
||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL,
|
||||
JSREPORT_WARNING |
|
||||
JSREPORT_STRICT,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
name);
|
||||
if (!ok)
|
||||
goto after_args;
|
||||
sprop = NULL;
|
||||
}
|
||||
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)) {
|
||||
if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG))
|
||||
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
|
||||
|
@ -2067,14 +1944,13 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
|
|||
0);
|
||||
if (!atom)
|
||||
goto bad;
|
||||
fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);
|
||||
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, 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:
|
||||
|
@ -2130,10 +2006,18 @@ 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;
|
||||
fun->u.n.native = native;
|
||||
fun->u.n.extra = 0;
|
||||
fun->u.n.minargs = 0;
|
||||
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->u.n.native = native;
|
||||
fun->u.n.extra = 0;
|
||||
fun->u.n.minargs = 0;
|
||||
}
|
||||
fun->atom = atom;
|
||||
fun->clasp = NULL;
|
||||
|
||||
|
@ -2180,7 +2064,7 @@ js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
|||
newfunobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
|
||||
if (!newfunobj)
|
||||
return NULL;
|
||||
fun = (JSFunction *) JS_GetPrivate(cx, funobj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
|
||||
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
|
||||
return NULL;
|
||||
|
@ -2238,7 +2122,7 @@ js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
|
|||
js_ReportIsNotFunction(cx, vp, flags);
|
||||
return NULL;
|
||||
}
|
||||
return (JSFunction *) JS_GetPrivate(cx, obj);
|
||||
return GET_FUNCTION_PRIVATE(cx, obj);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -2324,3 +2208,170 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,14 @@ 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);
|
||||
|
||||
|
@ -175,6 +183,49 @@ 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___ */
|
||||
|
|
|
@ -388,30 +388,6 @@ 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)
|
||||
{
|
||||
|
@ -916,7 +892,7 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
|
|||
key.lineno = 0;
|
||||
name = "";
|
||||
if (VALUE_IS_FUNCTION(cx, callee)) {
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
|
||||
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee));
|
||||
if (fun->atom)
|
||||
name = js_AtomToPrintableString(cx, fun->atom);
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
|
@ -1006,8 +982,8 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
|
|||
break;
|
||||
case JSTYPE_FUNCTION:
|
||||
if (VALUE_IS_FUNCTION(cx, argval)) {
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(argval));
|
||||
if (fun && fun->atom) {
|
||||
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(argval));
|
||||
if (fun->atom) {
|
||||
str = ATOM_TO_STRING(fun->atom);
|
||||
break;
|
||||
}
|
||||
|
@ -1173,7 +1149,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
|
|||
} else {
|
||||
have_fun:
|
||||
/* Get private data and set derived locals from it. */
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
nslots = FUN_MINARGS(fun);
|
||||
nslots = (nslots > argc) ? nslots - argc : 0;
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
|
@ -1517,8 +1493,7 @@ 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((JSFunction *)
|
||||
JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval))) &&
|
||||
FUN_INTERPRETED(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval))) &&
|
||||
!cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
|
||||
&fval)) {
|
||||
return JS_FALSE;
|
||||
|
@ -1938,7 +1913,7 @@ js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
|
|||
parent = OBJ_GET_PARENT(cx, obj2);
|
||||
|
||||
if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
|
||||
funclasp = ((JSFunction *) OBJ_GET_PRIVATE(cx, obj2))->clasp;
|
||||
funclasp = GET_FUNCTION_PRIVATE(cx, obj2)->clasp;
|
||||
if (funclasp)
|
||||
clasp = funclasp;
|
||||
}
|
||||
|
@ -3912,9 +3887,9 @@ interrupt:
|
|||
SAVE_SP_AND_PC(fp);
|
||||
if (VALUE_IS_FUNCTION(cx, lval)) {
|
||||
obj = JSVAL_TO_OBJECT(lval);
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
|
||||
if (fun->flags & JSFUN_INTERPRETED) {
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
uintN nframeslots, nvars, nslots, missing;
|
||||
JSArena *a;
|
||||
jsuword avail, nbytes;
|
||||
|
@ -4876,7 +4851,7 @@ interrupt:
|
|||
|
||||
BEGIN_CASE(JSOP_DEFFUN)
|
||||
LOAD_FUNCTION(0);
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
id = ATOM_TO_JSID(fun->atom);
|
||||
|
||||
/*
|
||||
|
@ -5117,7 +5092,7 @@ interrupt:
|
|||
* name is [fun->atom, the identifier parsed by the compiler],
|
||||
* value is Result(3), and attributes are { DontDelete, ReadOnly }.
|
||||
*/
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
attrs = JSFUN_GSFLAG2ATTR(fun->flags);
|
||||
if (attrs) {
|
||||
attrs |= JSPROP_SHARED;
|
||||
|
@ -5191,7 +5166,7 @@ interrupt:
|
|||
* unless fun is a getter or setter (in which case, obj is cast to
|
||||
* a JSPropertyOp and passed accordingly).
|
||||
*/
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
attrs = JSFUN_GSFLAG2ATTR(fun->flags);
|
||||
if (attrs) {
|
||||
attrs |= JSPROP_SHARED;
|
||||
|
@ -5870,7 +5845,7 @@ interrupt:
|
|||
/* Wrap primitive lval in object clothing if necessary. */
|
||||
if (!VALUE_IS_FUNCTION(cx, rval) ||
|
||||
(obj = JSVAL_TO_OBJECT(rval),
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj),
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj),
|
||||
!PRIMITIVE_THIS_TEST(fun, lval))) {
|
||||
ok = js_PrimitiveToObject(cx, &sp[-1]);
|
||||
if (!ok)
|
||||
|
|
|
@ -120,18 +120,6 @@ 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)
|
||||
|
||||
|
|
|
@ -2995,26 +2995,6 @@ 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,
|
||||
|
|
|
@ -174,7 +174,7 @@ struct JSObject {
|
|||
|
||||
#define STOBJ_SET_SYSTEM(obj) ((void)((obj)->fslots[JSSLOT_CLASS] |= 2))
|
||||
|
||||
#define STOBJ_GET_PRIVATE(obj) \
|
||||
#define STOBJ_GET_PRIVATE(obj) \
|
||||
(JS_ASSERT(JSVAL_IS_INT(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))), \
|
||||
JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE)))
|
||||
|
||||
|
@ -443,21 +443,6 @@ 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.
|
||||
|
@ -507,15 +492,11 @@ 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);
|
||||
|
@ -644,6 +625,7 @@ 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___ */
|
||||
|
|
|
@ -649,7 +649,8 @@ struct JSPrinter {
|
|||
JSPackedBool grouped; /* in parenthesized expression context */
|
||||
JSScript *script; /* script being printed */
|
||||
jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */
|
||||
JSObject *object; /* interpreted function object */
|
||||
JSFunction *fun; /* interpreted function */
|
||||
JSAtom **localNames; /* argument and variable names */
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
JSBraceState braceState; /* remove braces around let declaration */
|
||||
ptrdiff_t spaceOffset; /* -1 or offset of space before maybe-{ */
|
||||
|
@ -665,7 +666,8 @@ struct JSPrinter {
|
|||
#define JS_IN_GROUP_CONTEXT 0x10000
|
||||
|
||||
JSPrinter *
|
||||
JS_NEW_PRINTER(JSContext *cx, const char *name, uintN indent, JSBool pretty)
|
||||
JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
|
||||
uintN indent, JSBool pretty)
|
||||
{
|
||||
JSPrinter *jp;
|
||||
|
||||
|
@ -679,11 +681,20 @@ JS_NEW_PRINTER(JSContext *cx, const char *name, uintN indent, JSBool pretty)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -1206,50 +1217,35 @@ 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)
|
||||
{
|
||||
|
@ -1362,14 +1358,14 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
|
|||
i = GET_UINT16(pc);
|
||||
atom = NULL;
|
||||
lval = NULL;
|
||||
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)
|
||||
if (op == JSOP_SETARG || op == JSOP_SETVAR) {
|
||||
atom = GetSlotAtom(jp, op == JSOP_SETARG, i);
|
||||
LOCAL_ASSERT(atom);
|
||||
} 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);
|
||||
|
@ -2085,22 +2081,19 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
JS_GET_SCRIPT_OBJECT(jp->script, js_GetSrcNoteOffset(sn, 0),
|
||||
obj);
|
||||
do_function:
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
jp2 = JS_NEW_PRINTER(cx, "nested_function",
|
||||
js_puts(jp, "\n");
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
jp2 = JS_NEW_PRINTER(cx, "nested_function", fun,
|
||||
jp->indent, jp->pretty);
|
||||
if (!jp2)
|
||||
return NULL;
|
||||
jp2->object = jp->object;
|
||||
js_puts(jp2, "\n");
|
||||
ok = js_DecompileFunction(jp2, fun);
|
||||
if (ok && jp2->sprinter.base) {
|
||||
ok = js_DecompileFunction(jp2);
|
||||
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");
|
||||
js_puts(jp, "\n\n");
|
||||
break;
|
||||
|
||||
case SRC_BRACE:
|
||||
|
@ -2742,9 +2735,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
break;
|
||||
|
||||
case JSOP_RETURN:
|
||||
obj = jp->object;
|
||||
LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass);
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
LOCAL_ASSERT(jp->fun);
|
||||
fun = jp->fun;
|
||||
if (fun->flags & JSFUN_EXPR_CLOSURE) {
|
||||
rval = POP_STR();
|
||||
js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format,
|
||||
|
@ -3085,13 +3077,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
goto do_logical_connective;
|
||||
|
||||
case JSOP_FORARG:
|
||||
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_fornameinloop;
|
||||
|
||||
case JSOP_FORVAR:
|
||||
case JSOP_FORCONST:
|
||||
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_fornameinloop;
|
||||
|
||||
|
@ -3321,12 +3313,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
break;
|
||||
|
||||
case JSOP_SETARG:
|
||||
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_setname;
|
||||
|
||||
case JSOP_SETVAR:
|
||||
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_setname;
|
||||
|
||||
|
@ -3501,13 +3493,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
|
||||
case JSOP_INCARG:
|
||||
case JSOP_DECARG:
|
||||
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_incatom;
|
||||
|
||||
case JSOP_INCVAR:
|
||||
case JSOP_DECVAR:
|
||||
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_incatom;
|
||||
|
||||
|
@ -3563,13 +3555,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
|
||||
case JSOP_ARGINC:
|
||||
case JSOP_ARGDEC:
|
||||
atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_TRUE, GET_ARGNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_atominc;
|
||||
|
||||
case JSOP_VARINC:
|
||||
case JSOP_VARDEC:
|
||||
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_atominc;
|
||||
|
||||
|
@ -3646,12 +3638,13 @@ 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)
|
||||
if (!PushSlotAtom(ss, js_GetLocalVariable, GET_VARNO(pc), op))
|
||||
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))
|
||||
return NULL;
|
||||
goto do_getprop;
|
||||
|
||||
|
@ -3752,7 +3745,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
case JSOP_CALLARG:
|
||||
case JSOP_GETARG:
|
||||
i = GET_ARGNO(pc);
|
||||
atom = GetSlotAtom(jp, js_GetArgument, i);
|
||||
atom = GetSlotAtom(jp, JS_TRUE, i);
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (!atom) {
|
||||
todo = Sprint(&ss->sprinter, "%s[%d]", js_arguments_str, i);
|
||||
|
@ -3765,7 +3758,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
|
||||
case JSOP_CALLVAR:
|
||||
case JSOP_GETVAR:
|
||||
atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));
|
||||
atom = GetSlotAtom(jp, JS_FALSE, GET_VARNO(pc));
|
||||
LOCAL_ASSERT(atom);
|
||||
goto do_name;
|
||||
|
||||
|
@ -3828,7 +3821,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
SprintStack ss2;
|
||||
|
||||
LOAD_FUNCTION(0);
|
||||
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
LOCAL_ASSERT(FUN_INTERPRETED(fun));
|
||||
inner = fun->u.i.script;
|
||||
|
||||
|
@ -3944,7 +3937,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 = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
if (!(fun->flags & JSFUN_EXPR_CLOSURE))
|
||||
indent |= JS_IN_GROUP_CONTEXT;
|
||||
str = JS_DecompileFunction(cx, fun, indent);
|
||||
|
@ -4691,37 +4684,35 @@ js_DecompileScript(JSPrinter *jp, JSScript *script)
|
|||
static const char native_code_str[] = "\t[native code]\n";
|
||||
|
||||
JSBool
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun)
|
||||
js_DecompileFunctionBody(JSPrinter *jp)
|
||||
{
|
||||
JSScript *script;
|
||||
JSObject *oldobject;
|
||||
JSBool ok;
|
||||
|
||||
if (!FUN_INTERPRETED(fun)) {
|
||||
JS_ASSERT(jp->fun);
|
||||
JS_ASSERT(!jp->script);
|
||||
if (!FUN_INTERPRETED(jp->fun)) {
|
||||
js_printf(jp, native_code_str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
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;
|
||||
|
||||
script = jp->fun->u.i.script;
|
||||
return js_DecompileCode(jp, script, script->code, (uintN)script->length, 0);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
||||
js_DecompileFunction(JSPrinter *jp)
|
||||
{
|
||||
JSContext *cx;
|
||||
uintN i, nargs, indent;
|
||||
void *mark;
|
||||
JSAtom **params;
|
||||
JSObject *oldobject;
|
||||
JSScopeProperty *sprop;
|
||||
JSFunction *fun;
|
||||
uintN i;
|
||||
JSAtom *param;
|
||||
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
|
||||
|
@ -4743,45 +4734,19 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
|||
return JS_FALSE;
|
||||
js_puts(jp, "(");
|
||||
|
||||
if (FUN_INTERPRETED(fun) && fun->object) {
|
||||
size_t paramsize;
|
||||
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 {
|
||||
#ifdef JS_HAS_DESTRUCTURING
|
||||
SprintStack ss;
|
||||
JSScript *oldscript;
|
||||
void *mark;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
/* Print the parameters. */
|
||||
pc = fun->u.i.script->main;
|
||||
endpc = pc + fun->u.i.script->length;
|
||||
ok = JS_TRUE;
|
||||
|
@ -4792,20 +4757,20 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
|||
pc += JSOP_GENERATOR_LENGTH;
|
||||
|
||||
ss.printer = NULL;
|
||||
oldscript = jp->script;
|
||||
jp->script = fun->u.i.script;
|
||||
oldobject = jp->object;
|
||||
jp->object = fun->object;
|
||||
mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < nargs; i++) {
|
||||
for (i = 0; i < fun->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 (!params[i]) {
|
||||
if (!param) {
|
||||
ptrdiff_t todo;
|
||||
const char *lval;
|
||||
|
||||
|
@ -4813,7 +4778,8 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
|||
pc += JSOP_GETARG_LENGTH;
|
||||
LOCAL_ASSERT(*pc == JSOP_DUP);
|
||||
if (!ss.printer) {
|
||||
ok = InitSprintStack(cx, &ss, jp, fun->u.i.script->depth);
|
||||
ok = InitSprintStack(jp->sprinter.context, &ss, jp,
|
||||
fun->u.i.script->depth);
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
|
@ -4836,56 +4802,39 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
|
|||
#undef LOCAL_ASSERT
|
||||
#endif
|
||||
|
||||
if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(params[i]), 0)) {
|
||||
if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(param), 0)) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JS_HAS_DESTRUCTURING
|
||||
jp->script = oldscript;
|
||||
jp->object = oldobject;
|
||||
jp->script = NULL;
|
||||
JS_ARENA_RELEASE(&jp->sprinter.context->tempPool, mark);
|
||||
#endif
|
||||
JS_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
#ifdef __GNUC__
|
||||
} else {
|
||||
pc = NULL;
|
||||
#endif
|
||||
}
|
||||
if (fun->flags & JSFUN_EXPR_CLOSURE) {
|
||||
js_printf(jp, ") ");
|
||||
} else {
|
||||
js_printf(jp, ") {\n");
|
||||
jp->indent += 4;
|
||||
}
|
||||
|
||||
indent = jp->indent;
|
||||
if (fun->flags & JSFUN_EXPR_CLOSURE) {
|
||||
js_printf(jp, ") ");
|
||||
} else {
|
||||
js_printf(jp, ") {\n");
|
||||
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);
|
||||
jp->object = oldobject;
|
||||
if (!ok) {
|
||||
jp->indent = indent;
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!(fun->flags & JSFUN_EXPR_CLOSURE)) {
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t}");
|
||||
}
|
||||
} 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))
|
||||
js_puts(jp, ")");
|
||||
|
||||
if (!jp->pretty) {
|
||||
if (!jp->grouped && (fun->flags & JSFUN_LAMBDA))
|
||||
js_puts(jp, ")");
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -5213,12 +5162,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||
}
|
||||
|
||||
name = NULL;
|
||||
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", 0, JS_FALSE);
|
||||
jp = JS_NEW_PRINTER(cx, "js_DecompileValueGenerator", fp->fun, 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 *) "";
|
||||
|
|
|
@ -273,15 +273,16 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote);
|
|||
*/
|
||||
|
||||
#ifdef JS_ARENAMETER
|
||||
# define JS_NEW_PRINTER(cx, name, indent, pretty) \
|
||||
js_NewPrinter(cx, name, indent, pretty)
|
||||
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \
|
||||
js_NewPrinter(cx, name, fun, indent, pretty)
|
||||
#else
|
||||
# define JS_NEW_PRINTER(cx, name, indent, pretty) \
|
||||
js_NewPrinter(cx, indent, pretty)
|
||||
# define JS_NEW_PRINTER(cx, name, fun, indent, pretty) \
|
||||
js_NewPrinter(cx, fun, indent, pretty)
|
||||
#endif
|
||||
|
||||
extern JSPrinter *
|
||||
JS_NEW_PRINTER(JSContext *cx, const char *name, uintN indent, JSBool pretty);
|
||||
JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
|
||||
uintN indent, JSBool pretty);
|
||||
|
||||
extern void
|
||||
js_DestroyPrinter(JSPrinter *jp);
|
||||
|
@ -355,10 +356,10 @@ extern JSBool
|
|||
js_DecompileScript(JSPrinter *jp, JSScript *script);
|
||||
|
||||
extern JSBool
|
||||
js_DecompileFunctionBody(JSPrinter *jp, JSFunction *fun);
|
||||
js_DecompileFunctionBody(JSPrinter *jp);
|
||||
|
||||
extern JSBool
|
||||
js_DecompileFunction(JSPrinter *jp, JSFunction *fun);
|
||||
js_DecompileFunction(JSPrinter *jp);
|
||||
|
||||
/*
|
||||
* Find the source expression that resulted in v, and return a newly allocated
|
||||
|
|
317
js/src/jsparse.c
317
js/src/jsparse.c
|
@ -807,6 +807,7 @@ 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 ||
|
||||
|
@ -821,12 +822,6 @@ 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;
|
||||
|
||||
|
@ -987,9 +982,7 @@ struct BindData {
|
|||
struct {
|
||||
JSFunction *fun; /* this overlays u.arg.fun */
|
||||
JSClass *clasp;
|
||||
JSPropertyOp getter;
|
||||
JSPropertyOp setter;
|
||||
uintN attrs;
|
||||
JSLocalKind kind;
|
||||
} var;
|
||||
struct {
|
||||
jsuint index;
|
||||
|
@ -998,81 +991,38 @@ struct BindData {
|
|||
} u;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
/*
|
||||
* Check for a duplicate parameter name, a "feature" required by ECMA-262.
|
||||
*/
|
||||
if (js_LookupLocal(cx, data->u.arg.fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
|
||||
/*
|
||||
* 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, TS(tc->parseContext), data->pn,
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
|
||||
JSREPORT_WARNING | JSREPORT_STRICT,
|
||||
JSMSG_DUPLICATE_FORMAL,
|
||||
name);
|
||||
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
if (!ok)
|
||||
name)) {
|
||||
return JS_FALSE;
|
||||
|
||||
dupflag = SPROP_IS_DUPLICATE;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return js_AddLocal(cx, data->u.arg.fun, atom, JSLOCAL_ARG);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
|
||||
{
|
||||
JSFunction *fun;
|
||||
|
||||
/*
|
||||
* Can't increase fun->nvars in an active frame, so insist that getter is
|
||||
* js_GetLocalVariable, not js_GetCallVariable or anything else.
|
||||
* Can't increase fun->nvars in an active frame when kind is JSFL_NONE.
|
||||
*/
|
||||
if (data->u.var.getter != js_GetLocalVariable)
|
||||
if (data->u.var.kind == JSLOCAL_NONE)
|
||||
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.
|
||||
|
@ -1083,21 +1033,7 @@ BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
|
|||
if (atom == cx->runtime->atomState.argumentsAtom)
|
||||
return JS_TRUE;
|
||||
|
||||
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;
|
||||
return js_AddLocal(cx, data->u.var.fun, atom, data->u.var.kind);
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
|
@ -1113,9 +1049,6 @@ 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);
|
||||
|
@ -1126,13 +1059,7 @@ BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
|
|||
ALE_SET_JSOP(ale, data->op);
|
||||
}
|
||||
|
||||
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));
|
||||
if (js_LookupLocal(cx, data->u.var.fun, atom, NULL) != JSLOCAL_NONE) {
|
||||
name = js_AtomToPrintableString(cx, atom);
|
||||
if (!name ||
|
||||
!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
|
||||
|
@ -1141,7 +1068,6 @@ 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;
|
||||
|
@ -1160,9 +1086,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
JSAtom *funAtom;
|
||||
JSParsedObjectBox *funpob;
|
||||
JSStackFrame *fp;
|
||||
JSObject *varobj, *pobj;
|
||||
JSObject *varobj;
|
||||
JSAtomListElement *ale;
|
||||
JSProperty *prop;
|
||||
JSFunction *fun;
|
||||
JSTreeContext funtc;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
|
@ -1242,56 +1167,31 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
* JSOP_GETVAR bytecode).
|
||||
*/
|
||||
if (AT_TOP_LEVEL(tc) && (tc->flags & TCF_IN_FUNCTION)) {
|
||||
JSScopeProperty *sprop;
|
||||
JSLocalKind localKind;
|
||||
|
||||
/*
|
||||
* Define a property on the outer function so that BindNameToSlot
|
||||
* can properly optimize accesses.
|
||||
* 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.
|
||||
*/
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);
|
||||
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)) {
|
||||
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))
|
||||
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, lambda ? JSFUN_LAMBDA : 0, varobj,
|
||||
funAtom);
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0,
|
||||
JSFUN_INTERPRETED | (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;
|
||||
|
@ -1299,7 +1199,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
/*
|
||||
* Create wrapping box for fun->object early to protect against a
|
||||
* last-ditch GC under js_LookupHiddenProperty.
|
||||
* last-ditch GC.
|
||||
*/
|
||||
funpob = js_NewParsedObjectBox(cx, tc->parseContext, fun->object);
|
||||
if (!funpob)
|
||||
|
@ -1338,10 +1238,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
data.op = JSOP_DEFVAR;
|
||||
data.binder = BindDestructuringArg;
|
||||
data.u.var.clasp = &js_FunctionClass;
|
||||
data.u.var.getter = js_GetLocalVariable;
|
||||
data.u.var.setter = js_SetLocalVariable;
|
||||
data.u.var.attrs = JSPROP_PERMANENT;
|
||||
|
||||
data.u.var.kind = JSLOCAL_VAR;
|
||||
lhs = DestructuringExpr(cx, &data, &funtc, tt);
|
||||
if (!lhs)
|
||||
return NULL;
|
||||
|
@ -1357,7 +1254,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
* parameter that is to be destructured.
|
||||
*/
|
||||
slot = fun->nargs;
|
||||
if (!BumpFormalCount(cx, fun))
|
||||
if (!js_AddLocal(cx, fun, NULL, JSLOCAL_ARG))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
|
@ -1808,11 +1705,8 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
|||
JSOp op, prevop;
|
||||
const char *name;
|
||||
JSFunction *fun;
|
||||
JSObject *obj, *pobj;
|
||||
JSProperty *prop;
|
||||
JSBool ok;
|
||||
JSPropertyOp getter, setter;
|
||||
JSScopeProperty *sprop;
|
||||
JSObject *obj;
|
||||
JSLocalKind localKind;
|
||||
|
||||
stmt = js_LexicalLookup(tc, atom, NULL, 0);
|
||||
ATOM_LIST_SEARCH(ale, &tc->decls, atom);
|
||||
|
@ -1853,83 +1747,16 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
|||
|
||||
fun = data->u.var.fun;
|
||||
obj = data->obj;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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, TS(tc->parseContext), data->pn,
|
||||
JSREPORT_ERROR,
|
||||
JSMSG_REDECLARED_PARAM,
|
||||
name);
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
getter = js_GetArgument;
|
||||
setter = js_SetArgument;
|
||||
ok = js_ReportCompileErrorNumber(cx, TS(tc->parseContext),
|
||||
data->pn,
|
||||
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 {
|
||||
localKind = js_LookupLocal(cx, fun, atom, NULL);
|
||||
if (localKind == JSLOCAL_NONE) {
|
||||
/*
|
||||
* Property not found in current variable scope: we have not seen this
|
||||
* variable before. Define a new local variable by adding a property
|
||||
|
@ -1938,19 +1765,32 @@ 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, TS(tc->parseContext), data->pn,
|
||||
JSREPORT_ERROR, JSMSG_REDECLARED_PARAM,
|
||||
name);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!js_ReportCompileErrorNumber(cx, TS(tc->parseContext), data->pn,
|
||||
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 ok;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
|
@ -1985,7 +1825,7 @@ BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn,
|
|||
pn->pn_op = (data->op == JSOP_DEFCONST)
|
||||
? JSOP_SETCONST
|
||||
: JSOP_SETNAME;
|
||||
pn->pn_attrs = data->u.var.attrs;
|
||||
pn->pn_const = (data->u.var.kind == JSLOCAL_CONST);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -3720,20 +3560,16 @@ 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.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;
|
||||
data.u.var.kind = (data.op == JSOP_DEFCONST)
|
||||
? JSLOCAL_CONST
|
||||
: JSLOCAL_VAR;
|
||||
} else {
|
||||
data.u.var.getter = data.u.var.clasp->getProperty;
|
||||
data.u.var.setter = data.u.var.clasp->setProperty;
|
||||
/*
|
||||
* We are compiling global code or code from an eval inside a
|
||||
* function
|
||||
*/
|
||||
data.u.var.kind = JSLOCAL_NONE;
|
||||
}
|
||||
|
||||
data.u.var.attrs = (data.op == JSOP_DEFCONST)
|
||||
? JSPROP_PERMANENT | JSPROP_READONLY
|
||||
: JSPROP_PERMANENT;
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -3786,7 +3622,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
pn2->pn_atom = atom;
|
||||
pn2->pn_slot = -1;
|
||||
if (!let)
|
||||
pn2->pn_attrs = data.u.var.attrs;
|
||||
pn2->pn_const = (data.u.var.kind == JSLOCAL_CONST);
|
||||
PN_APPEND(pn, pn2);
|
||||
|
||||
if (js_MatchToken(cx, ts, TOK_ASSIGN)) {
|
||||
|
@ -4492,11 +4328,10 @@ 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, cx->fp->varobj,
|
||||
NULL);
|
||||
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
|
||||
cx->fp->varobj, NULL);
|
||||
if (!fun)
|
||||
return NULL;
|
||||
fun->flags |= JSFUN_INTERPRETED;
|
||||
|
||||
/*
|
||||
* This generator function is referenced by an anonymous function object
|
||||
|
|
|
@ -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_attrs telling const-ness
|
||||
* with pn_slot >= 0 and pn_const 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 */
|
||||
uintN attrs; /* attributes if local var or const */
|
||||
JSBool constslot; /* true for const names */
|
||||
} name;
|
||||
struct { /* lexical scope. */
|
||||
JSParsedObjectBox *pob; /* block object */
|
||||
|
@ -344,7 +344,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_attrs pn_u.name.attrs
|
||||
#define pn_const pn_u.name.constslot
|
||||
#define pn_dval pn_u.dval
|
||||
#define pn_atom2 pn_u.apair.atom2
|
||||
#define pn_pob pn_u.object.pob
|
||||
|
|
|
@ -89,6 +89,11 @@
|
|||
(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;
|
||||
|
|
|
@ -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_IS_DUPLICATE)
|
||||
#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_ALLOW_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_IS_DUPLICATE));
|
||||
JS_ASSERT(sparse || (sprop->flags & SPROP_ALLOW_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_IS_DUPLICATE flag helps us
|
||||
* cope with the consequent disparity between ancestor line height and
|
||||
* scope->entryCount.
|
||||
* descending from the old one. The SPROP_ALLOW_DUPLICATE flag helps
|
||||
* us cope with the consequent disparity between ancestor line height
|
||||
* and scope->entryCount.
|
||||
*/
|
||||
if (flags & SPROP_IS_DUPLICATE) {
|
||||
sprop->flags |= SPROP_IS_DUPLICATE;
|
||||
if (flags & SPROP_ALLOW_DUPLICATE) {
|
||||
sprop->flags |= SPROP_ALLOW_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_IS_DUPLICATE).
|
||||
* (unless flagged SPROP_ALLOW_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;
|
||||
child.flags = flags & ~SPROP_ALLOW_DUPLICATE;
|
||||
child.shortid = shortid;
|
||||
sprop = GetPropertyTreeChild(cx, scope->lastProp, &child);
|
||||
if (!sprop)
|
||||
|
|
|
@ -288,11 +288,9 @@ struct JSScopeProperty {
|
|||
|
||||
/* Bits stored in sprop->flags. */
|
||||
#define SPROP_MARK 0x01
|
||||
#define SPROP_IS_DUPLICATE 0x02
|
||||
#define SPROP_ALLOW_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
|
||||
|
|
|
@ -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 = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
|
||||
fun = GET_FUNCTION_PRIVATE(cx, obj);
|
||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
||||
return fun->u.i.script->lineno;
|
||||
}
|
||||
|
|
|
@ -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 - 15)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 16)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
|
|
@ -5585,6 +5585,7 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
|
|||
{
|
||||
JSXML *xml;
|
||||
JSFunction *fun;
|
||||
char numBuf[12];
|
||||
|
||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp));
|
||||
|
||||
|
@ -5604,14 +5605,11 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp));
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче