static void SetFunctionKinds(FunctionBox *funbox, uint32 *tcflags, bool isDirectEval) { for (; funbox; funbox = funbox->siblings) { ParseNode *fn = funbox->node; ParseNode *pn = fn->pn_body; if (funbox->kids) SetFunctionKinds(funbox->kids, tcflags, isDirectEval); JSFunction *fun = funbox->function(); JS_ASSERT(fun->kind() == JSFUN_INTERPRETED); if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) { /* nothing to do */ } else if (isDirectEval || funbox->inAnyDynamicScope()) { /* * Either we are in a with-block or a function scope that is * subject to direct eval; or we are compiling strict direct eval * code. * * In either case, fun may reference names that are not bound but * are not necessarily global either. (In the strict direct eval * case, we could bind them, but currently do not bother; see * the comment about strict mode code in BindTopLevelVar.) */ JS_ASSERT(!fun->isNullClosure()); } else { bool hasUpvars = false; bool canFlatten = true; if (pn->isKind(PNK_UPVARS)) { AtomDefnMapPtr upvars = pn->pn_names; JS_ASSERT(!upvars->empty()); /* * For each lexical dependency from this closure to an outer * binding, analyze whether it is safe to copy the binding's * value into a flat closure slot when the closure is formed. */ for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { Definition *defn = r.front().value(); Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) { hasUpvars = true; if (!CanFlattenUpvar(lexdep, funbox, *tcflags)) { /* * Can't flatten. Enclosing functions holding * variables used by this function will be flagged * heavyweight below. FIXME bug 545759: re-enable * partial flat closures. */ canFlatten = false; break; } } } } if (!hasUpvars) { /* No lexical dependencies => null closure, for best performance. */ fun->setKind(JSFUN_NULL_CLOSURE); } else if (canFlatten) { fun->setKind(JSFUN_FLAT_CLOSURE); switch (fn->getOp()) { case JSOP_DEFFUN: fn->setOp(JSOP_DEFFUN_FC); break; case JSOP_DEFLOCALFUN: fn->setOp(JSOP_DEFLOCALFUN_FC); break; case JSOP_LAMBDA: fn->setOp(JSOP_LAMBDA_FC); break; default: /* js::frontend::EmitTree's PNK_FUNCTION case sets op. */ JS_ASSERT(fn->isOp(JSOP_NOP)); } } } if (fun->kind() == JSFUN_INTERPRETED && pn->isKind(PNK_UPVARS)) { /* * One or more upvars cannot be safely snapshot into a flat * closure's non-reserved slot (see JSOP_GETFCSLOT), so we loop * again over all upvars, and for each non-free upvar, ensure that * its containing function has been flagged as heavyweight. * * The emitter must see TCF_FUN_HEAVYWEIGHT accurately before * generating any code for a tree of nested functions. */ AtomDefnMapPtr upvars = pn->pn_names; JS_ASSERT(!upvars->empty()); for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { Definition *defn = r.front().value(); Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) FlagHeavyweights(lexdep, funbox, tcflags); } } if (funbox->joinable()) fun->setJoinable(); } }
static void SetFunctionKinds(FunctionBox *funbox, bool *isHeavyweight, bool topInFunction, bool isDirectEval) { for (; funbox; funbox = funbox->siblings) { ParseNode *fn = funbox->node; if (!fn) continue; ParseNode *pn = fn->pn_body; if (!pn) continue; if (funbox->kids) SetFunctionKinds(funbox->kids, isHeavyweight, topInFunction, isDirectEval); JSFunction *fun = funbox->function(); JS_ASSERT(fun->kind() == JSFUN_INTERPRETED); if (funbox->funIsHeavyweight()) { /* nothing to do */ } else if (isDirectEval || funbox->inAnyDynamicScope()) { /* * Either we are in a with-block or a function scope that is * subject to direct eval; or we are compiling strict direct eval * code. * * In either case, fun may reference names that are not bound but * are not necessarily global either. (In the strict direct eval * case, we could bind them, but currently do not bother; see * the comment about strict mode code in BindTopLevelVar.) */ JS_ASSERT(!fun->isNullClosure()); } else { bool hasUpvars = false; if (pn->isKind(PNK_UPVARS)) { AtomDefnMapPtr upvars = pn->pn_names; JS_ASSERT(!upvars->empty()); /* Determine whether the this function contains upvars. */ for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { if (!r.front().value()->resolve()->isFreeVar()) { hasUpvars = true; break; } } } if (!hasUpvars) { /* No lexical dependencies => null closure, for best performance. */ fun->setKind(JSFUN_NULL_CLOSURE); } } if (fun->kind() == JSFUN_INTERPRETED && pn->isKind(PNK_UPVARS)) { /* * We loop again over all upvars, and for each non-free upvar, * ensure that its containing function has been flagged as * heavyweight. * * The emitter must see funIsHeavyweight() accurately before * generating any code for a tree of nested functions. */ AtomDefnMapPtr upvars = pn->pn_names; JS_ASSERT(!upvars->empty()); for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) { Definition *defn = r.front().value(); Definition *lexdep = defn->resolve(); if (!lexdep->isFreeVar()) FlagHeavyweights(lexdep, funbox, isHeavyweight, topInFunction); } } } }