void DumpAtomDefnMap(const AtomDefnMapPtr &map) { if (map->empty()) { fprintf(stderr, "empty\n"); return; } for (AtomDefnRange r = map->all(); !r.empty(); r.popFront()) { fprintf(stderr, "atom: "); js_DumpAtom(r.front().key()); fprintf(stderr, "defn: %p\n", (void *) r.front().value()); } }
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 bool MarkFunArgs(JSContext *cx, FunctionBox *funbox, uint32 functionCount) { FunctionBoxQueue queue; if (!queue.init(functionCount)) { js_ReportOutOfMemory(cx); return false; } FindFunArgs(funbox, -1, &queue); while ((funbox = queue.pull()) != NULL) { ParseNode *fn = funbox->node; JS_ASSERT(fn->isFunArg()); ParseNode *pn = fn->pn_body; if (pn->isKind(PNK_UPVARS)) { 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() && !lexdep->isFunArg() && (lexdep->kind() == Definition::FUNCTION || lexdep->isOp(JSOP_CALLEE))) { /* * Mark this formerly-Algol-like function as an escaping * function (i.e., as a funarg), because it is used from * another funarg. * * Progress is guaranteed because we set the funarg flag * here, which suppresses revisiting this function (thanks * to the !lexdep->isFunArg() test just above). */ lexdep->setFunArg(); FunctionBox *afunbox; if (lexdep->isOp(JSOP_CALLEE)) { /* * A named function expression will not appear to be a * funarg if it is immediately applied. However, if its * name is used in an escaping function nested within * it, then it must become flagged as a funarg again. * See bug 545980. */ afunbox = funbox; uintN calleeLevel = lexdep->pn_cookie.level(); uintN staticLevel = afunbox->level + 1U; while (staticLevel != calleeLevel) { afunbox = afunbox->parent; --staticLevel; } JS_ASSERT(afunbox->level + 1U == calleeLevel); afunbox->node->setFunArg(); } else { afunbox = lexdep->pn_funbox; } queue.push(afunbox); /* * Walk over nested functions again, now that we have * changed the level across which it is unsafe to access * upvars using the runtime dynamic link (frame chain). */ if (afunbox->kids) FindFunArgs(afunbox->kids, afunbox->level, &queue); } } } } return true; }
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); } } } }