author | Eddy Bruel <ejpbruel@mozilla.com> |
Fri, 18 Jan 2013 14:21:32 +0100 | |
changeset 119251 | 4bee0517d440f222505c2d1bc8af8841bc66338d |
parent 119250 | 0141f43d8c5b1fc4c02aceedb6a5f9b7af8f8131 |
child 119252 | a9676f4f869b6bab95fb65ba97b49f7eb5cc45cb |
push id | 24195 |
push user | Ms2ger@gmail.com |
push date | Sat, 19 Jan 2013 16:10:11 +0000 |
treeherder | mozilla-central@02e12a80aef9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jorendorff |
bugs | 568593 |
milestone | 21.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -694,22 +694,22 @@ PushStatementBCE(BytecodeEmitter *bce, S * block object or compiler created function. */ static JSObject * EnclosingStaticScope(BytecodeEmitter *bce) { if (bce->blockChain) return bce->blockChain; - if (!bce->sc->isFunction) { + if (!bce->sc->isFunctionBox()) { JS_ASSERT(!bce->parent); return NULL; } - return bce->sc->asFunbox()->function(); + return bce->sc->asFunctionBox()->function(); } // Push a block scope statement and link blockObj into bce->blockChain. static void PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj, ptrdiff_t top) { PushStatementBCE(bce, stmt, STMT_BLOCK, top); @@ -915,17 +915,17 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, if (pn->isUsed()) { /* * As explained in BindNameToSlot, the 'level' of a use indicates how * many function scopes (i.e., BytecodeEmitters) to skip to find the * enclosing function scope of the definition being accessed. */ for (unsigned i = pn->pn_cookie.level(); i; i--) { skippedScopes += ClonedBlockDepth(bceOfDef); - JSFunction *funOfDef = bceOfDef->sc->asFunbox()->function(); + JSFunction *funOfDef = bceOfDef->sc->asFunctionBox()->function(); if (funOfDef->isHeavyweight()) { skippedScopes++; if (funOfDef->isNamedLambda()) skippedScopes++; } bceOfDef = bceOfDef->parent; } } else { @@ -1077,17 +1077,17 @@ BytecodeEmitter::isAliasedName(ParseNode * js::frontend::CompileScript; see comments there. * * The function returns -1 on failures. */ static int AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot) { JS_ASSERT((unsigned) slot < bce->maxStackDepth); - if (bce->sc->isFunction) { + if (bce->sc->isFunctionBox()) { slot += bce->script->bindings.numVars(); if ((unsigned) slot >= SLOTNO_LIMIT) { bce->reportError(NULL, JSMSG_TOO_MANY_LOCALS); slot = -1; } } return slot; } @@ -1175,17 +1175,17 @@ TryConvertToGname(BytecodeEmitter *bce, case JSOP_SETNAME: *op = JSOP_SETINTRINSIC; break; /* Other *NAME ops aren't (yet) supported in self-hosted code. */ default: JS_NOT_REACHED("intrinsic"); } return true; } if (bce->script->compileAndGo && bce->hasGlobalScope && - !(bce->sc->isFunction && bce->sc->asFunbox()->mightAliasLocals()) && + !(bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->mightAliasLocals()) && !pn->isDeoptimized() && !bce->sc->strict) { // If you change anything here, you might also need to change // js::ReportIfUndeclaredVarAssignment. switch (*op) { case JSOP_NAME: *op = JSOP_GETGNAME; break; case JSOP_SETNAME: *op = JSOP_SETGNAME; break; @@ -1377,17 +1377,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm /* * Currently, the ALIASEDVAR ops do not support accessing the * callee of a DeclEnvObject, so use NAME. */ if (dn->pn_cookie.level() != bce->script->staticLevel) return true; - RootedFunction fun(cx, bce->sc->asFunbox()->function()); + RootedFunction fun(cx, bce->sc->asFunctionBox()->function()); JS_ASSERT(fun->isLambda()); JS_ASSERT(pn->pn_atom == fun->atom()); /* * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to * address two cases: a new binding introduced by eval, and * assignment to the name in strict mode. * @@ -1440,17 +1440,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm * bloat where a single live function keeps its whole global script * alive.), ScopeCoordinateToTypeSet is not able to find the var/let's * associated types::TypeSet. */ if (skip) { BytecodeEmitter *bceSkipped = bce; for (unsigned i = 0; i < skip; i++) bceSkipped = bceSkipped->parent; - if (!bceSkipped->sc->isFunction) + if (!bceSkipped->sc->isFunctionBox()) return true; } JS_ASSERT(!pn->isOp(op)); pn->setOp(op); if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot())) return false; @@ -1652,37 +1652,37 @@ CheckSideEffects(JSContext *cx, Bytecode break; } return ok; } bool BytecodeEmitter::checkSingletonContext() { - if (!script->compileAndGo || sc->isFunction) + if (!script->compileAndGo || sc->isFunctionBox()) return false; for (StmtInfoBCE *stmt = topStmt; stmt; stmt = stmt->down) { if (stmt->isLoop()) return false; } hasSingletons = true; return true; } bool BytecodeEmitter::needsImplicitThis() { if (!script->compileAndGo) return true; - if (sc->isFunction) { - if (sc->asFunbox()->inWith) + if (sc->isFunctionBox()) { + if (sc->asFunctionBox()->inWith) return true; } else { - JSObject *scope = sc->asGlobal()->scopeChain(); + JSObject *scope = sc->asGlobalSharedContext()->scopeChain(); while (scope) { if (scope->isWith()) return true; scope = scope->enclosingScope(); } } for (StmtInfoBCE *stmt = topStmt; stmt; stmt = stmt->down) { @@ -2542,17 +2542,17 @@ frontend::EmitFunctionScript(JSContext * { /* * The decompiler has assumptions about what may occur immediately after * script->main (e.g., in the case of destructuring params). Thus, put the * following ops into the range [script->code, script->main). Note: * execution starts from script->code, so this has no semantic effect. */ - FunctionBox *funbox = bce->sc->asFunbox(); + FunctionBox *funbox = bce->sc->asFunctionBox(); if (funbox->argumentsHasLocalBinding()) { JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */ bce->switchToProlog(); if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0) return false; InternalBindingsHandle bindings(bce->script, &bce->script->bindings); unsigned varIndex = Bindings::argumentsVarIndex(cx, bindings); if (bce->script->varIsAliased(varIndex)) { @@ -2619,17 +2619,17 @@ MaybeEmitVarDecl(JSContext *cx, Bytecode if (!pn->pn_cookie.isFree()) { atomIndex = pn->pn_cookie.slot(); } else { if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex)) return false; } if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM && - (!bce->sc->isFunction || bce->sc->asFunbox()->function()->isHeavyweight())) + (!bce->sc->isFunctionBox() || bce->sc->asFunctionBox()->function()->isHeavyweight())) { bce->switchToProlog(); if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin)) return false; if (!EmitIndexOp(cx, prologOp, atomIndex, bce)) return false; bce->switchToMain(); } @@ -4395,17 +4395,17 @@ EmitLexicalScope(JSContext *cx, Bytecode * shouldn't be so complicated; try to find a simpler condition. */ ptrdiff_t noteIndex = -1; if (pn->expr()->getKind() != PNK_FOR && pn->expr()->getKind() != PNK_CATCH && (stmtInfo.down ? stmtInfo.down->type == STMT_BLOCK && (!stmtInfo.down->down || stmtInfo.down->down->type != STMT_FOR_IN_LOOP) - : !bce->sc->isFunction)) + : !bce->sc->isFunctionBox())) { /* There must be no source note already output for the next op. */ JS_ASSERT(bce->noteCount() == 0 || bce->lastNoteOffset() != bce->offset() || !GettableNoteForNextOp(bce)); noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0); if (noteIndex < 0) return false; @@ -4788,25 +4788,25 @@ EmitFunc(JSContext *cx, BytecodeEmitter JS_ASSERT(fun->isInterpreted()); if (fun->hasScript()) { /* * This second pass is needed to emit JSOP_NOP with a source note * for the already-emitted function definition prolog opcode. See * comments in EmitStatementList. */ JS_ASSERT(pn->functionIsHoisted()); - JS_ASSERT(bce->sc->isFunction); + JS_ASSERT(bce->sc->isFunctionBox()); return EmitFunctionDefNop(cx, bce, pn->pn_index); } { SharedContext *outersc = bce->sc; FunctionBox *funbox = pn->pn_funbox; - if (outersc->isFunction && outersc->asFunbox()->mightAliasLocals()) + if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals()) funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent JS_ASSERT_IF(outersc->strict, funbox->strict); // Inherit most things (principals, version, etc) from the parent. Rooted<JSScript*> parent(cx, bce->script); Rooted<JSObject*> enclosingScope(cx, EnclosingStaticScope(bce)); CompileOptions options(cx); options.setPrincipals(parent->principals) @@ -4849,17 +4849,17 @@ EmitFunc(JSContext *cx, BytecodeEmitter * For a script we emit the code as we parse. Thus the bytecode for * top-level functions should go in the prolog to predefine their * names in the variable object before the already-generated main code * is executed. This extra work for top-level scripts is not necessary * when we emit the code for a function. It is fully parsed prior to * invocation of the emitter and calls to EmitTree for function * definitions can be scheduled before generating the rest of code. */ - if (!bce->sc->isFunction) { + if (!bce->sc->isFunctionBox()) { JS_ASSERT(pn->pn_cookie.isFree()); JS_ASSERT(pn->getOp() == JSOP_NOP); JS_ASSERT(!bce->topStmt); bce->switchToProlog(); if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce)) return false; if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin)) return false; @@ -5142,17 +5142,17 @@ EmitStatement(JSContext *cx, BytecodeEmi * expression statement as the script's result, despite the fact * that it appears useless to the compiler. * * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when * calling JS_Compile* to suppress JSOP_POPV. */ bool wantval = false; bool useful = false; - if (bce->sc->isFunction) { + if (bce->sc->isFunctionBox()) { JS_ASSERT(!bce->script->noScriptRval); } else { useful = wantval = !bce->script->noScriptRval; } /* Don't eliminate expressions with side effects. */ if (!useful) { if (!CheckSideEffects(cx, bce, pn2, &useful)) @@ -5957,17 +5957,17 @@ frontend::EmitTree(JSContext *cx, Byteco switch (pn->getKind()) { case PNK_FUNCTION: ok = EmitFunc(cx, bce, pn); break; case PNK_ARGSBODY: { - RootedFunction fun(cx, bce->sc->asFunbox()->function()); + RootedFunction fun(cx, bce->sc->asFunctionBox()->function()); ParseNode *pnlast = pn->last(); // Carefully emit everything in the right order: // 1. Destructuring // 2. Functions // 3. Defaults ParseNode *pnchild = pnlast->pn_head; if (pnlast->pn_xflags & PNX_DESTRUCT) { @@ -5995,17 +5995,17 @@ frontend::EmitTree(JSContext *cx, Byteco return false; } } } if (fun->hasDefaults()) { ParseNode *rest = NULL; bool restIsDefn = false; if (fun->hasRest()) { - JS_ASSERT(!bce->sc->asFunbox()->argumentsHasLocalBinding()); + JS_ASSERT(!bce->sc->asFunctionBox()->argumentsHasLocalBinding()); // Defaults with a rest parameter need special handling. The // rest parameter needs to be undefined while defaults are being // processed. To do this, we create the rest argument and let it // sit on the stack while processing defaults. The rest // parameter's slot is set to undefined for the course of // default processing. rest = pn->pn_head; while (rest->pn_next != pnlast) @@ -6040,17 +6040,17 @@ frontend::EmitTree(JSContext *cx, Byteco // Only bind the parameter if it's not aliased by a nested function // in the body. if (!pn2->isDefn()) continue; if (!BindNameToSlot(cx, bce, pn2)) return false; if (pn2->pn_next == pnlast && fun->hasRest() && !fun->hasDefaults()) { // Fill rest parameter. We handled the case with defaults above. - JS_ASSERT(!bce->sc->asFunbox()->argumentsHasLocalBinding()); + JS_ASSERT(!bce->sc->asFunctionBox()->argumentsHasLocalBinding()); bce->switchToProlog(); if (Emit1(cx, bce, JSOP_REST) < 0) return false; CheckTypeSet(cx, bce, JSOP_REST); if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce)) return false; if (Emit1(cx, bce, JSOP_POP) < 0) return false; @@ -6110,17 +6110,17 @@ frontend::EmitTree(JSContext *cx, Byteco break; case PNK_RETURN: ok = EmitReturn(cx, bce, pn); break; #if JS_HAS_GENERATORS case PNK_YIELD: - JS_ASSERT(bce->sc->isFunction); + JS_ASSERT(bce->sc->isFunctionBox()); if (pn->pn_kid) { if (!EmitTree(cx, bce, pn->pn_kid)) return false; } else { if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) return false; } if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
--- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -800,16 +800,24 @@ ObjectBox::ObjectBox(JSObject *object, O } ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink) : object(function), traceLink(traceLink), emitLink(NULL) { JS_ASSERT(object->isFunction()); + JS_ASSERT(asFunctionBox()->function() == function); +} + +FunctionBox * +ObjectBox::asFunctionBox() +{ + JS_ASSERT(isFunctionBox()); + return static_cast<FunctionBox *>(this); } void ObjectBox::trace(JSTracer *trc) { ObjectBox *box = this; while (box) { MarkObjectRoot(trc, &box->object, "parser.object");
--- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1498,17 +1498,17 @@ LinkUseToDef(ParseNode *pn, Definition * } class ObjectBox { public: JSObject *object; ObjectBox(JSObject *object, ObjectBox *traceLink); bool isFunctionBox() { return object->isFunction(); } - FunctionBox *asFunctionBox() { JS_ASSERT(isFunctionBox()); return (FunctionBox *)(this); } + FunctionBox *asFunctionBox(); void trace(JSTracer *trc); protected: friend struct CGObjectList; ObjectBox *traceLink; ObjectBox *emitLink;
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -149,32 +149,32 @@ ParseContext::define(JSContext *cx, Prop pn->setDefn(true); pn->pn_dflags &= ~PND_PLACEHOLDER; if (kind == Definition::CONST) pn->pn_dflags |= PND_CONST; Definition *dn = (Definition *)pn; switch (kind) { case Definition::ARG: - JS_ASSERT(sc->isFunction); + JS_ASSERT(sc->isFunctionBox()); dn->setOp(JSOP_GETARG); dn->pn_dflags |= PND_BOUND; if (!dn->pn_cookie.set(cx, staticLevel, args_.length())) return false; if (!args_.append(dn)) return false; if (name == cx->names().empty) break; if (!decls_.addUnique(name, dn)) return false; break; case Definition::CONST: case Definition::VAR: - if (sc->isFunction) { + if (sc->isFunctionBox()) { dn->setOp(JSOP_GETLOCAL); dn->pn_dflags |= PND_BOUND; if (!dn->pn_cookie.set(cx, staticLevel, vars_.length())) return false; if (!vars_.append(dn)) return false; } if (!decls_.addUnique(name, dn)) @@ -211,17 +211,17 @@ void ParseContext::updateDecl(JSAtom *atom, ParseNode *pn) { Definition *oldDecl = decls_.lookupFirst(atom); pn->setDefn(true); Definition *newDecl = (Definition *)pn; decls_.updateFirst(atom, newDecl); - if (!sc->isFunction) { + if (!sc->isFunctionBox()) { JS_ASSERT(newDecl->isFreeVar()); return; } JS_ASSERT(oldDecl->isBound()); JS_ASSERT(!oldDecl->pn_cookie.isFree()); newDecl->pn_cookie = oldDecl->pn_cookie; newDecl->pn_dflags |= PND_BOUND; @@ -280,17 +280,17 @@ AppendPackedBindings(const ParseContext *dst = Binding(name, kind, aliased); } } bool ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const { - JS_ASSERT(sc->isFunction); + JS_ASSERT(sc->isFunctionBox()); unsigned count = args_.length() + vars_.length(); Binding *packedBindings = cx->tempLifoAlloc().newArrayUninitialized<Binding>(count); if (!packedBindings) { js_ReportOutOfMemory(cx); return false; } @@ -298,17 +298,17 @@ ParseContext::generateFunctionBindings(J AppendPackedBindings(this, vars_, packedBindings + args_.length()); if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), packedBindings)) { return false; } - FunctionBox *funbox = sc->asFunbox(); + FunctionBox *funbox = sc->asFunctionBox(); if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope()) funbox->function()->setIsHeavyweight(); return true; } Parser::Parser(JSContext *cx, const CompileOptions &options, StableCharPtr chars, size_t length, bool foldConstants) @@ -368,17 +368,17 @@ Parser::newObjectBox(JSObject *obj) traceListHead = objbox; return objbox; } FunctionBox::FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, ParseContext *outerpc, bool strict) : ObjectBox(fun, traceListHead), - SharedContext(cx, /* isFunction = */ true, strict), + SharedContext(cx, strict), bindings(), bufStart(0), bufEnd(0), ndefaults(0), inWith(false), // initialized below inGenexpLambda(false), funCxFlags() { @@ -389,42 +389,42 @@ FunctionBox::FunctionBox(JSContext *cx, // This covers cases that don't involve eval(). For example: // // with (o) { (function() { g(); })(); } // // In this case, |outerpc| corresponds to global code, and // outerpc->parsingWith is true. inWith = true; - } else if (!outerpc->sc->isFunction) { + } else if (!outerpc->sc->isFunctionBox()) { // This covers the case where a function is nested within an eval() // within a |with| statement. // // with (o) { eval("(function() { g(); })();"); } // // In this case, |outerpc| corresponds to the eval(), // outerpc->parsingWith is false because the eval() breaks the // ParseContext chain, and |parent| is NULL (again because of the // eval(), so we have to look at |outerpc|'s scopeChain. // - JSObject *scope = outerpc->sc->asGlobal()->scopeChain(); + JSObject *scope = outerpc->sc->asGlobalSharedContext()->scopeChain(); while (scope) { if (scope->isWith()) inWith = true; scope = scope->enclosingScope(); } } else { // This is like the above case, but for more deeply nested functions. // For example: // // with (o) { eval("(function() { (function() { g(); })(); })();"); } } // // In this case, the inner anonymous function needs to inherit the // setting of |inWith| from the outer one. - FunctionBox *parent = outerpc->sc->asFunbox(); + FunctionBox *parent = outerpc->sc->asFunctionBox(); if (parent && parent->inWith) inWith = true; } } FunctionBox * Parser::newFunctionBox(JSFunction *fun, ParseContext *outerpc, bool strict) { @@ -624,30 +624,30 @@ HasFinalReturn(ParseNode *pn) } } static bool ReportBadReturn(JSContext *cx, Parser *parser, ParseNode *pn, Parser::Reporter reporter, unsigned errnum, unsigned anonerrnum) { JSAutoByteString name; - JSAtom *atom = parser->pc->sc->asFunbox()->function()->atom(); + JSAtom *atom = parser->pc->sc->asFunctionBox()->function()->atom(); if (atom) { if (!js_AtomToPrintableString(cx, atom, &name)) return false; } else { errnum = anonerrnum; } return (parser->*reporter)(pn, errnum, name.ptr()); } static bool CheckFinalReturn(JSContext *cx, Parser *parser, ParseNode *pn) { - JS_ASSERT(parser->pc->sc->isFunction); + JS_ASSERT(parser->pc->sc->isFunctionBox()); return HasFinalReturn(pn) == ENDS_IN_RETURN || ReportBadReturn(cx, parser, pn, &Parser::reportStrictWarning, JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE); } /* * Check that it is permitted to assign to lhs. Strict mode code may not * assign to 'eval' or 'arguments'. @@ -734,33 +734,33 @@ Parser::standaloneFunctionBody(HandleFun return NULL; return pn; } ParseNode * Parser::functionBody(FunctionBodyType type) { - JS_ASSERT(pc->sc->isFunction); + JS_ASSERT(pc->sc->isFunctionBox()); JS_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid); ParseNode *pn; if (type == StatementListBody) { pn = statements(); } else { JS_ASSERT(type == ExpressionBody); JS_ASSERT(JS_HAS_EXPR_CLOSURES); pn = UnaryNode::create(PNK_RETURN, this); if (pn) { pn->pn_kid = assignExpr(); if (!pn->pn_kid) { pn = NULL; } else { - if (pc->sc->asFunbox()->isGenerator()) { + if (pc->sc->asFunctionBox()->isGenerator()) { ReportBadReturn(context, this, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); pn = NULL; } else { pn->setOp(JSOP_RETURN); pn->pn_pos.end = pn->pn_kid->pn_pos.end; } @@ -817,17 +817,17 @@ Parser::functionBody(FunctionBodyType ty /* * Report error if both rest parameters and 'arguments' are used. Do this * check before adding artificial 'arguments' below. */ Definition *maybeArgDef = pc->decls().lookupFirst(arguments); bool argumentsHasBinding = !!maybeArgDef; bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG; - bool hasRest = pc->sc->asFunbox()->function()->hasRest(); + bool hasRest = pc->sc->asFunctionBox()->function()->hasRest(); if (hasRest && argumentsHasLocalBinding) { reportError(NULL, JSMSG_ARGUMENTS_AND_REST); return NULL; } /* * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup * forces an 'arguments' binding. The exception is that functions with rest @@ -844,17 +844,17 @@ Parser::functionBody(FunctionBodyType ty } /* * Now that all possible 'arguments' bindings have been added, note whether * 'arguments' has a local binding and whether it unconditionally needs an * arguments object. (Also see the flags' comments in ContextFlags.) */ if (argumentsHasLocalBinding) { - FunctionBox *funbox = pc->sc->asFunbox(); + FunctionBox *funbox = pc->sc->asFunctionBox(); funbox->setArgumentsHasLocalBinding(); /* Dynamic scope access destroys all hope of optimization. */ if (pc->sc->bindingsAccessedDynamically()) funbox->setDefinitelyNeedsArgsObj(); /* * Check whether any parameters have been assigned within this @@ -1070,17 +1070,17 @@ Parser::newFunction(ParseContext *pc, Ha * function's parent slot to pc->sc->asGlobal()->scopeChain. If the global * context is a compile-and-go one, we leave the pre-set parent intact; * otherwise we clear parent and proto. */ while (pc->parent) pc = pc->parent; RootedObject parent(context); - parent = pc->sc->isFunction ? NULL : pc->sc->asGlobal()->scopeChain(); + parent = pc->sc->isFunctionBox() ? NULL : pc->sc->asGlobalSharedContext()->scopeChain(); RootedFunction fun(context); JSFunction::Flags flags = (kind == Expression) ? JSFunction::INTERPRETED_LAMBDA : JSFunction::INTERPRETED; fun = js_NewFunction(context, NullPtr(), NULL, 0, flags, parent, atom); if (selfHostingMode) fun->setIsSelfHostedBuiltin(); @@ -1138,17 +1138,17 @@ LeaveFunction(ParseNode *fn, Parser *par FunctionSyntaxKind kind = Expression) { JSContext *cx = parser->context; ParseContext *funpc = parser->pc; ParseContext *pc = funpc->parent; pc->blockidGen = funpc->blockidGen; FunctionBox *funbox = fn->pn_funbox; - JS_ASSERT(funbox == funpc->sc->asFunbox()); + JS_ASSERT(funbox == funpc->sc->asFunctionBox()); if (!pc->topStmt || pc->topStmt->type == STMT_BLOCK) fn->pn_dflags |= PND_BLOCKCHILD; /* Propagate unresolved lexical names up to pc->lexdeps. */ if (funpc->lexdeps->count()) { for (AtomDefnRange r = funpc->lexdeps->all(); !r.empty(); r.popFront()) { JSAtom *atom = r.front().key(); @@ -1325,17 +1325,17 @@ frontend::DefineArg(Parser *parser, Pars return parser->pc->define(parser->context, name, argpn, Definition::ARG); } #if JS_HAS_DESTRUCTURING static bool BindDestructuringArg(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser) { ParseContext *pc = parser->pc; - JS_ASSERT(pc->sc->isFunction); + JS_ASSERT(pc->sc->isFunctionBox()); if (pc->decls().lookupFirst(name)) { parser->reportError(NULL, JSMSG_BAD_DUP_ARGS); return false; } if (!CheckStrictBinding(cx, parser, name, data->pn)) return false; @@ -1347,17 +1347,17 @@ BindDestructuringArg(JSContext *cx, Bind bool Parser::functionArguments(ParseNode **listp, ParseNode* funcpn, bool &hasRest) { if (tokenStream.getToken() != TOK_LP) { reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL); return false; } - FunctionBox *funbox = pc->sc->asFunbox(); + FunctionBox *funbox = pc->sc->asFunctionBox(); funbox->bufStart = tokenStream.offsetOfToken(tokenStream.currentToken()); hasRest = false; ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, this); if (!argsbody) return false; argsbody->setOp(JSOP_NOP); @@ -1578,23 +1578,23 @@ Parser::functionDef(HandlePropertyName f * As a SpiderMonkey-specific extension, non-body-level function * statements (e.g., functions in an "if" or "while" block) are * dynamically bound when control flow reaches the statement. The * emitter normally emits functions in two passes (see PNK_ARGSBODY). * To distinguish */ if (bodyLevel) { JS_ASSERT(pn->functionIsHoisted()); - JS_ASSERT_IF(pc->sc->isFunction, !pn->pn_cookie.isFree()); - JS_ASSERT_IF(!pc->sc->isFunction, pn->pn_cookie.isFree()); + JS_ASSERT_IF(pc->sc->isFunctionBox(), !pn->pn_cookie.isFree()); + JS_ASSERT_IF(!pc->sc->isFunctionBox(), pn->pn_cookie.isFree()); } else { JS_ASSERT(!pc->sc->strict); JS_ASSERT(pn->pn_cookie.isFree()); - if (pc->sc->isFunction) { - FunctionBox *funbox = pc->sc->asFunbox(); + if (pc->sc->isFunctionBox()) { + FunctionBox *funbox = pc->sc->asFunctionBox(); funbox->setMightAliasLocals(); funbox->setHasExtensibleScope(); } pn->setOp(JSOP_DEFFUN); /* * Instead of setting bindingsAccessedDynamically, which would be * overly conservative, remember the names of all function @@ -1871,17 +1871,17 @@ Parser::maybeParseDirective(ParseNode *p pn->pn_prologue = true; JSAtom *directive = string->pn_atom; if (directive == context->runtime->atomState.useStrict) { // We're going to be in strict mode. Note that this scope explicitly // had "use strict"; pc->sc->setExplicitUseStrict(); if (!pc->sc->strict) { - if (pc->sc->isFunction) { + if (pc->sc->isFunctionBox()) { // Request that this function be reparsed as strict. pc->funBecameStrict = true; return false; } else { // We don't reparse global scopes, so we keep track of the // one possible strict violation that could occur in the // directive prologue -- octal escapes -- and complain now. if (tokenStream.sawOctalEscape()) { @@ -1951,17 +1951,17 @@ Parser::statements(bool *hasFunctionStmt */ if (pc->atBodyLevel()) { pn->pn_xflags |= PNX_FUNCDEFS; } else { /* * General deoptimization was done in functionDef, here we just * need to tell TOK_LC in Parser::statement to add braces. */ - JS_ASSERT_IF(pc->sc->isFunction, pc->sc->asFunbox()->hasExtensibleScope()); + JS_ASSERT_IF(pc->sc->isFunctionBox(), pc->sc->asFunctionBox()->hasExtensibleScope()); if (hasFunctionStmt) *hasFunctionStmt = true; } } pn->append(next); } /* @@ -2151,18 +2151,18 @@ BindVarOrConst(JSContext *cx, BindData * if (!CheckStrictBinding(cx, parser, name, pn)) return false; StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL); if (stmt && stmt->type == STMT_WITH) { pn->pn_dflags |= PND_DEOPTIMIZED; - if (pc->sc->isFunction) - pc->sc->asFunbox()->setMightAliasLocals(); + if (pc->sc->isFunctionBox()) + pc->sc->asFunctionBox()->setMightAliasLocals(); return true; } DefinitionList::Range defs = pc->decls().lookupMulti(name); JS_ASSERT_IF(stmt, !defs.empty()); if (defs.empty()) return pc->define(cx, name, pn, isConstDecl ? Definition::CONST : Definition::VAR); @@ -2523,34 +2523,34 @@ Parser::destructuringExpr(BindData *data } #endif /* JS_HAS_DESTRUCTURING */ ParseNode * Parser::returnOrYield(bool useAssignExpr) { TokenKind tt = tokenStream.currentToken().type; - if (!pc->sc->isFunction) { + if (!pc->sc->isFunctionBox()) { reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD, (tt == TOK_RETURN) ? js_return_str : js_yield_str); return NULL; } ParseNode *pn = UnaryNode::create((tt == TOK_RETURN) ? PNK_RETURN : PNK_YIELD, this); if (!pn) return NULL; #if JS_HAS_GENERATORS if (tt == TOK_YIELD) { /* * If we're within parens, we won't know if this is a generator expression until we see * a |for| token, so we have to delay flagging the current function. */ if (pc->parenDepth == 0) { - pc->sc->asFunbox()->setIsGenerator(); + pc->sc->asFunctionBox()->setIsGenerator(); } else { pc->yieldCount++; pc->yieldNode = pn; } } #endif /* This is ugly, but we don't want to require a semicolon. */ @@ -2577,17 +2577,17 @@ Parser::returnOrYield(bool useAssignExpr pn->pn_kid = pn2; } else { #if JS_HAS_GENERATORS if (tt == TOK_RETURN) #endif pc->funHasReturnVoid = true; } - if (pc->funHasReturnExpr && pc->sc->asFunbox()->isGenerator()) { + if (pc->funHasReturnExpr && pc->sc->asFunctionBox()->isGenerator()) { /* As in Python (see PEP-255), disallow return v; in generators. */ ReportBadReturn(context, this, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); return NULL; } if (context->hasStrictOption() && pc->funHasReturnExpr && pc->funHasReturnVoid && !ReportBadReturn(context, this, pn, &Parser::reportStrictWarning, @@ -4831,21 +4831,21 @@ GenexpGuard::checkValidBody(ParseNode *p * Call this after endBody() when determining that the body *was not* in a * generator expression. */ bool GenexpGuard::maybeNoteGenerator(ParseNode *pn) { ParseContext *pc = parser->pc; if (pc->yieldCount > 0) { - if (!pc->sc->isFunction) { + if (!pc->sc->isFunctionBox()) { parser->reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return false; } - pc->sc->asFunbox()->setIsGenerator(); + pc->sc->asFunctionBox()->setIsGenerator(); if (pc->funHasReturnExpr) { /* At the time we saw the yield, we might not have set isGenerator yet. */ ReportBadReturn(pc->sc->context, parser, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); return false; } } return true; @@ -5332,18 +5332,18 @@ Parser::generatorExpr(ParseNode *kid) /* * We assume conservatively that any deoptimization flags in pc->sc * come from the kid. So we propagate these flags into genfn. For code * simplicity we also do not detect if the flags were only set in the * kid and could be removed from pc->sc. */ genFunbox->anyCxFlags = outerpc->sc->anyCxFlags; - if (outerpc->sc->isFunction) - genFunbox->funCxFlags = outerpc->sc->asFunbox()->funCxFlags; + if (outerpc->sc->isFunctionBox()) + genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags; genFunbox->setIsGenerator(); genFunbox->inGenexpLambda = true; genfn->pn_funbox = genFunbox; genfn->pn_blockid = genpc.bodyid; ParseNode *body = comprehensionTail(pn, outerpc->blockid(), true); if (!body) @@ -5659,18 +5659,18 @@ Parser::memberExpr(bool allowCallSyntax) /* Select JSOP_EVAL and flag pc as heavyweight. */ nextMember->setOp(JSOP_EVAL); pc->sc->setBindingsAccessedDynamically(); /* * In non-strict mode code, direct calls to eval can add * variables to the call object. */ - if (pc->sc->isFunction && !pc->sc->strict) - pc->sc->asFunbox()->setHasExtensibleScope(); + if (pc->sc->isFunctionBox() && !pc->sc->strict) + pc->sc->asFunctionBox()->setHasExtensibleScope(); } } else if (lhs->isOp(JSOP_GETPROP)) { /* Select JSOP_FUNAPPLY given foo.apply(...). */ if (lhs->pn_atom == context->names().apply) nextMember->setOp(JSOP_FUNAPPLY); else if (lhs->pn_atom == context->names().call) nextMember->setOp(JSOP_FUNCALL); }
--- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -76,22 +76,22 @@ struct ParseContext /* t DeclVector vars_; /* var/const definitions */ public: const AtomDecls &decls() const { return decls_; } uint32_t numArgs() const { - JS_ASSERT(sc->isFunction); + JS_ASSERT(sc->isFunctionBox()); return args_.length(); } uint32_t numVars() const { - JS_ASSERT(sc->isFunction); + JS_ASSERT(sc->isFunctionBox()); return vars_.length(); } /* * This function adds a definition to the lexical scope represented by this * ParseContext. * * Pre-conditions:
--- a/js/src/frontend/SharedContext-inl.h +++ b/js/src/frontend/SharedContext-inl.h @@ -10,46 +10,45 @@ #include "frontend/Parser.h" #include "frontend/SharedContext.h" namespace js { namespace frontend { inline -SharedContext::SharedContext(JSContext *cx, bool isFun, bool strict) +SharedContext::SharedContext(JSContext *cx, bool strict) : context(cx), - isFunction(isFun), anyCxFlags(), strict(strict) { } inline bool SharedContext::needStrictChecks() { return context->hasStrictOption() || strict; } inline GlobalSharedContext * -SharedContext::asGlobal() +SharedContext::asGlobalSharedContext() { - JS_ASSERT(!isFunction); + JS_ASSERT(isGlobalSharedContext()); return static_cast<GlobalSharedContext*>(this); } inline FunctionBox * -SharedContext::asFunbox() +SharedContext::asFunctionBox() { - JS_ASSERT(isFunction); + JS_ASSERT(isFunctionBox()); return static_cast<FunctionBox*>(this); } GlobalSharedContext::GlobalSharedContext(JSContext *cx, JSObject *scopeChain, bool strict) - : SharedContext(cx, /* isFunction = */ false, strict), + : SharedContext(cx, strict), scopeChain_(cx, scopeChain) { } } /* namespace frontend */ template <class ContextT> void
--- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -132,30 +132,29 @@ class GlobalSharedContext; * The struct SharedContext is part of the current parser context (see * ParseContext). It stores information that is reused between the parser and * the bytecode emitter. Note however, that this information is not shared * between the two; they simply reuse the same data structure. */ class SharedContext { public: - JSContext *const context; - - const bool isFunction; /* true for function code, false for - global code */ + JSContext *const context; AnyContextFlags anyCxFlags; - bool strict; // If it's function code, funbox must be non-NULL and scopeChain must be NULL. // If it's global code, funbox must be NULL. - inline SharedContext(JSContext *cx, bool isFun, bool strict); + inline SharedContext(JSContext *cx, bool strict); - inline GlobalSharedContext *asGlobal(); - inline FunctionBox *asFunbox(); + virtual ObjectBox *toObjectBox() = 0; + inline bool isGlobalSharedContext() { return toObjectBox() == NULL; } + inline bool isFunctionBox() { return toObjectBox() && toObjectBox()->isFunctionBox(); } + inline GlobalSharedContext *asGlobalSharedContext(); + inline FunctionBox *asFunctionBox(); bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; } bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; } void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; } void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; } // JSOPTION_STRICT warnings or strict mode errors. @@ -165,16 +164,17 @@ class SharedContext class GlobalSharedContext : public SharedContext { private: const RootedObject scopeChain_; /* scope chain object for the script */ public: inline GlobalSharedContext(JSContext *cx, JSObject *scopeChain, bool strict); + ObjectBox *toObjectBox() { return NULL; } JSObject *scopeChain() const { return scopeChain_; } }; class FunctionBox : public ObjectBox, public SharedContext { public: Bindings bindings; /* bindings for this function */ size_t bufStart; @@ -184,16 +184,17 @@ class FunctionBox : public ObjectBox, pu or E4X filter-expression */ bool inGenexpLambda:1; /* lambda from generator expression */ FunctionContextFlags funCxFlags; FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, ParseContext *pc, bool strict); + ObjectBox *toObjectBox() { return this; } JSFunction *function() const { return object->toFunction(); } bool isGenerator() const { return funCxFlags.isGenerator; } bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; } bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; } bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; } bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1745,17 +1745,17 @@ JSScript::fullyInitFromEmitter(JSContext bce->objectList.length, bce->regexpList.length, bce->tryNoteList.length(), bce->constList.length(), bce->typesetCount)) return false; JS_ASSERT(script->mainOffset == 0); script->mainOffset = prologLength; PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength); PodCopy<jsbytecode>(script->main(), bce->base(), mainLength); - uint32_t nfixed = bce->sc->isFunction ? script->bindings.numVars() : 0; + uint32_t nfixed = bce->sc->isFunctionBox() ? script->bindings.numVars() : 0; JS_ASSERT(nfixed < SLOTNO_LIMIT); script->nfixed = uint16_t(nfixed); InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms); const char *filename = bce->parser->tokenStream.getFilename(); if (filename) { script->filename = SaveScriptFilename(cx, filename); if (!script->filename) @@ -1763,17 +1763,17 @@ JSScript::fullyInitFromEmitter(JSContext } script->lineno = bce->firstLine; if (script->nfixed + bce->maxStackDepth >= JS_BIT(16)) { bce->reportError(NULL, JSMSG_NEED_DIET, "script"); return false; } script->nslots = script->nfixed + bce->maxStackDepth; - FunctionBox *funbox = bce->sc->isFunction ? bce->sc->asFunbox() : NULL; + FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : NULL; if (!FinishTakingSrcNotes(cx, bce, script->notes())) return false; if (bce->tryNoteList.length() != 0) bce->tryNoteList.finish(script->trynotes()); if (bce->objectList.length != 0) bce->objectList.finish(script->objects()); if (bce->regexpList.length != 0)