Bug 589199 - Fix eval static scope to play with the global lexical scope. (r=efaust)

This commit is contained in:
Shu-yu Guo 2015-10-06 14:00:29 -07:00
Родитель e168c18e3b
Коммит df3a5245f4
11 изменённых файлов: 44 добавлений и 31 удалений

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

@ -229,7 +229,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
{
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !caller);
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !pc);
MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is<GlobalObject>());
MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, IsGlobalLexicalScope(scopeobj));
AssertInnerizedScopeChain(cx, *scopeobj);
Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global());
@ -271,7 +271,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
return false;
thisv = caller.thisValue();
} else {
MOZ_ASSERT(args.callee().global() == *scopeobj);
MOZ_ASSERT(args.callee().global() == scopeobj->as<ClonedBlockObject>().global());
// Use the global as 'this', modulo outerization.
JSObject* thisobj = GetThisObject(cx, scopeobj);
@ -313,6 +313,8 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
RootedObject enclosing(cx);
if (evalType == DIRECT_EVAL)
enclosing = callerScript->innermostStaticScope(pc);
else
enclosing = &cx->global()->lexicalScope().staticBlock();
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, enclosing));
if (!staticScope)
return false;
@ -454,7 +456,8 @@ js::IndirectEval(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, &args.callee().global());
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global, nullptr);
RootedObject globalLexical(cx, &global->lexicalScope());
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), globalLexical, nullptr);
}
bool

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

@ -287,8 +287,11 @@ BytecodeCompiler::isEvalCompilationUnit()
bool
BytecodeCompiler::isNonGlobalEvalCompilationUnit()
{
return isEvalCompilationUnit() &&
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
if (!isEvalCompilationUnit())
return false;
StaticEvalObject& eval = enclosingStaticScope->as<StaticEvalObject>();
JSObject* enclosing = eval.enclosingScopeForStaticScopeIter();
return !IsStaticGlobalLexicalScope(enclosing);
}
bool

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

@ -1537,9 +1537,14 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
FunctionBox* funbox = sc->asFunctionBox();
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;
// Don't optimize names through non-global eval. For global eval
// we can use GNAME ops.
if (ssi.type() == StaticScopeIter<NoGC>::Eval) {
if (ssi.eval().isNonGlobal())
return false;
MOZ_ASSERT(!slot.isSome());
break;
}
if (!ssi.hasSyntacticDynamicScopeObject())
continue;

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

@ -50,16 +50,14 @@ setLazyParsingDisabled(false);
eval("function h() { assertEq(x, 'inner');} h()");
eval("function h2() { (function nest() { assertEq(x, 'inner'); })(); } h2()");
}
// It sure would be nice if we could run the h3/h4 tests below, but it turns out
// that lazy functions and eval don't play together all that well. See bug
// 1146080. For now, assert we have no gname, so people will notice if they
// accidentally fix it and adjust this test accordingly.
// GNAME optimizations should work through lazy parsing.
eval(`
function h3() {
assertEq(x, 'outer');
}
h3();
hasGname(h3, 'x', false);
hasGname(h3, 'x', true);
`);
eval(`
function h4() {
@ -67,7 +65,7 @@ eval(`
nest();
return nest;
}
hasGname(h4(), 'x', false);
hasGname(h4(), 'x', true);
`);
setLazyParsingDisabled(true);

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

@ -88,10 +88,10 @@ BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator)
}
bool
BaselineFrame::isDirectEvalFrame() const
BaselineFrame::isNonGlobalEvalFrame() const
{
return isEvalFrame() &&
script()->enclosingStaticScope()->as<StaticEvalObject>().isDirect();
script()->enclosingStaticScope()->as<StaticEvalObject>().isNonGlobal();
}
bool

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

@ -408,9 +408,9 @@ class BaselineFrame
bool isNonStrictEvalFrame() const {
return isEvalFrame() && !script()->strict();
}
bool isDirectEvalFrame() const;
bool isNonGlobalEvalFrame() const;
bool isNonStrictDirectEvalFrame() const {
return isNonStrictEvalFrame() && isDirectEvalFrame();
return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
}
bool isNonEvalFunctionFrame() const {
return isFunctionFrame() && !isEvalFrame();

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

@ -3486,7 +3486,7 @@ IsFunctionCloneable(HandleFunction fun)
// If the script is an indirect eval that is immediately scoped
// under the global, we can clone it.
if (enclosing->is<StaticEvalObject>())
return !enclosing->as<StaticEvalObject>().isDirect();
return !enclosing->as<StaticEvalObject>().isNonGlobal();
// If the script already deals with a non-syntactic scope, we can
// clone it.

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

@ -3309,7 +3309,8 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
RootedObject enclosingScope(cx);
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) {
if (IsStaticGlobalLexicalScope(enclosingBlock)) {
MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope));
MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope) ||
scriptStaticScope->is<StaticNonSyntacticScopeObjects>());
enclosingScope = scriptStaticScope;
} else {
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];

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

@ -456,12 +456,7 @@ class StaticEvalObject : public ScopeObject
return getReservedSlot(STRICT_SLOT).isTrue();
}
// Indirect evals terminate in the global at run time, and has no static
// enclosing scope.
bool isDirect() const {
MOZ_ASSERT_IF(!getReservedSlot(SCOPE_CHAIN_SLOT).isObject(), !isStrict());
return getReservedSlot(SCOPE_CHAIN_SLOT).isObject();
}
inline bool isNonGlobal() const;
};
// Static scope objects that stand in for one or more "polluting global"
@ -1215,6 +1210,14 @@ NestedScopeObject::enclosingNestedScope() const
return obj && obj->is<NestedScopeObject>() ? &obj->as<NestedScopeObject>() : nullptr;
}
inline bool
StaticEvalObject::isNonGlobal() const
{
if (isStrict())
return true;
return !IsStaticGlobalLexicalScope(&getReservedSlot(SCOPE_CHAIN_SLOT).toObject());
}
inline bool
ScopeIter::done() const
{

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

@ -109,10 +109,10 @@ InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractF
}
bool
InterpreterFrame::isDirectEvalFrame() const
InterpreterFrame::isNonGlobalEvalFrame() const
{
return isEvalFrame() &&
script()->enclosingStaticScope()->as<StaticEvalObject>().isDirect();
script()->enclosingStaticScope()->as<StaticEvalObject>().isNonGlobal();
}
bool
@ -259,7 +259,7 @@ InterpreterFrame::epilogue(JSContext* cx)
MOZ_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
DebugScopes::onPopStrictEvalScope(this);
} else if (isDirectEvalFrame()) {
} else if (isNonGlobalEvalFrame()) {
MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain()));
}
return;

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

@ -515,10 +515,10 @@ class InterpreterFrame
return isEvalFrame() && !script()->strict();
}
bool isDirectEvalFrame() const;
bool isNonGlobalEvalFrame() const;
bool isNonStrictDirectEvalFrame() const {
return isNonStrictEvalFrame() && isDirectEvalFrame();
return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
}
/*