Bug 1193606 - Clean up LazyFunction case of tryConvertFreeName and remove directlyInEval. (r=bhackett)

This commit is contained in:
Shu-yu Guo 2015-08-19 12:02:32 -07:00
Родитель 9cbf164447
Коммит df4b17486d
7 изменённых файлов: 73 добавлений и 99 удалений

Просмотреть файл

@ -87,7 +87,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool maybeSetSourceMapFromOptions();
bool emitFinalReturn();
bool initGlobalBindings(ParseContext<FullParseHandler>& pc);
void markFunctionsWithinEvalScript();
bool maybeCompleteCompressSource();
AutoCompilationTraceLogger traceLogger;
@ -519,29 +518,6 @@ BytecodeCompiler::initGlobalBindings(ParseContext<FullParseHandler>& pc)
return true;
}
void
BytecodeCompiler::markFunctionsWithinEvalScript()
{
// Mark top level functions in an eval script as being within an eval.
if (!script->hasObjects())
return;
ObjectArray* objects = script->objects();
size_t start = script->innerObjectsStart();
for (size_t i = start; i < objects->length; i++) {
JSObject* obj = objects->vector[i];
if (obj->is<JSFunction>()) {
JSFunction* fun = &obj->as<JSFunction>();
if (fun->hasScript())
fun->nonLazyScript()->setDirectlyInsideEval();
else if (fun->isInterpretedLazy())
fun->lazyScript()->setDirectlyInsideEval();
}
}
}
bool
BytecodeCompiler::maybeCompleteCompressSource()
{
@ -621,12 +597,6 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller
return nullptr;
}
// Note that this marking must happen before we tell Debugger
// about the new script, in case Debugger delazifies the script's
// inner functions.
if (options.forEval)
markFunctionsWithinEvalScript();
emitter->tellDebuggerAboutCompiledScript(cx);
if (!maybeCompleteCompressSource())
@ -790,8 +760,6 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
script->bindings = pn->pn_funbox->bindings;
if (lazy->directlyInsideEval())
script->setDirectlyInsideEval();
if (lazy->usesArgumentsApplyAndThis())
script->setUsesArgumentsApplyAndThis();
if (lazy->hasBeenCloned())

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
@ -48,6 +49,8 @@ using namespace js;
using namespace js::gc;
using namespace js::frontend;
using mozilla::Maybe;
using mozilla::Some;
using mozilla::DebugOnly;
using mozilla::NumberIsInt32;
using mozilla::PodCopy;
@ -1502,58 +1505,66 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
return true;
}
size_t hops = 0;
// Walk the static scope chain and look for an aliased binding with
// the name pn->pn_atom.
uint32_t hops = 0;
Maybe<uint32_t> slot;
FunctionBox* funbox = sc->asFunctionBox();
if (funbox->hasExtensibleScope())
PropertyName* name = pn->pn_atom->asPropertyName();
for (StaticScopeIter<NoGC> ssi(funbox->staticScope()); !ssi.done(); ssi++) {
// Don't optimize names through eval.
if (ssi.type() == StaticScopeIter<NoGC>::Eval)
return false;
if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom)
return false;
if (funbox->isHeavyweight()) {
hops++;
if (funbox->function()->isNamedLambda())
hops++;
}
if (script->directlyInsideEval())
return false;
RootedObject outerScope(cx, script->enclosingStaticScope());
for (StaticScopeIter<CanGC> ssi(cx, outerScope); !ssi.done(); ssi++) {
if (ssi.type() != StaticScopeIter<CanGC>::Function) {
if (ssi.type() == StaticScopeIter<CanGC>::Block) {
// Use generic ops if a catch block is encountered.
return false;
}
if (ssi.hasSyntacticDynamicScopeObject())
hops++;
if (!ssi.hasSyntacticDynamicScopeObject())
continue;
}
RootedScript script(cx, ssi.funScript());
if (script->functionNonDelazifying()->atom() == pn->pn_atom)
// Look up for name in function and block scopes.
if (ssi.type() == StaticScopeIter<NoGC>::Function) {
RootedScript funScript(cx, ssi.funScript());
if (funScript->funHasExtensibleScope() || ssi.fun().atom() == pn->pn_atom)
return false;
if (ssi.hasSyntacticDynamicScopeObject()) {
uint32_t slot;
if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) {
// Skip the current function, since we're trying to convert a
// free name.
if (script != funScript) {
uint32_t slot_;
if (lookupAliasedName(funScript, name, &slot_, pn)) {
slot = Some(slot_);
break;
}
}
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
RootedShape shape(cx, ssi.block().lookupAliasedName(name));
if (shape) {
// Don't optimize setting a 'const' binding. Let the slow
// path do the error checking.
if (!shape->writable() && pn->getOp() == JSOP_SETNAME)
return false;
slot = Some(shape->slot());
pn->pn_dflags |= PND_LEXICAL;
break;
}
} else {
MOZ_ASSERT(ssi.type() != StaticScopeIter<NoGC>::With);
}
hops++;
}
// If we found a scope binding name, convert the name op to an aliased
// var op.
if (slot.isSome()) {
JSOp op;
switch (pn->getOp()) {
case JSOP_GETNAME: op = JSOP_GETALIASEDVAR; break;
case JSOP_SETNAME: op = JSOP_SETALIASEDVAR; break;
default: return false;
}
pn->setOp(op);
MOZ_ALWAYS_TRUE(pn->pn_scopecoord.set(parser->tokenStream, hops, slot));
MOZ_ALWAYS_TRUE(pn->pn_scopecoord.set(parser->tokenStream, hops, *slot));
return true;
}
hops++;
}
// If this walk up and check for directlyInsideEval is ever removed,
// we'll need to adjust CompileLazyFunction to better communicate
// whether we're inside eval to the BytecodeEmitter. For now, this
// walk is why CompileLazyFunction can claim that it's never inside
// eval.
if (script->funHasExtensibleScope() || script->directlyInsideEval())
return false;
}
}
// Unbound names aren't recognizable global-property references if the

Просмотреть файл

@ -3968,7 +3968,6 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
p.bindingsAccessedDynamically = false;
p.hasDebuggerStatement = false;
p.hasDirectEval = false;
p.directlyInsideEval = false;
p.usesArgumentsApplyAndThis = false;
p.isDerivedClassConstructor = false;

Просмотреть файл

@ -1098,9 +1098,6 @@ class JSScript : public js::gc::TenuredCell
// Script came from eval(), and is in eval cache.
bool isCachedEval_:1;
// Set for functions defined at the top level within an 'eval' script.
bool directlyInsideEval_:1;
// 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper.
bool usesArgumentsApplyAndThis_:1;
@ -1334,7 +1331,6 @@ class JSScript : public js::gc::TenuredCell
bool isActiveEval() const { return isActiveEval_; }
bool isCachedEval() const { return isCachedEval_; }
bool directlyInsideEval() const { return directlyInsideEval_; }
void cacheForEval() {
MOZ_ASSERT(isActiveEval() && !isCachedEval());
@ -1353,7 +1349,6 @@ class JSScript : public js::gc::TenuredCell
}
void setActiveEval() { isActiveEval_ = true; }
void setDirectlyInsideEval() { directlyInsideEval_ = true; }
bool usesArgumentsApplyAndThis() const {
return usesArgumentsApplyAndThis_;
@ -2064,7 +2059,6 @@ class LazyScript : public gc::TenuredCell
uint32_t bindingsAccessedDynamically : 1;
uint32_t hasDebuggerStatement : 1;
uint32_t hasDirectEval : 1;
uint32_t directlyInsideEval : 1;
uint32_t usesArgumentsApplyAndThis : 1;
uint32_t hasBeenCloned : 1;
uint32_t treatAsRunOnce : 1;
@ -2213,13 +2207,6 @@ class LazyScript : public gc::TenuredCell
p_.hasDirectEval = true;
}
bool directlyInsideEval() const {
return p_.directlyInsideEval;
}
void setDirectlyInsideEval() {
p_.directlyInsideEval = true;
}
bool usesArgumentsApplyAndThis() const {
return p_.usesArgumentsApplyAndThis;
}

Просмотреть файл

@ -70,13 +70,6 @@ CallObject::initAliasedLexicalsToThrowOnTouch(JSScript* script)
initRemainingSlotsToUninitializedLexicals(script->bindings.aliasedBodyLevelLexicalBegin());
}
template <AllowGC allowGC>
inline bool
StaticScopeIter<allowGC>::done() const
{
return !obj;
}
template <AllowGC allowGC>
inline void
StaticScopeIter<allowGC>::operator++(int)

Просмотреть файл

@ -687,6 +687,19 @@ StaticBlockObject::create(ExclusiveContext* cx)
return NewObjectWithNullTaggedProto<StaticBlockObject>(cx, TenuredObject, BaseShape::DELEGATE);
}
Shape*
StaticBlockObject::lookupAliasedName(PropertyName* name)
{
Shape::Range<NoGC> r(lastProperty());
while (!r.empty()) {
jsid id = r.front().propidRaw();
if (JSID_TO_ATOM(id)->asPropertyName() == name && isAliased(shapeToIndex(r.front())))
return &r.front();
r.popFront();
}
return nullptr;
}
/* static */ Shape*
StaticBlockObject::addVar(ExclusiveContext* cx, Handle<StaticBlockObject*> block, HandleId id,
bool constant, unsigned index, bool* redeclared)

Просмотреть файл

@ -114,7 +114,7 @@ class StaticScopeIter
"used in NoGC code");
}
bool done() const;
bool done() const { return !obj; }
void operator++(int);
JSObject* staticScope() const { MOZ_ASSERT(!done()); return obj; }
@ -653,6 +653,9 @@ class StaticBlockObject : public BlockObject
return slotValue(i).isTrue();
}
// Look up if the block has an aliased binding named |name|.
Shape* lookupAliasedName(PropertyName* name);
/*
* A static block object is cloned (when entering the block) iff some
* variable of the block isAliased.