Bug 885522 - Move function heavyweight info to JSScript, r=luke.

This commit is contained in:
Brian Hackett 2013-06-20 18:37:45 -06:00
parent f80974aecb
commit 9beb9a61fc
9 changed files with 58 additions and 50 deletions

View File

@ -853,10 +853,10 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
*/
for (unsigned i = pn->pn_cookie.level(); i; i--) {
skippedScopes += ClonedBlockDepth(bceOfDef);
JSFunction *funOfDef = bceOfDef->sc->asFunctionBox()->function();
if (funOfDef->isHeavyweight()) {
FunctionBox *funbox = bceOfDef->sc->asFunctionBox();
if (funbox->isHeavyweight()) {
skippedScopes++;
if (funOfDef->isNamedLambda())
if (funbox->function()->isNamedLambda())
skippedScopes++;
}
bceOfDef = bceOfDef->parent;
@ -1136,7 +1136,7 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn)
return false;
if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom)
return false;
if (funbox->function()->isHeavyweight()) {
if (funbox->isHeavyweight()) {
hops++;
if (funbox->function()->isNamedLambda())
hops++;
@ -1389,7 +1389,7 @@ BindNameToSlotHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (dn->pn_cookie.level() != bce->script->staticLevel)
return true;
RootedFunction fun(cx, bce->sc->asFunctionBox()->function());
DebugOnly<JSFunction *> fun = bce->sc->asFunctionBox()->function();
JS_ASSERT(fun->isLambda());
JS_ASSERT(pn->pn_atom == fun->atom());
@ -1417,7 +1417,7 @@ BindNameToSlotHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* heavyweight, ensuring that the function name is represented in
* the scope chain so that assignment will throw a TypeError.
*/
if (!fun->isHeavyweight()) {
if (!bce->sc->asFunctionBox()->isHeavyweight()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
@ -2624,7 +2624,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *
}
if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
(!bce->sc->isFunctionBox() || bce->sc->asFunctionBox()->function()->isHeavyweight()))
(!bce->sc->isFunctionBox() || bce->sc->asFunctionBox()->isHeavyweight()))
{
bce->switchToProlog();
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))

View File

@ -311,17 +311,8 @@ ParseContext<ParseHandler>::generateFunctionBindings(JSContext *cx, InternalHand
AppendPackedBindings(this, args_, packedBindings);
AppendPackedBindings(this, vars_, packedBindings + args_.length());
if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
packedBindings))
{
return false;
}
FunctionBox *funbox = sc->asFunctionBox();
if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope())
funbox->function()->setIsHeavyweight();
return true;
return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
packedBindings);
}
template <typename ParseHandler>
@ -1279,7 +1270,7 @@ ConvertDefinitionToNamedLambdaUse(JSContext *cx, ParseContext<FullParseHandler>
* produce an error (in strict mode).
*/
if (dn->isClosed() || dn->isAssigned())
funbox->function()->setIsHeavyweight();
funbox->setNeedsDeclEnvObject();
return true;
}

View File

@ -74,11 +74,11 @@ class FunctionContextFlags
friend class FunctionBox;
// We parsed a yield statement in the function.
bool isGenerator:1;
bool isGenerator:1;
// The function or a function that encloses it may define new local names
// at runtime through means other than calling eval.
bool mightAliasLocals:1;
bool mightAliasLocals:1;
// This function does something that can extend the set of bindings in its
// call objects --- it does a direct eval in non-strict code, or includes a
@ -87,7 +87,11 @@ class FunctionContextFlags
// This flag is *not* inherited by enclosed or enclosing functions; it
// applies only to the function in whose flags it appears.
//
bool hasExtensibleScope:1;
bool hasExtensibleScope:1;
// This function refers directly to its name in a way which requires the
// name to be a separate object on the scope chain.
bool needsDeclEnvObject:1;
// Technically, every function has a binding named 'arguments'. Internally,
// this binding is only added when 'arguments' is mentioned by the function
@ -110,7 +114,7 @@ class FunctionContextFlags
// have no special semantics: the initial value is unconditionally the
// actual argument (or undefined if nactual < nformal).
//
bool argumentsHasLocalBinding:1;
bool argumentsHasLocalBinding:1;
// In many cases where 'arguments' has a local binding (as described above)
// we do not need to actually create an arguments object in the function
@ -121,13 +125,14 @@ class FunctionContextFlags
// be unsound in several cases. The frontend filters out such cases by
// setting this flag which eagerly sets script->needsArgsObj to true.
//
bool definitelyNeedsArgsObj:1;
bool definitelyNeedsArgsObj:1;
public:
FunctionContextFlags()
: isGenerator(false),
mightAliasLocals(false),
hasExtensibleScope(false),
needsDeclEnvObject(false),
argumentsHasLocalBinding(false),
definitelyNeedsArgsObj(false)
{ }
@ -226,12 +231,14 @@ class FunctionBox : public ObjectBox, public SharedContext
bool isGenerator() const { return funCxFlags.isGenerator; }
bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; }
bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
bool needsDeclEnvObject() const { return funCxFlags.needsDeclEnvObject; }
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
void setIsGenerator() { funCxFlags.isGenerator = true; }
void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
void setNeedsDeclEnvObject() { funCxFlags.needsDeclEnvObject = true; }
void setArgumentsHasLocalBinding() { funCxFlags.argumentsHasLocalBinding = true; }
void setDefinitelyNeedsArgsObj() { JS_ASSERT(funCxFlags.argumentsHasLocalBinding);
funCxFlags.definitelyNeedsArgsObj = true; }
@ -247,6 +254,14 @@ class FunctionBox : public ObjectBox, public SharedContext
startLine = tokenStream.getLineno();
startColumn = tokenStream.getColumn();
}
bool isHeavyweight()
{
// Note: this should be kept in sync with JSFunction::isHeavyweight().
return bindings.hasAnyAliasedBindings() ||
hasExtensibleScope() ||
needsDeclEnvObject();
}
};
inline FunctionBox *

View File

@ -1063,14 +1063,6 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
if (JSScript *script = lazy->maybeScript()) {
fun->initScript(script);
/*
* Set some bits that are normally filled in by the Parser after
* the full parse tree has been produced.
*/
if (script->function()->isHeavyweight())
fun->setIsHeavyweight();
fun->nargs = script->function()->nargs;
return true;
}

View File

@ -23,7 +23,6 @@ class JSFunction : public JSObject
INTERPRETED = 0x0001, /* function has a JSScript and environment. */
NATIVE_CTOR = 0x0002, /* native that can be called as a constructor */
EXTENDED = 0x0004, /* structure is FunctionExtended */
HEAVYWEIGHT = 0x0008, /* activation requires a Call object */
IS_FUN_PROTO = 0x0010, /* function is Function.prototype for some global object */
EXPR_CLOSURE = 0x0020, /* expression closure: function(x) x*x */
HAS_GUESSED_ATOM = 0x0040, /* function had no explicit name, but a
@ -80,11 +79,8 @@ class JSFunction : public JSObject
public:
bool isHeavyweight() {
/* The heavyweight flag is not set until the script is parsed. */
JS_ASSERT(!isInterpretedLazy());
return flags & HEAVYWEIGHT;
}
/* Call objects must be created for each invocation of a heavyweight function. */
inline bool isHeavyweight() const;
/* A function can be classified as either native (C++) or interpreted (JS): */
bool isInterpreted() const { return flags & (INTERPRETED | INTERPRETED_LAZY); }
@ -173,10 +169,6 @@ class JSFunction : public JSObject
flags |= IS_FUN_PROTO;
}
void setIsHeavyweight() {
flags |= HEAVYWEIGHT;
}
// Can be called multiple times by the parser.
void setIsExprClosure() {
flags |= EXPR_CLOSURE;

View File

@ -223,6 +223,20 @@ CloneFunctionObjectIfNotSingleton(JSContext *cx, HandleFunction fun, HandleObjec
} /* namespace js */
inline bool
JSFunction::isHeavyweight() const
{
JS_ASSERT(!isInterpretedLazy());
if (isNative())
return false;
// Note: this should be kept in sync with FunctionBox::isHeavyweight().
return nonLazyScript()->bindings.hasAnyAliasedBindings() ||
nonLazyScript()->funHasExtensibleScope ||
nonLazyScript()->funNeedsDeclEnvObject;
}
inline JSScript *
JSFunction::existingScript()
{
@ -238,10 +252,6 @@ JSFunction::existingScript()
flags &= ~INTERPRETED_LAZY;
flags |= INTERPRETED;
initScript(script);
if (script->function()->isHeavyweight())
setIsHeavyweight();
nargs = script->function()->nargs;
}
JS_ASSERT(hasScript());
return u.i.s.script_;

View File

@ -396,6 +396,7 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
Strict,
ContainsDynamicNameAccess,
FunHasExtensibleScope,
FunNeedsDeclEnvObject,
FunHasAnyAliasedFormal,
ArgumentsHasVarBinding,
NeedsArgsObj,
@ -477,6 +478,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
scriptBits |= (1 << ContainsDynamicNameAccess);
if (script->funHasExtensibleScope)
scriptBits |= (1 << FunHasExtensibleScope);
if (script->funNeedsDeclEnvObject)
scriptBits |= (1 << FunNeedsDeclEnvObject);
if (script->funHasAnyAliasedFormal)
scriptBits |= (1 << FunHasAnyAliasedFormal);
if (script->argumentsHasVarBinding())
@ -576,6 +579,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
script->bindingsAccessedDynamically = true;
if (scriptBits & (1 << FunHasExtensibleScope))
script->funHasExtensibleScope = true;
if (scriptBits & (1 << FunNeedsDeclEnvObject))
script->funNeedsDeclEnvObject = true;
if (scriptBits & (1 << FunHasAnyAliasedFormal))
script->funHasAnyAliasedFormal = true;
if (scriptBits & (1 << ArgumentsHasVarBinding))
@ -1894,6 +1899,7 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle<JSScript*> script, Bytecode
script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
script->funHasExtensibleScope = funbox ? funbox->hasExtensibleScope() : false;
script->funNeedsDeclEnvObject = funbox ? funbox->needsDeclEnvObject() : false;
script->hasSingletons = bce->hasSingletons;
if (funbox) {
@ -2408,6 +2414,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
dst->explicitUseStrict = src->explicitUseStrict;
dst->bindingsAccessedDynamically = src->bindingsAccessedDynamically;
dst->funHasExtensibleScope = src->funHasExtensibleScope;
dst->funNeedsDeclEnvObject = src->funNeedsDeclEnvObject;
dst->funHasAnyAliasedFormal = src->funHasAnyAliasedFormal;
dst->hasSingletons = src->hasSingletons;
dst->isGenerator = src->isGenerator;

View File

@ -205,7 +205,7 @@ class Bindings
bool bindingIsAliased(unsigned bindingIndex);
/* Return whether this scope has any aliased bindings. */
bool hasAnyAliasedBindings() const { return !callObjShape_->isEmptyShape(); }
bool hasAnyAliasedBindings() const { return callObjShape_ && !callObjShape_->isEmptyShape(); }
void trace(JSTracer *trc);
};
@ -525,8 +525,9 @@ class JSScript : public js::gc::Cell
bool explicitUseStrict:1; /* code has "use strict"; explicitly */
bool compileAndGo:1; /* see Parser::compileAndGo */
bool selfHosted:1; /* see Parser::selfHostingMode */
bool bindingsAccessedDynamically:1; /* see ContextFlags' field of the same name */
bool funHasExtensibleScope:1; /* see ContextFlags' field of the same name */
bool bindingsAccessedDynamically:1; /* see FunctionContextFlags */
bool funHasExtensibleScope:1; /* see FunctionContextFlags */
bool funNeedsDeclEnvObject:1; /* see FunctionContextFlags */
bool funHasAnyAliasedFormal:1; /* true if any formalIsAliased(i) */
bool warnedAboutTwoArgumentEval:1; /* have warned about use of
obsolete eval(s, o) in

View File

@ -26,7 +26,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be
* invalidated if possible.
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 147);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 148);
class XDRBuffer {
public: