diff --git a/mozilla/js/src/js.c b/mozilla/js/src/js.c index 3fa6853e933..4dd8ae656de 100644 --- a/mozilla/js/src/js.c +++ b/mozilla/js/src/js.c @@ -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); diff --git a/mozilla/js/src/jsapi.c b/mozilla/js/src/jsapi.c index 70580d6280d..5c41437be07 100644 --- a/mozilla/js/src/jsapi.c +++ b/mozilla/js/src/jsapi.c @@ -4663,24 +4663,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; } } @@ -4716,7 +4710,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) @@ -4736,12 +4730,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; @@ -4756,12 +4750,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; diff --git a/mozilla/js/src/jsdbgapi.c b/mozilla/js/src/jsdbgapi.c index 0d9d70d69f9..69162b852f4 100644 --- a/mozilla/js/src/jsdbgapi.c +++ b/mozilla/js/src/jsdbgapi.c @@ -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 && diff --git a/mozilla/js/src/jsemit.c b/mozilla/js/src/jsemit.c index 755720154b3..58cfa933ddf 100644 --- a/mozilla/js/src/jsemit.c +++ b/mozilla/js/src/jsemit.c @@ -1233,8 +1233,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; @@ -1646,26 +1645,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); @@ -1835,7 +1818,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 @@ -1851,14 +1834,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) @@ -1922,42 +1901,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, @@ -1969,10 +1938,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); @@ -1986,93 +1951,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; } @@ -2109,7 +2071,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; @@ -2170,7 +2132,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; } } @@ -4034,7 +3996,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; @@ -4087,31 +4049,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 @@ -4123,9 +4076,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); } } @@ -4483,7 +4436,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 diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index 54376fd3da1..d0ba7448e90 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/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, spflags; + jsval value; fp = (JSStackFrame *) JS_GetPrivate(cx, obj); if (!fp) @@ -840,61 +828,42 @@ 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); + value = (slot < fp->argc) ? fp->argv[slot] : JSVAL_VOID; + getter = setter = NULL; + attrs = JSPROP_PERMANENT; + spflags = 0; + slot = 0; + } else { + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); + JS_ASSERT(fp->fun->u.i.nvars == fp->nvars); + JS_ASSERT(slot < fp->nvars); + value = fp->vars[slot]; + getter = js_GetCallVariable; + setter = js_SetCallVariable; + attrs = (localKind == JSLOCAL_CONST) + ? JSPROP_PERMANENT | JSPROP_READONLY + : JSPROP_PERMANENT; + spflags = SPROP_HAS_SHORTID; } - - 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), value, + getter, setter, attrs, + spflags, (int) slot, NULL)) { + return JS_FALSE; } + *objp = obj; return JS_TRUE; } @@ -1106,39 +1075,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 +1195,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 +1202,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 +1218,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 +1239,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 +1383,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"); @@ -1497,6 +1401,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) @@ -1559,7 +1468,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); @@ -1799,12 +1708,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; @@ -1812,7 +1719,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)) { @@ -1821,6 +1727,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; @@ -1837,8 +1748,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; @@ -1962,54 +1873,24 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * we're assured at this point that it's a valid identifier. */ atom = CURRENT_TOKEN(&pc.tokenStream).t_atom; - if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), - &obj2, &prop)) { - goto after_args; - } - sprop = (JSScopeProperty *) prop; - dupflag = 0; - if (sprop) { - ok = JS_TRUE; - if (obj2 == obj) { - const char *name = js_AtomToPrintableString(cx, atom); - /* - * A duplicate parameter name. We force a duplicate - * node on the SCOPE_LAST_PROP(scope) list with the - * same id, distinguished by the SPROP_IS_DUPLICATE - * flag, and not mapped by an entry in scope. - */ - JS_ASSERT(sprop->getter == js_GetArgument); - ok = name && - js_ReportCompileErrorNumber(cx, &pc.tokenStream, - JSREPORT_TS | - 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, + JSREPORT_TS | + 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 @@ -2074,14 +1955,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: @@ -2137,10 +2017,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; @@ -2176,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; @@ -2234,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 * @@ -2320,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; +} + diff --git a/mozilla/js/src/jsfun.h b/mozilla/js/src/jsfun.h index f2ff2445691..af8f188a7f9 100644 --- a/mozilla/js/src/jsfun.h +++ b/mozilla/js/src/jsfun.h @@ -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); @@ -172,6 +180,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___ */ diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index 46e685a33c5..7446a72dfa5 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -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) diff --git a/mozilla/js/src/jsinterp.h b/mozilla/js/src/jsinterp.h index 073d6da673b..9758dc6d55d 100644 --- a/mozilla/js/src/jsinterp.h +++ b/mozilla/js/src/jsinterp.h @@ -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) diff --git a/mozilla/js/src/jsobj.c b/mozilla/js/src/jsobj.c index 28368bae01b..bf8af597153 100644 --- a/mozilla/js/src/jsobj.c +++ b/mozilla/js/src/jsobj.c @@ -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, diff --git a/mozilla/js/src/jsobj.h b/mozilla/js/src/jsobj.h index 783a2281c41..90832419b56 100644 --- a/mozilla/js/src/jsobj.h +++ b/mozilla/js/src/jsobj.h @@ -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___ */ diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index 7d99f617146..42ea949a0e8 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -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 *) ""; diff --git a/mozilla/js/src/jsopcode.h b/mozilla/js/src/jsopcode.h index 7adb3842d98..244203bde4d 100644 --- a/mozilla/js/src/jsopcode.h +++ b/mozilla/js/src/jsopcode.h @@ -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 diff --git a/mozilla/js/src/jsparse.c b/mozilla/js/src/jsparse.c index ff73eb7657f..fdbe3796c4a 100644 --- a/mozilla/js/src/jsparse.c +++ b/mozilla/js/src/jsparse.c @@ -814,6 +814,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 || @@ -828,12 +829,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; @@ -996,9 +991,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; @@ -1016,83 +1009,40 @@ struct BindData { (data)->pn ? (void *)(data)->pn : (void *)(data)->ts, \ ((data)->pn ? JSREPORT_PN : JSREPORT_TS) | (flags) -static JSBool -BumpFormalCount(JSContext *cx, JSFunction *fun) -{ - if (fun->nargs == JS_BITMASK(16)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_FUN_ARGS); - return JS_FALSE; - } - fun->nargs++; - return JS_TRUE; -} - static JSBool BindArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) { - JSObject *obj, *pobj; - JSProperty *prop; - JSBool ok; - uintN dupflag; - JSFunction *fun; const char *name; - 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, + if (!name || + !js_ReportCompileErrorNumber(cx, BIND_DATA_REPORT_ARGS(data, 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. @@ -1103,21 +1053,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 @@ -1133,9 +1069,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); @@ -1146,13 +1079,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, @@ -1163,7 +1090,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; @@ -1182,9 +1108,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 @@ -1265,56 +1190,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; @@ -1322,7 +1222,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) @@ -1362,10 +1262,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; @@ -1381,7 +1278,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; /* @@ -1839,11 +1736,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); @@ -1885,84 +1779,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, - BIND_DATA_REPORT_ARGS(data, - JSREPORT_ERROR), - JSMSG_REDECLARED_PARAM, - name); - ok = JS_FALSE; - } else { - getter = js_GetArgument; - setter = js_SetArgument; - ok = js_ReportCompileErrorNumber(cx, - BIND_DATA_REPORT_ARGS(data, - JSREPORT_WARNING | - JSREPORT_STRICT), - JSMSG_VAR_HIDES_ARG, - name); - } - } else { - JS_ASSERT(getter == js_GetLocalVariable); - - if (fun) { - /* Not an argument, must be a redeclared local var. */ - if (data->u.var.clasp == &js_FunctionClass) { - JS_ASSERT(sprop->getter == js_GetLocalVariable); - JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) && - (uint16) sprop->shortid < fun->u.i.nvars); - } else if (data->u.var.clasp == &js_CallClass) { - if (sprop->getter == js_GetCallVariable) { - /* - * Referencing a name introduced by a var statement in - * the enclosing function. Check that the slot number - * we have is in range. - */ - JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) && - (uint16) sprop->shortid < fun->u.i.nvars); - } else { - /* - * A variable introduced through another eval: don't - * use the special getters and setters since we can't - * allocate a slot in the frame. - */ - getter = sprop->getter; - setter = sprop->setter; - } - } - - /* Override the old getter and setter, to handle eval. */ - sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop, - 0, sprop->attrs, - getter, setter); - if (!sprop) - ok = JS_FALSE; - } - } - if (prop) - OBJ_DROP_PROPERTY(cx, pobj, prop); - } else { + 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 @@ -1971,19 +1797,37 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) * bodies are handled at runtime, by script prolog JSOP_DEFVAR opcodes * generated for slot-less vars. */ - sprop = NULL; - if (prop) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - prop = NULL; - } - if (cx->fp->scopeChain == obj && !js_InWithStatement(tc) && !BindLocalVariable(cx, data, atom)) { return JS_FALSE; } + } else if (localKind == JSLOCAL_ARG) { + name = js_AtomToPrintableString(cx, atom); + if (!name) + return JS_FALSE; + + if (op == JSOP_DEFCONST) { + js_ReportCompileErrorNumber(cx, + BIND_DATA_REPORT_ARGS(data, + JSREPORT_ERROR), + JSMSG_REDECLARED_PARAM, + name); + return JS_FALSE; + } + if (!js_ReportCompileErrorNumber(cx, + BIND_DATA_REPORT_ARGS(data, + JSREPORT_WARNING | + JSREPORT_STRICT), + JSMSG_VAR_HIDES_ARG, + name)) { + return JS_FALSE; + } + } else { + /* Not an argument, must be a redeclared local var. */ + JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST); } - return ok; + return JS_TRUE; } #if JS_HAS_DESTRUCTURING @@ -2018,7 +1862,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; } @@ -3768,20 +3612,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 { @@ -3834,7 +3674,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)) { @@ -4545,11 +4385,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 diff --git a/mozilla/js/src/jsparse.h b/mozilla/js/src/jsparse.h index c8334db4155..e1a417965ef 100644 --- a/mozilla/js/src/jsparse.h +++ b/mozilla/js/src/jsparse.h @@ -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 */ @@ -345,7 +345,7 @@ struct JSParseNode { #define pn_atom pn_u.name.atom #define pn_expr pn_u.name.expr #define pn_slot pn_u.name.slot -#define pn_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 diff --git a/mozilla/js/src/jsprvtd.h b/mozilla/js/src/jsprvtd.h index 162978d10e5..94eda25b5d9 100644 --- a/mozilla/js/src/jsprvtd.h +++ b/mozilla/js/src/jsprvtd.h @@ -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; diff --git a/mozilla/js/src/jsscope.c b/mozilla/js/src/jsscope.c index 614bb68556a..b0f9bcbdced 100644 --- a/mozilla/js/src/jsscope.c +++ b/mozilla/js/src/jsscope.c @@ -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) diff --git a/mozilla/js/src/jsscope.h b/mozilla/js/src/jsscope.h index 5ee217914e0..e997277cf67 100644 --- a/mozilla/js/src/jsscope.h +++ b/mozilla/js/src/jsscope.h @@ -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 diff --git a/mozilla/js/src/jsscript.c b/mozilla/js/src/jsscript.c index d013ebf375f..f6449281bac 100644 --- a/mozilla/js/src/jsscript.c +++ b/mozilla/js/src/jsscript.c @@ -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; } diff --git a/mozilla/js/src/jsxdrapi.h b/mozilla/js/src/jsxdrapi.h index c44f245b3b4..598aff2fb72 100644 --- a/mozilla/js/src/jsxdrapi.h +++ b/mozilla/js/src/jsxdrapi.h @@ -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. diff --git a/mozilla/js/src/jsxml.c b/mozilla/js/src/jsxml.c index 9de9086e8ca..ddcc55a6024 100644 --- a/mozilla/js/src/jsxml.c +++ b/mozilla/js/src/jsxml.c @@ -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; }