diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 5a5394ef254..357a460eebc 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -212,18 +212,6 @@ TryEvalJSON(JSContext* cx, JSLinearString* str, MutableHandleValue rval) : ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval); } -static bool -HasPollutedScopeChain(JSObject* scopeChain) -{ - while (scopeChain) { - if (scopeChain->is()) - return true; - scopeChain = scopeChain->enclosingScope(); - } - - return false; -} - // Define subset of ExecuteType so that casting performs the injection. enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL }; @@ -326,13 +314,8 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame if (!staticScope) return false; - bool hasPollutedGlobalScope = - HasPollutedScopeChain(scopeobj) || - (evalType == DIRECT_EVAL && callerScript->hasPollutedGlobalScope()); - CompileOptions options(cx); options.setFileAndLine(filename, 1) - .setHasPollutedScope(hasPollutedGlobalScope) .setIsRunOnce(true) .setForEval(true) .setNoScriptRval(false) @@ -404,7 +387,7 @@ js::DirectEvalStringFromIon(JSContext* cx, bool mutedErrors; uint32_t pcOffset; DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset, - &mutedErrors, CALLED_FROM_JSOP_EVAL); + &mutedErrors, CALLED_FROM_JSOP_EVAL); const char* introducerFilename = filename; if (maybeScript && maybeScript->scriptSource()->introducerFilename()) @@ -417,8 +400,6 @@ js::DirectEvalStringFromIon(JSContext* cx, CompileOptions options(cx); options.setFileAndLine(filename, 1) - .setHasPollutedScope(HasPollutedScopeChain(scopeobj) || - callerScript->hasPollutedGlobalScope()) .setIsRunOnce(true) .setForEval(true) .setNoScriptRval(false) @@ -511,7 +492,10 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri RootedScript script(cx, scriptArg); if (script->compartment() != cx->compartment()) { - script = CloneScript(cx, nullptr, nullptr, script); + Rooted staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr)); + if (!staticScope) + return false; + script = CloneGlobalScript(cx, staticScope, script); if (!script) return false; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index ff0038358a7..9c1ff3986e8 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2272,11 +2272,10 @@ EvalReturningScope(JSContext* cx, unsigned argc, jsval* vp) JS::CompileOptions options(cx); options.setFileAndLine(filename.get(), lineno); options.setNoScriptRval(true); - options.setHasPollutedScope(true); JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership); RootedScript script(cx); - if (!JS::Compile(cx, options, srcBuf, &script)) + if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) return false; if (global) { diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index b811080b704..bf7d97e0051 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -144,10 +144,11 @@ MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, Ha } static inline bool -CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options) +CanLazilyParse(ExclusiveContext* cx, HandleObject staticScope, + const ReadOnlyCompileOptions& options) { return options.canLazilyParse && - !options.hasPollutedGlobalScope && + !HasNonSyntacticStaticScopeChain(staticScope) && !cx->compartment()->options().disableLazyParsing() && !cx->compartment()->options().discardSource() && !options.sourceIsLazy; @@ -260,7 +261,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco return nullptr; } - bool canLazilyParse = CanLazilyParse(cx, options); + bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); Maybe > syntaxParser; if (canLazilyParse) { @@ -561,7 +562,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp return false; } - bool canLazilyParse = CanLazilyParse(cx, options); + bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); Maybe > syntaxParser; if (canLazilyParse) { diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 02fffe550b5..e4816fc5423 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3406,6 +3406,19 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body) */ FunctionBox* funbox = sc->asFunctionBox(); + + // Link the function and the script to each other, so that StaticScopeIter + // may walk the scope chain of currently compiling scripts. + RootedFunction fun(cx, funbox->function()); + MOZ_ASSERT(fun->isInterpreted()); + + script->setFunction(fun); + + if (fun->isInterpretedLazy()) + fun->setUnlazifiedScript(script); + else + fun->setScript(script); + if (funbox->argumentsHasLocalBinding()) { MOZ_ASSERT(offset() == 0); /* See JSScript::argumentsBytecode. */ switchToPrologue(); @@ -3509,15 +3522,6 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body) MOZ_ASSERT(!script->hasRunOnce()); } - /* Initialize fun->script() so that the debugger has a valid fun->script(). */ - RootedFunction fun(cx, script->functionNonDelazifying()); - MOZ_ASSERT(fun->isInterpreted()); - - if (fun->isInterpretedLazy()) - fun->setUnlazifiedScript(script); - else - fun->setScript(script); - tellDebuggerAboutCompiledScript(cx); return true; @@ -5765,8 +5769,6 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted parent(cx, script); CompileOptions options(cx, parser->options()); options.setMutedErrors(parent->mutedErrors()) - .setHasPollutedScope(parent->hasPollutedGlobalScope()) - .setSelfHostingMode(parent->selfHosted()) .setNoScriptRval(false) .setForEval(false) .setVersion(parent->getVersion()); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 06d0fdcc790..87580e9c8de 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3283,12 +3283,22 @@ JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id } static bool -CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, - MutableHandleObject dynamicScopeObj, - MutableHandleObject staticScopeObj) +CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, + MutableHandleObject dynamicScopeObj, + MutableHandle staticScopeObj) { - return js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(), - dynamicScopeObj, staticScopeObj); + if (!js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(), dynamicScopeObj)) + return false; + + if (scopeChain.empty()) { + staticScopeObj.set(nullptr); + } else { + staticScopeObj.set(StaticNonSyntacticScopeObjects::create(cx, nullptr)); + if (!staticScopeObj) + return false; + } + + return true; } static bool @@ -3837,9 +3847,10 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version) asmJSOption = cx->runtime()->options().asmJS(); } -bool -JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, MutableHandleScript script) +static bool +Compile(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, Handle topStaticScope, + MutableHandleScript script) { MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); AssertHeapIsIdle(cx); @@ -3847,10 +3858,27 @@ JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, AutoLastFrameCheck lfc(cx); script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), cx->global(), - nullptr, nullptr, options, srcBuf)); + topStaticScope, nullptr, options, srcBuf)); return !!script; } +bool +JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, MutableHandleScript script) +{ + Rooted staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr)); + if (!staticScope) + return false; + return ::Compile(cx, options, srcBuf, staticScope, script); +} + +bool +JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, MutableHandleScript script) +{ + return ::Compile(cx, options, srcBuf, nullptr, script); +} + bool JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, MutableHandleScript script) @@ -4077,14 +4105,17 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, if (!fun) return false; - // Make sure to handle cases when we have a polluted scopechain. - CompileOptions options(cx, optionsArg); - if (!enclosingDynamicScope->is()) - options.setHasPollutedScope(true); + // Make sure the static scope chain matches up when we have a + // non-syntactic scope. + MOZ_ASSERT_IF(!enclosingDynamicScope->is(), + HasNonSyntacticStaticScopeChain(enclosingStaticScope)); + CompileOptions options(cx, optionsArg); if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope)) + { return false; + } return true; } @@ -4096,8 +4127,8 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, SourceBufferHolder& srcBuf, MutableHandleFunction fun) { RootedObject dynamicScopeObj(cx); - RootedObject staticScopeObj(cx); - if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj)) + Rooted staticScopeObj(cx); + if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj)) return false; return CompileFunction(cx, options, name, nargs, argnames, @@ -4171,33 +4202,34 @@ JS_DecompileFunctionBody(JSContext* cx, HandleFunction fun, unsigned indent) } MOZ_NEVER_INLINE static bool -ExecuteScript(JSContext* cx, HandleObject obj, HandleScript scriptArg, jsval* rval) +ExecuteScript(JSContext* cx, HandleObject scope, HandleScript script, jsval* rval) { - RootedScript script(cx, scriptArg); - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, scriptArg); - - if (!script->hasNonSyntacticScope() && !obj->is()) { - script = CloneScript(cx, nullptr, nullptr, script, HasPollutedGlobalScope); - if (!script) - return false; - js::Debugger::onNewScript(cx, script); - } + assertSameCompartment(cx, scope, script); + MOZ_ASSERT_IF(!scope->is(), script->hasNonSyntacticScope()); AutoLastFrameCheck lfc(cx); - return Execute(cx, script, *obj, rval); + return Execute(cx, script, *scope, rval); } static bool ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptArg, jsval* rval) { RootedObject dynamicScope(cx); - RootedObject unusedStaticScope(cx); - if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope)) + Rooted staticScope(cx); + if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope)) return false; - return ExecuteScript(cx, dynamicScope, scriptArg, rval); + + RootedScript script(cx, scriptArg); + if (!script->hasNonSyntacticScope()) { + script = CloneGlobalScript(cx, staticScope, script); + if (!script) + return false; + js::Debugger::onNewScript(cx, script); + } + + return ExecuteScript(cx, dynamicScope, script, rval); } MOZ_NEVER_INLINE JS_PUBLIC_API(bool) @@ -4243,7 +4275,8 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg) static const unsigned LARGE_SCRIPT_LENGTH = 500*1024; static bool -Evaluate(JSContext* cx, HandleObject scope, const ReadOnlyCompileOptions& optionsArg, +Evaluate(JSContext* cx, HandleObject scope, Handle staticScope, + const ReadOnlyCompileOptions& optionsArg, SourceBufferHolder& srcBuf, MutableHandleValue rval) { CompileOptions options(cx, optionsArg); @@ -4254,12 +4287,14 @@ Evaluate(JSContext* cx, HandleObject scope, const ReadOnlyCompileOptions& option AutoLastFrameCheck lfc(cx); - options.setHasPollutedScope(!scope->is()); + MOZ_ASSERT_IF(!scope->is(), HasNonSyntacticStaticScopeChain(staticScope)); + options.setIsRunOnce(true); SourceCompressionTask sct(cx); RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), - scope, nullptr, nullptr, options, - srcBuf, nullptr, 0, &sct)); + scope, staticScope, + /* evalCaller = */ nullptr, options, + srcBuf, /* source = */ nullptr, 0, &sct)); if (!script) return false; @@ -4289,10 +4324,10 @@ Evaluate(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptio SourceBufferHolder& srcBuf, MutableHandleValue rval) { RootedObject dynamicScope(cx); - RootedObject unusedStaticScope(cx); - if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope)) + Rooted staticScope(cx); + if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope)) return false; - return ::Evaluate(cx, dynamicScope, optionsArg, srcBuf, rval); + return ::Evaluate(cx, dynamicScope, staticScope, optionsArg, srcBuf, rval); } static bool @@ -4300,7 +4335,7 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char16_t* chars, size_t length, MutableHandleValue rval) { SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); - return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval); + return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); } extern JS_PUBLIC_API(bool) @@ -4316,7 +4351,7 @@ JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, return false; SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership); - bool ok = ::Evaluate(cx, cx->global(), options, srcBuf, rval); + bool ok = ::Evaluate(cx, cx->global(), nullptr, options, srcBuf, rval); return ok; } @@ -4340,7 +4375,7 @@ JS_PUBLIC_API(bool) JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, SourceBufferHolder& srcBuf, MutableHandleValue rval) { - return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval); + return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); } JS_PUBLIC_API(bool) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index c09c4f7bbd9..e06341a949f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3446,7 +3446,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) utf8(false), lineno(1), column(0), - hasPollutedGlobalScope(false), isRunOnce(false), forEval(false), noScriptRval(false), @@ -3486,7 +3485,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) bool utf8; unsigned lineno; unsigned column; - bool hasPollutedGlobalScope; // isRunOnce only applies to non-function scripts. bool isRunOnce; bool forEval; @@ -3579,7 +3577,6 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions } OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; } - OwningCompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; } OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; } OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } @@ -3663,7 +3660,6 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti } CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setColumn(unsigned c) { column = c; return *this; } - CompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; } CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } CompileOptions& setForEval(bool eval) { forEval = eval; return *this; } CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } @@ -3714,6 +3710,10 @@ extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleScript script); +extern JS_PUBLIC_API(bool) +CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, JS::MutableHandleScript script); + extern JS_PUBLIC_API(bool) CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index aa36cd7d47f..4a01fd95ce2 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2429,11 +2429,16 @@ JSScript::Create(ExclusiveContext* cx, HandleObject enclosingScope, bool savedCa script->savedCallerFun_ = savedCallerFun; script->initCompartment(cx); - script->hasNonSyntacticScope_ = options.hasPollutedGlobalScope; script->selfHosted_ = options.selfHostingMode; script->noScriptRval_ = options.noScriptRval; script->treatAsRunOnce_ = options.isRunOnce; + // Compute whether this script is under a non-syntactic scope. We don't + // need to walk the entire static scope chain if the script is nested in a + // function. In that case, we can propagate the cached value from the + // outer script. + script->hasNonSyntacticScope_ = HasNonSyntacticStaticScopeChain(enclosingScope); + script->version = options.version; MOZ_ASSERT(script->getVersion() == options.version); // assert that no overflow occurred @@ -2668,10 +2673,13 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco RootedFunction fun(cx, nullptr); if (funbox) { + // The function should have already been earlier to enable + // StaticScopeIter to walk the static scope chain of + // currently compiling scripts. + MOZ_ASSERT(script->functionNonDelazifying() == funbox->function()); MOZ_ASSERT(!bce->script->noScriptRval()); script->isGeneratorExp_ = funbox->inGenexpLambda; script->setGeneratorKind(funbox->generatorKind()); - script->setFunction(funbox->function()); if (bce->yieldOffsetList.length() != 0) bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 846e510fda9..3b9e57c8cc9 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -755,11 +755,6 @@ bool XDRScript(XDRState* xdr, HandleObject enclosingScope, HandleScript enclosingScript, HandleFunction fun, MutableHandleScript scriptp); -enum PollutedGlobalScopeOption { - HasPollutedGlobalScope, - HasCleanGlobalScope -}; - JSScript* CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script, PollutedGlobalScopeOption polluted = HasCleanGlobalScope, diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index c818b04256c..150ccfe5751 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -6261,12 +6261,14 @@ EvaluateInEnv(JSContext* cx, Handle env, HandleValue thisv, AbstractFrameP * boundaries, and we are putting a DebugScopeProxy or non-syntactic With on * the scope chain. */ - Rooted staticScope(cx, StaticEvalObject::create(cx, nullptr)); + Rooted enclosingStaticScope(cx); + if (!env->is()) + enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr); + Rooted staticScope(cx, StaticEvalObject::create(cx, enclosingStaticScope)); if (!staticScope) return false; CompileOptions options(cx); - options.setHasPollutedScope(true) - .setIsRunOnce(true) + options.setIsRunOnce(true) .setForEval(true) .setNoScriptRval(false) .setFileAndLine(filename, lineno) @@ -6417,14 +6419,8 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code return false; RootedObject dynamicScope(cx); - // We ignore the static scope here. See comments about static - // scopes in EvaluateInEnv. - RootedObject unusedStaticScope(cx); - if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope, - &unusedStaticScope)) - { + if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope)) return false; - } env = dynamicScope; } diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index eafc8526c29..924fb4253ed 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2487,8 +2487,7 @@ js::GetObjectEnvironmentObjectForFunction(JSFunction* fun) bool js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, HandleObject dynamicTerminatingScope, - MutableHandleObject dynamicScopeObj, - MutableHandleObject staticScopeObj) + MutableHandleObject dynamicScopeObj) { #ifdef DEBUG for (size_t i = 0; i < scopeChain.length(); ++i) { @@ -2518,10 +2517,23 @@ js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, } dynamicScopeObj.set(dynamicEnclosingScope); - staticScopeObj.set(staticEnclosingScope); return true; } +bool +js::HasNonSyntacticStaticScopeChain(JSObject* staticScope) +{ + for (StaticScopeIter ssi(staticScope); !ssi.done(); ssi++) { + // If we hit a function scope, we can short circuit the logic, as + // scripts cache whether they are under a non-syntactic scope. + if (ssi.type() == StaticScopeIter::Function) + return ssi.funScript()->hasNonSyntacticScope(); + if (ssi.type() == StaticScopeIter::NonSyntactic) + return true; + } + return false; +} + #ifdef DEBUG typedef HashSet PropertyNameSet; diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 8fd222af445..0a09c7ee5d5 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -1158,8 +1158,9 @@ ScopeIter::enclosingScope() const extern bool CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, HandleObject dynamicTerminatingScope, - MutableHandleObject dynamicScopeObj, - MutableHandleObject staticScopeObj); + MutableHandleObject dynamicScopeObj); + +bool HasNonSyntacticStaticScopeChain(JSObject* staticScope); #ifdef DEBUG bool diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 3f4650eafca..212de838451 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -187,7 +187,7 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject* // The scope chain is always ended by one or more non-syntactic // ScopeObjects (viz. GlobalObject or an unqualified varobj). - MOZ_ASSERT(!scope->is()); + MOZ_ASSERT(!IsSyntacticScope(scope)); #endif } @@ -253,8 +253,7 @@ InterpreterFrame::epilogue(JSContext* cx) if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) DebugScopes::onPopStrictEvalScope(this); } else if (isDirectEvalFrame()) { - if (isDebuggerEvalFrame()) - MOZ_ASSERT(!scopeChain()->is()); + MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain())); } else { /* * Debugger.Object.prototype.evalInGlobal creates indirect eval