Backed out 12 changesets (bug 1165486) for windows spidermonkey failures CLOSED TREE

Backed out changeset ce3c302864bf (bug 1165486)
Backed out changeset f69852001c61 (bug 1165486)
Backed out changeset 06cc09729bf4 (bug 1165486)
Backed out changeset 52772afc023e (bug 1165486)
Backed out changeset 502ddf7d2268 (bug 1165486)
Backed out changeset b04ab7bd78af (bug 1165486)
Backed out changeset 53fcddbe4cfb (bug 1165486)
Backed out changeset 63bd369e5349 (bug 1165486)
Backed out changeset 1e35269a8062 (bug 1165486)
Backed out changeset e3c11d517e18 (bug 1165486)
Backed out changeset ccd90228daf6 (bug 1165486)
Backed out changeset eb11e655d223 (bug 1165486)
This commit is contained in:
Wes Kocher 2015-06-15 18:07:52 -07:00
Родитель 76d8ba0697
Коммит 9dceeed482
39 изменённых файлов: 707 добавлений и 1141 удалений

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

@ -1788,7 +1788,8 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
} }
} else { } else {
// We're going to run these against some non-global scope. // We're going to run these against some non-global scope.
if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) { options.setHasPollutedScope(true);
if (!JS::Compile(cx, options, srcBuf, &script)) {
return; return;
} }
} }

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

@ -212,6 +212,18 @@ TryEvalJSON(JSContext* cx, JSLinearString* str, MutableHandleValue rval)
: ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval); : ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
} }
static bool
HasPollutedScopeChain(JSObject* scopeChain)
{
while (scopeChain) {
if (scopeChain->is<DynamicWithObject>())
return true;
scopeChain = scopeChain->enclosingScope();
}
return false;
}
// Define subset of ExecuteType so that casting performs the injection. // Define subset of ExecuteType so that casting performs the injection.
enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL }; enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
@ -314,8 +326,13 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
if (!staticScope) if (!staticScope)
return false; return false;
bool hasPollutedGlobalScope =
HasPollutedScopeChain(scopeobj) ||
(evalType == DIRECT_EVAL && callerScript->hasPollutedGlobalScope());
CompileOptions options(cx); CompileOptions options(cx);
options.setFileAndLine(filename, 1) options.setFileAndLine(filename, 1)
.setHasPollutedScope(hasPollutedGlobalScope)
.setIsRunOnce(true) .setIsRunOnce(true)
.setForEval(true) .setForEval(true)
.setNoScriptRval(false) .setNoScriptRval(false)
@ -333,7 +350,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
: SourceBufferHolder::NoOwnership; : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership); SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, staticScope, callerScript, scopeobj, callerScript, staticScope,
options, srcBuf, linearStr, staticLevel); options, srcBuf, linearStr, staticLevel);
if (!compiled) if (!compiled)
return false; return false;
@ -387,7 +404,7 @@ js::DirectEvalStringFromIon(JSContext* cx,
bool mutedErrors; bool mutedErrors;
uint32_t pcOffset; uint32_t pcOffset;
DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset, DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
&mutedErrors, CALLED_FROM_JSOP_EVAL); &mutedErrors, CALLED_FROM_JSOP_EVAL);
const char* introducerFilename = filename; const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename()) if (maybeScript && maybeScript->scriptSource()->introducerFilename())
@ -400,6 +417,8 @@ js::DirectEvalStringFromIon(JSContext* cx,
CompileOptions options(cx); CompileOptions options(cx);
options.setFileAndLine(filename, 1) options.setFileAndLine(filename, 1)
.setHasPollutedScope(HasPollutedScopeChain(scopeobj) ||
callerScript->hasPollutedGlobalScope())
.setIsRunOnce(true) .setIsRunOnce(true)
.setForEval(true) .setForEval(true)
.setNoScriptRval(false) .setNoScriptRval(false)
@ -417,7 +436,7 @@ js::DirectEvalStringFromIon(JSContext* cx,
: SourceBufferHolder::NoOwnership; : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership); SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, staticScope, callerScript, scopeobj, callerScript, staticScope,
options, srcBuf, linearStr, staticLevel); options, srcBuf, linearStr, staticLevel);
if (!compiled) if (!compiled)
return false; return false;
@ -488,31 +507,35 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, global); assertSameCompartment(cx, global);
MOZ_ASSERT(global->is<GlobalObject>()); MOZ_ASSERT(global->is<GlobalObject>());
MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope()); MOZ_RELEASE_ASSERT(scriptArg->hasPollutedGlobalScope());
RootedScript script(cx, scriptArg); RootedScript script(cx, scriptArg);
if (script->compartment() != cx->compartment()) { if (script->compartment() != cx->compartment()) {
Rooted<ScopeObject*> staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr)); script = CloneScript(cx, nullptr, nullptr, script);
if (!staticScope)
return false;
script = CloneGlobalScript(cx, staticScope, script);
if (!script) if (!script)
return false; return false;
Debugger::onNewScript(cx, script); Debugger::onNewScript(cx, script);
} }
Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>()); RootedObject scope(cx, JS_NewPlainObject(cx));
Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot));
if (!scope) if (!scope)
return false; return false;
if (!scope->setQualifiedVarObj(cx))
return false;
if (!scope->setUnqualifiedVarObj(cx))
return false;
JSObject* thisobj = GetThisObject(cx, global); JSObject* thisobj = GetThisObject(cx, global);
if (!thisobj) if (!thisobj)
return false; return false;
RootedValue thisv(cx, ObjectValue(*thisobj)); RootedValue thisv(cx, ObjectValue(*thisobj));
RootedValue rval(cx); RootedValue rval(cx);
// XXXbz when this is fixed to pass in an actual ScopeObject, fix
// up the assert in js::CloneFunctionObject accordingly.
if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL, if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL,
NullFramePtr() /* evalInFrame */, rval.address())) NullFramePtr() /* evalInFrame */, rval.address()))
{ {

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

@ -2272,10 +2272,11 @@ EvalReturningScope(JSContext* cx, unsigned argc, jsval* vp)
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
options.setFileAndLine(filename.get(), lineno); options.setFileAndLine(filename.get(), lineno);
options.setNoScriptRval(true); options.setNoScriptRval(true);
options.setHasPollutedScope(true);
JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership); JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership);
RootedScript script(cx); RootedScript script(cx);
if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) if (!JS::Compile(cx, options, srcBuf, &script))
return false; return false;
if (global) { if (global) {

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

@ -144,11 +144,10 @@ MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, Ha
} }
static inline bool static inline bool
CanLazilyParse(ExclusiveContext* cx, HandleObject staticScope, CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
const ReadOnlyCompileOptions& options)
{ {
return options.canLazilyParse && return options.canLazilyParse &&
!HasNonSyntacticStaticScopeChain(staticScope) && !options.hasPollutedGlobalScope &&
!cx->compartment()->options().disableLazyParsing() && !cx->compartment()->options().disableLazyParsing() &&
!cx->compartment()->options().discardSource() && !cx->compartment()->options().discardSource() &&
!options.sourceIsLazy; !options.sourceIsLazy;
@ -211,8 +210,8 @@ frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOp
JSScript* JSScript*
frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject scopeChain, frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject scopeChain,
Handle<ScopeObject*> enclosingStaticScope,
HandleScript evalCaller, HandleScript evalCaller,
Handle<StaticEvalObject*> evalStaticScope,
const ReadOnlyCompileOptions& options, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, SourceBufferHolder& srcBuf,
JSString* source_ /* = nullptr */, JSString* source_ /* = nullptr */,
@ -261,7 +260,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
return nullptr; return nullptr;
} }
bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); bool canLazilyParse = CanLazilyParse(cx, options);
Maybe<Parser<SyntaxParseHandler> > syntaxParser; Maybe<Parser<SyntaxParseHandler> > syntaxParser;
if (canLazilyParse) { if (canLazilyParse) {
@ -285,22 +284,22 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction(); bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction();
Directives directives(options.strictOption); Directives directives(options.strictOption);
GlobalSharedContext globalsc(cx, directives, enclosingStaticScope, options.extraWarningsOption); GlobalSharedContext globalsc(cx, directives, evalStaticScope, options.extraWarningsOption);
Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingStaticScope, savedCallerFun, Rooted<JSScript*> script(cx, JSScript::Create(cx, evalStaticScope, savedCallerFun,
options, staticLevel, sourceObject, 0, options, staticLevel, sourceObject, 0,
srcBuf.length())); srcBuf.length()));
if (!script) if (!script)
return nullptr; return nullptr;
bool insideNonGlobalEval = bool insideNonGlobalEval =
enclosingStaticScope && enclosingStaticScope->is<StaticEvalObject>() && evalStaticScope && evalStaticScope->enclosingScopeForStaticScopeIter();
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
BytecodeEmitter::EmitterMode emitterMode = BytecodeEmitter::EmitterMode emitterMode =
options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal; options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script,
/* lazyScript = */ nullptr, options.forEval, /* lazyScript = */ nullptr, options.forEval,
evalCaller, insideNonGlobalEval, options.lineno, emitterMode); evalCaller, insideNonGlobalEval,
options.lineno, emitterMode);
if (!bce.init()) if (!bce.init())
return nullptr; return nullptr;
@ -562,7 +561,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
return false; return false;
} }
bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); bool canLazilyParse = CanLazilyParse(cx, options);
Maybe<Parser<SyntaxParseHandler> > syntaxParser; Maybe<Parser<SyntaxParseHandler> > syntaxParser;
if (canLazilyParse) { if (canLazilyParse) {

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

@ -17,17 +17,18 @@ class AutoNameVector;
class LazyScript; class LazyScript;
class LifoAlloc; class LifoAlloc;
class ScriptSourceObject; class ScriptSourceObject;
class ScopeObject; class StaticEvalObject;
struct SourceCompressionTask; struct SourceCompressionTask;
namespace frontend { namespace frontend {
JSScript* JSScript*
CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, CompileScript(ExclusiveContext* cx, LifoAlloc* alloc,
HandleObject scopeChain, Handle<ScopeObject*> enclosingStaticScope, HandleObject scopeChain, HandleScript evalCaller,
HandleScript evalCaller, const ReadOnlyCompileOptions& options, Handle<StaticEvalObject*> evalStaticScope,
SourceBufferHolder& srcBuf, JSString* source_ = nullptr, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf,
unsigned staticLevel = 0, SourceCompressionTask* extraSct = nullptr); JSString* source_ = nullptr, unsigned staticLevel = 0,
SourceCompressionTask* extraSct = nullptr);
bool bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length); CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);

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

@ -769,7 +769,7 @@ BytecodeEmitter::enclosingStaticScope()
// Top-level eval scripts have a placeholder static scope so that // Top-level eval scripts have a placeholder static scope so that
// StaticScopeIter may iterate through evals. // StaticScopeIter may iterate through evals.
return sc->asGlobalSharedContext()->topStaticScope(); return sc->asGlobalSharedContext()->evalStaticScope();
} }
return sc->asFunctionBox()->function(); return sc->asFunctionBox()->function();
@ -1548,14 +1548,14 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
// Use generic ops if a catch block is encountered. // Use generic ops if a catch block is encountered.
return false; return false;
} }
if (ssi.hasSyntacticDynamicScopeObject()) if (ssi.hasDynamicScopeObject())
hops++; hops++;
continue; continue;
} }
RootedScript script(cx, ssi.funScript()); RootedScript script(cx, ssi.funScript());
if (script->functionNonDelazifying()->atom() == pn->pn_atom) if (script->functionNonDelazifying()->atom() == pn->pn_atom)
return false; return false;
if (ssi.hasSyntacticDynamicScopeObject()) { if (ssi.hasDynamicScopeObject()) {
uint32_t slot; uint32_t slot;
if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) { if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) {
JSOp op; JSOp op;
@ -1587,9 +1587,9 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
if (insideNonGlobalEval) if (insideNonGlobalEval)
return false; return false;
// Skip trying to use GNAME ops if we know our script has a non-syntactic // Skip trying to use GNAME ops if we know our script has a polluted
// scope, since they'll just get treated as NAME ops anyway. // global scope, since they'll just get treated as NAME ops anyway.
if (script->hasNonSyntacticScope()) if (script->hasPollutedGlobalScope())
return false; return false;
// Deoptimized names also aren't necessarily globals. // Deoptimized names also aren't necessarily globals.
@ -2356,14 +2356,13 @@ BytecodeEmitter::checkRunOnceContext()
bool bool
BytecodeEmitter::needsImplicitThis() BytecodeEmitter::needsImplicitThis()
{ {
if (sc->inWith()) if (sc->isFunctionBox() && sc->asFunctionBox()->inWith)
return true; return true;
for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) { for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
if (stmt->type == STMT_WITH) if (stmt->type == STMT_WITH)
return true; return true;
} }
return false; return false;
} }
@ -3407,19 +3406,6 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
*/ */
FunctionBox* funbox = sc->asFunctionBox(); 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()) { if (funbox->argumentsHasLocalBinding()) {
MOZ_ASSERT(offset() == 0); /* See JSScript::argumentsBytecode. */ MOZ_ASSERT(offset() == 0); /* See JSScript::argumentsBytecode. */
switchToPrologue(); switchToPrologue();
@ -3523,6 +3509,15 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
MOZ_ASSERT(!script->hasRunOnce()); 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); tellDebuggerAboutCompiledScript(cx);
return true; return true;
@ -5770,6 +5765,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSScript*> parent(cx, script); Rooted<JSScript*> parent(cx, script);
CompileOptions options(cx, parser->options()); CompileOptions options(cx, parser->options());
options.setMutedErrors(parent->mutedErrors()) options.setMutedErrors(parent->mutedErrors())
.setHasPollutedScope(parent->hasPollutedGlobalScope())
.setSelfHostingMode(parent->selfHosted())
.setNoScriptRval(false) .setNoScriptRval(false)
.setForEval(false) .setForEval(false)
.setVersion(parent->getVersion()); .setVersion(parent->getVersion());

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

@ -22,7 +22,7 @@
namespace js { namespace js {
class ScopeObject; class StaticEvalObject;
namespace frontend { namespace frontend {

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

@ -596,7 +596,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
bufEnd(0), bufEnd(0),
length(0), length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)), generatorKindBits_(GeneratorKindAsBits(generatorKind)),
inWith_(false), // initialized below inWith(false), // initialized below
inGenexpLambda(false), inGenexpLambda(false),
hasDestructuringArgs(false), hasDestructuringArgs(false),
useAsm(false), useAsm(false),
@ -612,7 +612,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
MOZ_ASSERT(fun->isTenured()); MOZ_ASSERT(fun->isTenured());
if (!outerpc) { if (!outerpc) {
inWith_ = false; inWith = false;
} else if (outerpc->parsingWith) { } else if (outerpc->parsingWith) {
// This covers cases that don't involve eval(). For example: // This covers cases that don't involve eval(). For example:
@ -621,7 +621,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
// //
// In this case, |outerpc| corresponds to global code, and // In this case, |outerpc| corresponds to global code, and
// outerpc->parsingWith is true. // outerpc->parsingWith is true.
inWith_ = true; inWith = true;
} else if (outerpc->sc->isFunctionBox()) { } else if (outerpc->sc->isFunctionBox()) {
// This is like the above case, but for more deeply nested functions. // This is like the above case, but for more deeply nested functions.
@ -632,17 +632,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
// In this case, the inner anonymous function needs to inherit the // In this case, the inner anonymous function needs to inherit the
// setting of |inWith| from the outer one. // setting of |inWith| from the outer one.
FunctionBox* parent = outerpc->sc->asFunctionBox(); FunctionBox* parent = outerpc->sc->asFunctionBox();
if (parent && parent->inWith()) if (parent && parent->inWith)
inWith_ = true; inWith = true;
} else {
// This is like the above case, but when inside eval.
//
// For example:
//
// with(o) { eval("(function() { g(); })();"); }
//
// In this case, the static scope chain tells us the presence of with.
inWith_ = outerpc->sc->inWith();
} }
} }
@ -2224,7 +2215,7 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
// while its ParseContext and associated lexdeps and inner functions are // while its ParseContext and associated lexdeps and inner functions are
// still available. // still available.
if (funbox->inWith()) if (funbox->inWith)
return abortIfSyntaxParser(); return abortIfSyntaxParser();
size_t numFreeVariables = pc->lexdeps->count(); size_t numFreeVariables = pc->lexdeps->count();

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

@ -235,7 +235,6 @@ class SharedContext
SuperProperty SuperProperty
}; };
virtual bool allowSyntax(AllowedSyntax allowed) const = 0; virtual bool allowSyntax(AllowedSyntax allowed) const = 0;
virtual bool inWith() const = 0;
protected: protected:
static bool FunctionAllowsSyntax(JSFunction* func, AllowedSyntax allowed) static bool FunctionAllowsSyntax(JSFunction* func, AllowedSyntax allowed)
@ -257,13 +256,21 @@ class SharedContext
class GlobalSharedContext : public SharedContext class GlobalSharedContext : public SharedContext
{ {
private: private:
Handle<ScopeObject*> topStaticScope_; Handle<StaticEvalObject*> staticEvalScope_;
bool allowNewTarget_;
bool allowSuperProperty_;
bool inWith_;
bool computeAllowSyntax(AllowedSyntax allowed) const { public:
StaticScopeIter<CanGC> it(context, topStaticScope_); GlobalSharedContext(ExclusiveContext* cx,
Directives directives, Handle<StaticEvalObject*> staticEvalScope,
bool extraWarnings)
: SharedContext(cx, directives, extraWarnings),
staticEvalScope_(staticEvalScope)
{}
ObjectBox* toObjectBox() { return nullptr; }
HandleObject evalStaticScope() const { return staticEvalScope_; }
bool allowSyntax(AllowedSyntax allowed) const {
StaticScopeIter<CanGC> it(context, staticEvalScope_);
for (; !it.done(); it++) { for (; !it.done(); it++) {
if (it.type() == StaticScopeIter<CanGC>::Function && if (it.type() == StaticScopeIter<CanGC>::Function &&
!it.fun().isArrow()) !it.fun().isArrow())
@ -273,40 +280,6 @@ class GlobalSharedContext : public SharedContext
} }
return false; return false;
} }
bool computeInWith() const {
for (StaticScopeIter<CanGC> it(context, topStaticScope_); !it.done(); it++) {
if (it.type() == StaticScopeIter<CanGC>::With)
return true;
}
return false;
}
public:
GlobalSharedContext(ExclusiveContext* cx,
Directives directives, Handle<ScopeObject*> topStaticScope,
bool extraWarnings)
: SharedContext(cx, directives, extraWarnings),
topStaticScope_(topStaticScope),
allowNewTarget_(computeAllowSyntax(AllowedSyntax::NewTarget)),
allowSuperProperty_(computeAllowSyntax(AllowedSyntax::SuperProperty)),
inWith_(computeInWith())
{}
ObjectBox* toObjectBox() { return nullptr; }
HandleObject topStaticScope() const { return topStaticScope_; }
bool allowSyntax(AllowedSyntax allowSyntax) const override {
switch (allowSyntax) {
case AllowedSyntax::NewTarget:
// Any function supports new.target
return allowNewTarget_;
case AllowedSyntax::SuperProperty:
return allowSuperProperty_;
default:;
}
MOZ_CRASH("Unknown AllowedSyntax query");
}
bool inWith() const override { return inWith_; }
}; };
class FunctionBox : public ObjectBox, public SharedContext class FunctionBox : public ObjectBox, public SharedContext
@ -320,7 +293,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint16_t length; uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
bool inWith_:1; /* some enclosing scope is a with-statement */ bool inWith:1; /* some enclosing scope is a with-statement */
bool inGenexpLambda:1; /* lambda from generator expression */ bool inGenexpLambda:1; /* lambda from generator expression */
bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */ bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
bool useAsm:1; /* see useAsmOrInsideUseAsm */ bool useAsm:1; /* see useAsmOrInsideUseAsm */
@ -399,13 +372,9 @@ class FunctionBox : public ObjectBox, public SharedContext
isGenerator(); isGenerator();
} }
bool allowSyntax(AllowedSyntax allowed) const override { bool allowSyntax(AllowedSyntax allowed) const {
return FunctionAllowsSyntax(function(), allowed); return FunctionAllowsSyntax(function(), allowed);
} }
bool inWith() const override {
return inWith_;
}
}; };
inline FunctionBox* inline FunctionBox*

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

@ -4,7 +4,6 @@ var g = newGlobal();
var g2 = newGlobal(); var g2 = newGlobal();
var dbg = new Debugger(g, g2); var dbg = new Debugger(g, g2);
var log = ''; var log = '';
var canary = 42;
dbg.onNewScript = function (evalScript) { dbg.onNewScript = function (evalScript) {
log += 'e'; log += 'e';
@ -25,8 +24,5 @@ dbg.onDebuggerStatement = function (frame) {
}; };
assertEq(log, ''); assertEq(log, '');
var evalScope = g.evalReturningScope("canary = 'dead'; debugger; // nee", g2); var evalScope = g.evalReturningScope("debugger; // nee", g2);
assertEq(log, 'ecbd'); assertEq(log, 'ecbd');
assertEq(canary, 42);
assertEq(evalScope.canary, 'dead');

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

@ -704,14 +704,13 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
scopeChain = fun->environment(); scopeChain = fun->environment();
} }
} else { } else {
// For global scripts without a non-syntactic scope the scope // For global scripts without a polluted global scope the scope
// chain is the script's global (Ion does not compile scripts // chain is the script's global (Ion does not compile scripts
// with a non-syntactic global scope). Also note that it's // with a polluted global scope). Also note that it's invalid to
// invalid to resume into the prologue in this case because // resume into the prologue in this case because the prologue
// the prologue expects the scope chain in R1 for eval and // expects the scope chain in R1 for eval and global scripts.
// global scripts.
MOZ_ASSERT(!script->isForEval()); MOZ_ASSERT(!script->isForEval());
MOZ_ASSERT(!script->hasNonSyntacticScope()); MOZ_ASSERT(!script->hasPollutedGlobalScope());
scopeChain = &(script->global()); scopeChain = &(script->global());
} }
} }

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

@ -20,7 +20,6 @@
#endif #endif
#include "jit/SharedICHelpers.h" #include "jit/SharedICHelpers.h"
#include "jit/VMFunctions.h" #include "jit/VMFunctions.h"
#include "vm/ScopeObject.h"
#include "vm/TraceLogging.h" #include "vm/TraceLogging.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -129,7 +128,7 @@ BaselineCompiler::compile()
return Method_Error; return Method_Error;
if (fun->isNamedLambda()) { if (fun->isNamedLambda()) {
RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, TenuredObject)); RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap));
if (!declEnvObject) if (!declEnvObject)
return Method_Error; return Method_Error;
templateScope->as<ScopeObject>().setEnclosingScope(declEnvObject); templateScope->as<ScopeObject>().setEnclosingScope(declEnvObject);
@ -2063,7 +2062,7 @@ BaselineCompiler::emit_JSOP_IN()
bool bool
BaselineCompiler::emit_JSOP_GETGNAME() BaselineCompiler::emit_JSOP_GETGNAME()
{ {
if (script->hasNonSyntacticScope()) if (script->hasPollutedGlobalScope())
return emit_JSOP_GETNAME(); return emit_JSOP_GETNAME();
RootedPropertyName name(cx, script->getName(pc)); RootedPropertyName name(cx, script->getName(pc));
@ -2098,7 +2097,7 @@ BaselineCompiler::emit_JSOP_GETGNAME()
bool bool
BaselineCompiler::emit_JSOP_BINDGNAME() BaselineCompiler::emit_JSOP_BINDGNAME()
{ {
if (!script->hasNonSyntacticScope()) { if (!script->hasPollutedGlobalScope()) {
frame.push(ObjectValue(script->global())); frame.push(ObjectValue(script->global()));
return true; return true;
} }
@ -2921,7 +2920,7 @@ BaselineCompiler::emit_JSOP_IMPLICITTHIS()
bool bool
BaselineCompiler::emit_JSOP_GIMPLICITTHIS() BaselineCompiler::emit_JSOP_GIMPLICITTHIS()
{ {
if (!script->hasNonSyntacticScope()) { if (!script->hasPollutedGlobalScope()) {
frame.push(UndefinedValue()); frame.push(UndefinedValue());
return true; return true;
} }

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

@ -6031,7 +6031,7 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
attached = true; attached = true;
} }
if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) { if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasPollutedGlobalScope()) {
if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub, scopeChain.as<GlobalObject>(), if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub, scopeChain.as<GlobalObject>(),
name, &attached, &isTemporarilyUnoptimizable)) name, &attached, &isTemporarilyUnoptimizable))
{ {
@ -6061,7 +6061,7 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
if (attached) if (attached)
return true; return true;
if (IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) { if (IsGlobalOp(JSOp(*pc)) && !script->hasPollutedGlobalScope()) {
Handle<GlobalObject*> global = scopeChain.as<GlobalObject>(); Handle<GlobalObject*> global = scopeChain.as<GlobalObject>();
if (!TryAttachGlobalNameValueStub(cx, script, pc, stub, global, name, &attached)) if (!TryAttachGlobalNameValueStub(cx, script, pc, stub, global, name, &attached))
return false; return false;

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

@ -170,7 +170,7 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
case JSOP_GETGNAME: case JSOP_GETGNAME:
case JSOP_SETGNAME: case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME: case JSOP_STRICTSETGNAME:
if (script_->hasNonSyntacticScope()) if (script_->hasPollutedGlobalScope())
usesScopeChain_ = true; usesScopeChain_ = true;
break; break;

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

@ -4683,7 +4683,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
bailoutFrom(&bail, lir->snapshot()); bailoutFrom(&bail, lir->snapshot());
} }
typedef js::DeclEnvObject* (*NewDeclEnvObjectFn)(JSContext*, HandleFunction, NewObjectKind); typedef js::DeclEnvObject* (*NewDeclEnvObjectFn)(JSContext*, HandleFunction, gc::InitialHeap);
static const VMFunction NewDeclEnvObjectInfo = static const VMFunction NewDeclEnvObjectInfo =
FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject); FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
@ -4697,7 +4697,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject* lir)
// If we have a template object, we can inline call object creation. // If we have a template object, we can inline call object creation.
OutOfLineCode* ool = oolCallVM(NewDeclEnvObjectInfo, lir, OutOfLineCode* ool = oolCallVM(NewDeclEnvObjectInfo, lir,
ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(GenericObject)), ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(gc::DefaultHeap)),
StoreRegisterTo(objReg)); StoreRegisterTo(objReg));
bool initContents = ShouldInitFixedSlots(lir, templateObj); bool initContents = ShouldInitFixedSlots(lir, templateObj);

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

@ -2128,12 +2128,12 @@ CheckScript(JSContext* cx, JSScript* script, bool osr)
return false; return false;
} }
if (script->hasNonSyntacticScope() && !script->functionNonDelazifying()) { if (script->hasPollutedGlobalScope() && !script->functionNonDelazifying()) {
// Support functions with a non-syntactic global scope but not other // Support functions with a polluted global scope but not other
// scripts. For global scripts, IonBuilder currently uses the global // scripts. For global scripts, IonBuilder currently uses the global
// object as scope chain, this is not valid when the script has a // object as scope chain, this is not valid when the script has a
// non-syntactic global scope. // polluted global scope.
TrackAndSpewIonAbort(cx, script, "has non-syntactic global scope"); TrackAndSpewIonAbort(cx, script, "has polluted global scope");
return false; return false;
} }

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

@ -613,7 +613,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
type = MIRType_Undefined; type = MIRType_Undefined;
break; break;
case JSOP_GIMPLICITTHIS: case JSOP_GIMPLICITTHIS:
if (!script()->hasNonSyntacticScope()) if (!script()->hasPollutedGlobalScope())
type = MIRType_Undefined; type = MIRType_Undefined;
break; break;
case JSOP_NULL: case JSOP_NULL:
@ -1177,10 +1177,10 @@ IonBuilder::initScopeChain(MDefinition* callee)
return false; return false;
} }
} else { } else {
// For global scripts without a non-syntactic global scope, the scope // For global scripts without a polluted global scope, the scope chain
// chain is the global object. // is the global object.
MOZ_ASSERT(!script()->isForEval()); MOZ_ASSERT(!script()->isForEval());
MOZ_ASSERT(!script()->hasNonSyntacticScope()); MOZ_ASSERT(!script()->hasPollutedGlobalScope());
scope = constant(ObjectValue(script()->global())); scope = constant(ObjectValue(script()->global()));
} }
@ -1795,7 +1795,7 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_GETGNAME: case JSOP_GETGNAME:
{ {
PropertyName* name = info().getAtom(pc)->asPropertyName(); PropertyName* name = info().getAtom(pc)->asPropertyName();
if (!script()->hasNonSyntacticScope()) if (!script()->hasPollutedGlobalScope())
return jsop_getgname(name); return jsop_getgname(name);
return jsop_getname(name); return jsop_getname(name);
} }
@ -1804,7 +1804,7 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_STRICTSETGNAME: case JSOP_STRICTSETGNAME:
{ {
PropertyName* name = info().getAtom(pc)->asPropertyName(); PropertyName* name = info().getAtom(pc)->asPropertyName();
if (script()->hasNonSyntacticScope()) if (script()->hasPollutedGlobalScope())
return jsop_setprop(name); return jsop_setprop(name);
JSObject* obj = &script()->global(); JSObject* obj = &script()->global();
return setStaticName(obj, name); return setStaticName(obj, name);
@ -1823,7 +1823,7 @@ IonBuilder::inspectOpcode(JSOp op)
} }
case JSOP_BINDGNAME: case JSOP_BINDGNAME:
if (!script()->hasNonSyntacticScope()) if (!script()->hasPollutedGlobalScope())
return pushConstant(ObjectValue(script()->global())); return pushConstant(ObjectValue(script()->global()));
// Fall through to JSOP_BINDNAME // Fall through to JSOP_BINDNAME
case JSOP_BINDNAME: case JSOP_BINDNAME:
@ -1970,7 +1970,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_debugger(); return jsop_debugger();
case JSOP_GIMPLICITTHIS: case JSOP_GIMPLICITTHIS:
if (!script()->hasNonSyntacticScope()) if (!script()->hasPollutedGlobalScope())
return pushConstant(UndefinedValue()); return pushConstant(UndefinedValue());
// Just fall through to the unsupported bytecode case. // Just fall through to the unsupported bytecode case.
@ -7608,7 +7608,7 @@ bool
IonBuilder::jsop_getname(PropertyName* name) IonBuilder::jsop_getname(PropertyName* name)
{ {
MDefinition* object; MDefinition* object;
if (IsGlobalOp(JSOp(*pc)) && !script()->hasNonSyntacticScope()) { if (IsGlobalOp(JSOp(*pc)) && !script()->hasPollutedGlobalScope()) {
MInstruction* global = constant(ObjectValue(script()->global())); MInstruction* global = constant(ObjectValue(script()->global()));
object = global; object = global;
} else { } else {

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

@ -2553,7 +2553,7 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, MaybeReadFallback&
// Ion does not handle non-function scripts that have anything other than // Ion does not handle non-function scripts that have anything other than
// the global on their scope chain. // the global on their scope chain.
MOZ_ASSERT(!script()->isForEval()); MOZ_ASSERT(!script()->isForEval());
MOZ_ASSERT(!script()->hasNonSyntacticScope()); MOZ_ASSERT(!script()->hasPollutedGlobalScope());
return &script()->global(); return &script()->global();
} }

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

@ -3283,22 +3283,12 @@ JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id
} }
static bool static bool
CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
MutableHandleObject dynamicScopeObj, MutableHandleObject dynamicScopeObj,
MutableHandle<ScopeObject*> staticScopeObj) MutableHandleObject staticScopeObj)
{ {
if (!js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(), dynamicScopeObj)) return js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(),
return false; dynamicScopeObj, staticScopeObj);
if (scopeChain.empty()) {
staticScopeObj.set(nullptr);
} else {
staticScopeObj.set(StaticNonSyntacticScopeObjects::create(cx, nullptr));
if (!staticScopeObj)
return false;
}
return true;
} }
static bool static bool
@ -3309,23 +3299,11 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
// If a function was compiled to be lexically nested inside some other // If a function was compiled to be lexically nested inside some other
// script, we cannot clone it without breaking the compiler's assumptions. // script, we cannot clone it without breaking the compiler's assumptions.
if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) { JSObject* scope = fun->nonLazyScript()->enclosingStaticScope();
// If the script already deals with a non-syntactic scope, we can clone if (scope && (!scope->is<StaticEvalObject>() ||
// it. scope->as<StaticEvalObject>().isDirect() ||
if (scope->is<StaticNonSyntacticScopeObjects>()) scope->as<StaticEvalObject>().isStrict()))
return true; {
// If the script is an indirect eval that is immediately scoped under
// the global, we can clone it.
if (scope->is<StaticEvalObject>() &&
!scope->as<StaticEvalObject>().isDirect() &&
!scope->as<StaticEvalObject>().isStrict())
{
return true;
}
// Any other enclosing static scope (e.g., function, block) cannot be
// cloned.
return false; return false;
} }
@ -3333,8 +3311,7 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
} }
static JSObject* static JSObject*
CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope, CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope)
Handle<ScopeObject*> staticScope)
{ {
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
@ -3371,21 +3348,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScop
return nullptr; return nullptr;
} }
if (CanReuseScriptForClone(cx->compartment(), fun, dynamicScope)) { return CloneFunctionObject(cx, fun, dynamicScope, fun->getAllocKind());
// If the script is to be reused, either the script can already handle
// non-syntactic scopes, or there is no new static scope.
#ifdef DEBUG
// Fail here if we OOM during debug asserting.
// CloneFunctionReuseScript will delazify the script anyways, so we
// are not creating an extra failure condition for DEBUG builds.
if (!fun->getOrCreateScript(cx))
return nullptr;
MOZ_ASSERT(!staticScope || fun->nonLazyScript()->hasNonSyntacticScope());
#endif
return CloneFunctionReuseScript(cx, fun, dynamicScope, fun->getAllocKind());
}
return CloneFunctionAndScript(cx, fun, dynamicScope, staticScope, fun->getAllocKind());
} }
namespace JS { namespace JS {
@ -3393,18 +3356,18 @@ namespace JS {
JS_PUBLIC_API(JSObject*) JS_PUBLIC_API(JSObject*)
CloneFunctionObject(JSContext* cx, JS::Handle<JSObject*> funobj) CloneFunctionObject(JSContext* cx, JS::Handle<JSObject*> funobj)
{ {
return CloneFunctionObject(cx, funobj, cx->global(), /* staticScope = */ nullptr); return CloneFunctionObject(cx, funobj, cx->global());
} }
extern JS_PUBLIC_API(JSObject*) extern JS_PUBLIC_API(JSObject*)
CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain) CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain)
{ {
RootedObject dynamicScope(cx); RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx); RootedObject unusedStaticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope)) if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return nullptr; return nullptr;
return CloneFunctionObject(cx, funobj, dynamicScope, staticScope); return CloneFunctionObject(cx, funobj, dynamicScope);
} }
} // namespace JS } // namespace JS
@ -3874,40 +3837,31 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version)
asmJSOption = cx->runtime()->options().asmJS(); asmJSOption = cx->runtime()->options().asmJS();
} }
enum SyntacticScopeOption { HasSyntacticScope, HasNonSyntacticScope }; bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
static bool SourceBufferHolder& srcBuf, MutableHandleScript script)
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
SourceBufferHolder& srcBuf, MutableHandleScript script)
{ {
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
AutoLastFrameCheck lfc(cx); AutoLastFrameCheck lfc(cx);
Rooted<ScopeObject*> staticScope(cx);
if (scopeOption == HasNonSyntacticScope) {
staticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
if (!staticScope)
return false;
}
script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), cx->global(), script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), cx->global(),
staticScope, nullptr, options, srcBuf)); nullptr, nullptr, options, srcBuf));
return !!script; return !!script;
} }
static bool bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption, JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, MutableHandleScript script) const char16_t* chars, size_t length, MutableHandleScript script)
{ {
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return ::Compile(cx, options, scopeOption, srcBuf, script); return Compile(cx, options, srcBuf, script);
} }
static bool bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption, JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, MutableHandleScript script) const char* bytes, size_t length, MutableHandleScript script)
{ {
mozilla::UniquePtr<char16_t, JS::FreePolicy> chars; mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
if (options.utf8) if (options.utf8)
@ -3917,101 +3871,30 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOpti
if (!chars) if (!chars)
return false; return false;
return ::Compile(cx, options, scopeOption, chars.get(), length, script); return Compile(cx, options, chars.get(), length, script);
} }
static bool bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption, JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* fp,
FILE* fp, MutableHandleScript script) MutableHandleScript script)
{ {
FileContents buffer(cx); FileContents buffer(cx);
if (!ReadCompleteFile(cx, fp, buffer)) if (!ReadCompleteFile(cx, fp, buffer))
return false; return false;
return ::Compile(cx, options, scopeOption, buffer.begin(), buffer.length(), script); return Compile(cx, options, buffer.begin(), buffer.length(), script);
} }
static bool bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, SyntacticScopeOption scopeOption, JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char* filename,
const char* filename, MutableHandleScript script) MutableHandleScript script)
{ {
AutoFile file; AutoFile file;
if (!file.open(cx, filename)) if (!file.open(cx, filename))
return false; return false;
CompileOptions options(cx, optionsArg); CompileOptions options(cx, optionsArg);
options.setFileAndLine(filename, 1); options.setFileAndLine(filename, 1);
return ::Compile(cx, options, scopeOption, file.fp(), script); return Compile(cx, options, file.fp(), script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, srcBuf, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, bytes, length, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, chars, length, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, file, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, filename, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, srcBuf, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, bytes, length, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, chars, length, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, file, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, filename, script);
} }
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)
@ -4194,13 +4077,13 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
if (!fun) if (!fun)
return false; return false;
// Make sure the static scope chain matches up when we have a // Make sure to handle cases when we have a polluted scopechain.
// non-syntactic scope.
MOZ_ASSERT_IF(!enclosingDynamicScope->is<GlobalObject>(),
HasNonSyntacticStaticScopeChain(enclosingStaticScope));
CompileOptions options(cx, optionsArg); CompileOptions options(cx, optionsArg);
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope)) if (!enclosingDynamicScope->is<GlobalObject>())
options.setHasPollutedScope(true);
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf,
enclosingStaticScope))
return false; return false;
return true; return true;
@ -4213,8 +4096,8 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& scopeChain,
SourceBufferHolder& srcBuf, MutableHandleFunction fun) SourceBufferHolder& srcBuf, MutableHandleFunction fun)
{ {
RootedObject dynamicScopeObj(cx); RootedObject dynamicScopeObj(cx);
Rooted<ScopeObject*> staticScopeObj(cx); RootedObject staticScopeObj(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj)) if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj))
return false; return false;
return CompileFunction(cx, options, name, nargs, argnames, return CompileFunction(cx, options, name, nargs, argnames,
@ -4288,34 +4171,33 @@ JS_DecompileFunctionBody(JSContext* cx, HandleFunction fun, unsigned indent)
} }
MOZ_NEVER_INLINE static bool MOZ_NEVER_INLINE static bool
ExecuteScript(JSContext* cx, HandleObject scope, HandleScript script, jsval* rval) ExecuteScript(JSContext* cx, HandleObject obj, HandleScript scriptArg, jsval* rval)
{ {
RootedScript script(cx, scriptArg);
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, scope, script); assertSameCompartment(cx, obj, scriptArg);
MOZ_ASSERT_IF(!scope->is<GlobalObject>(), script->hasNonSyntacticScope());
if (!script->hasPollutedGlobalScope() && !obj->is<GlobalObject>()) {
script = CloneScript(cx, nullptr, nullptr, script, HasPollutedGlobalScope);
if (!script)
return false;
js::Debugger::onNewScript(cx, script);
}
AutoLastFrameCheck lfc(cx); AutoLastFrameCheck lfc(cx);
return Execute(cx, script, *scope, rval); return Execute(cx, script, *obj, rval);
} }
static bool static bool
ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptArg, jsval* rval) ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptArg, jsval* rval)
{ {
RootedObject dynamicScope(cx); RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx); RootedObject unusedStaticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope)) if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return false; 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) MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
@ -4349,7 +4231,7 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg)
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
RootedScript script(cx, scriptArg); RootedScript script(cx, scriptArg);
if (script->compartment() != cx->compartment()) { if (script->compartment() != cx->compartment()) {
script = CloneGlobalScript(cx, /* enclosingScope = */ nullptr, script); script = CloneScript(cx, nullptr, nullptr, script);
if (!script) if (!script)
return false; return false;
@ -4361,8 +4243,7 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg)
static const unsigned LARGE_SCRIPT_LENGTH = 500*1024; static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
static bool static bool
Evaluate(JSContext* cx, HandleObject scope, Handle<ScopeObject*> staticScope, Evaluate(JSContext* cx, HandleObject scope, const ReadOnlyCompileOptions& optionsArg,
const ReadOnlyCompileOptions& optionsArg,
SourceBufferHolder& srcBuf, MutableHandleValue rval) SourceBufferHolder& srcBuf, MutableHandleValue rval)
{ {
CompileOptions options(cx, optionsArg); CompileOptions options(cx, optionsArg);
@ -4373,14 +4254,12 @@ Evaluate(JSContext* cx, HandleObject scope, Handle<ScopeObject*> staticScope,
AutoLastFrameCheck lfc(cx); AutoLastFrameCheck lfc(cx);
MOZ_ASSERT_IF(!scope->is<GlobalObject>(), HasNonSyntacticStaticScopeChain(staticScope)); options.setHasPollutedScope(!scope->is<GlobalObject>());
options.setIsRunOnce(true); options.setIsRunOnce(true);
SourceCompressionTask sct(cx); SourceCompressionTask sct(cx);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scope, staticScope, scope, nullptr, nullptr, options,
/* evalCaller = */ nullptr, options, srcBuf, nullptr, 0, &sct));
srcBuf, /* source = */ nullptr, 0, &sct));
if (!script) if (!script)
return false; return false;
@ -4410,10 +4289,10 @@ Evaluate(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptio
SourceBufferHolder& srcBuf, MutableHandleValue rval) SourceBufferHolder& srcBuf, MutableHandleValue rval)
{ {
RootedObject dynamicScope(cx); RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx); RootedObject unusedStaticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope)) if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return false; return false;
return ::Evaluate(cx, dynamicScope, staticScope, optionsArg, srcBuf, rval); return ::Evaluate(cx, dynamicScope, optionsArg, srcBuf, rval);
} }
static bool static bool
@ -4421,7 +4300,7 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char16_t* chars, size_t length, MutableHandleValue rval) const char16_t* chars, size_t length, MutableHandleValue rval)
{ {
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval);
} }
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
@ -4437,7 +4316,7 @@ JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
return false; return false;
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership); SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership);
bool ok = ::Evaluate(cx, cx->global(), nullptr, options, srcBuf, rval); bool ok = ::Evaluate(cx, cx->global(), options, srcBuf, rval);
return ok; return ok;
} }
@ -4461,7 +4340,7 @@ JS_PUBLIC_API(bool)
JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
SourceBufferHolder& srcBuf, MutableHandleValue rval) SourceBufferHolder& srcBuf, MutableHandleValue rval)
{ {
return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval);
} }
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)

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

@ -3446,6 +3446,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
utf8(false), utf8(false),
lineno(1), lineno(1),
column(0), column(0),
hasPollutedGlobalScope(false),
isRunOnce(false), isRunOnce(false),
forEval(false), forEval(false),
noScriptRval(false), noScriptRval(false),
@ -3485,6 +3486,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
bool utf8; bool utf8;
unsigned lineno; unsigned lineno;
unsigned column; unsigned column;
bool hasPollutedGlobalScope;
// isRunOnce only applies to non-function scripts. // isRunOnce only applies to non-function scripts.
bool isRunOnce; bool isRunOnce;
bool forEval; bool forEval;
@ -3577,6 +3579,7 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions
} }
OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; }
OwningCompileOptions& setColumn(unsigned c) { column = c; 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& setIsRunOnce(bool once) { isRunOnce = once; return *this; }
OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; } OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; }
OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
@ -3660,6 +3663,7 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
} }
CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setUTF8(bool u) { utf8 = u; return *this; }
CompileOptions& setColumn(unsigned c) { column = c; 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& setIsRunOnce(bool once) { isRunOnce = once; return *this; }
CompileOptions& setForEval(bool eval) { forEval = eval; return *this; } CompileOptions& setForEval(bool eval) { forEval = eval; return *this; }
CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
@ -3703,32 +3707,12 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script); const char16_t* chars, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, Compile(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file,
FILE* file, JS::MutableHandleScript script); JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename,
const char* filename, JS::MutableHandleScript script); JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);

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

@ -35,7 +35,6 @@
#include "jit/JitFrameIterator.h" #include "jit/JitFrameIterator.h"
#include "js/CallNonGenericMethod.h" #include "js/CallNonGenericMethod.h"
#include "js/Proxy.h" #include "js/Proxy.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h" #include "vm/GlobalObject.h"
#include "vm/Interpreter.h" #include "vm/Interpreter.h"
#include "vm/Shape.h" #include "vm/Shape.h"
@ -525,7 +524,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
HasSingletonType = 0x8 HasSingletonType = 0x8
}; };
/* NB: Keep this in sync with CloneInnerInterpretedFunction. */ /* NB: Keep this in sync with CloneFunctionAndScript. */
RootedAtom atom(xdr->cx()); RootedAtom atom(xdr->cx());
uint32_t firstword = 0; /* bitmask of FirstWordFlag */ uint32_t firstword = 0; /* bitmask of FirstWordFlag */
uint32_t flagsword = 0; /* word for argument count and fun->flags */ uint32_t flagsword = 0; /* word for argument count and fun->flags */
@ -616,9 +615,10 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
fun->setFlags(uint16_t(flagsword)); fun->setFlags(uint16_t(flagsword));
fun->initAtom(atom); fun->initAtom(atom);
if (firstword & IsLazy) { if (firstword & IsLazy) {
MOZ_ASSERT(fun->lazyScript() == lazy); fun->initLazyScript(lazy);
} else { } else {
MOZ_ASSERT(fun->nonLazyScript() == script); fun->initScript(script);
script->setFunction(fun);
MOZ_ASSERT(fun->nargs() == script->bindings.numArgs()); MOZ_ASSERT(fun->nargs() == script->bindings.numArgs());
} }
@ -637,6 +637,44 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleObject, HandleScript, Mu
template bool template bool
js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleObject, HandleScript, MutableHandleFunction); js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleObject, HandleScript, MutableHandleFunction);
JSObject*
js::CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun,
PollutedGlobalScopeOption polluted)
{
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
gc::AllocKind allocKind = srcFun->getAllocKind();
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED, nullptr, nullptr,
cloneProto, allocKind, TenuredObject));
if (!clone)
return nullptr;
JSScript::AutoDelazify srcScript(cx, srcFun);
if (!srcScript)
return nullptr;
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript, polluted));
if (!clonedScript)
return nullptr;
clone->setArgCount(srcFun->nargs());
clone->setFlags(srcFun->flags());
clone->initAtom(srcFun->displayAtom());
clone->initScript(clonedScript);
clonedScript->setFunction(clone);
if (!JSFunction::setTypeForScriptedFunction(cx, clone))
return nullptr;
RootedScript cloneScript(cx, clone->nonLazyScript());
return clone;
}
/* /*
* [[HasInstance]] internal method for Function objects: fetch the .prototype * [[HasInstance]] internal method for Function objects: fetch the .prototype
* property of its 'this' parameter, and walks the prototype chain of v (only * property of its 'this' parameter, and walks the prototype chain of v (only
@ -790,7 +828,7 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
/* /*
* The default 'new' group of Function.prototype is required by type * The default 'new' group of Function.prototype is required by type
* inference to have unknown properties, to simplify handling of e.g. * inference to have unknown properties, to simplify handling of e.g.
* NewFunctionClone. * CloneFunctionObject.
*/ */
if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto)) if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto))
return nullptr; return nullptr;
@ -1385,13 +1423,16 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
if (script) { if (script) {
RootedObject enclosingScope(cx, lazy->enclosingScope()); RootedObject enclosingScope(cx, lazy->enclosingScope());
RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, enclosingScope, fun, script)); RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
if (!clonedScript) if (!clonedScript)
return false; return false;
clonedScript->setSourceObject(lazy->sourceObject()); clonedScript->setSourceObject(lazy->sourceObject());
fun->initAtom(script->functionNonDelazifying()->displayAtom()); fun->initAtom(script->functionNonDelazifying()->displayAtom());
clonedScript->setFunction(fun);
fun->setUnlazifiedScript(clonedScript);
if (!lazy->maybeScript()) if (!lazy->maybeScript())
lazy->initScript(clonedScript); lazy->initScript(clonedScript);
@ -1978,20 +2019,6 @@ js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
atom, nullptr, allocKind, newKind); atom, nullptr, allocKind, newKind);
} }
#ifdef DEBUG
static bool
NewFunctionScopeIsWellFormed(ExclusiveContext* cx, HandleObject parent)
{
// Assert that the parent is null, global, or a debug scope proxy. All
// other cases of polluting global scope behavior are handled by
// ScopeObjects (viz. non-syntactic DynamicWithObject and
// NonSyntacticVariablesObject).
RootedObject realParent(cx, SkipScopeParent(parent));
return !realParent || realParent == cx->global() ||
realParent->is<DebugScopeObject>();
}
#endif
JSFunction* JSFunction*
js::NewFunctionWithProto(ExclusiveContext* cx, Native native, js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope, unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope,
@ -2001,7 +2028,6 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
{ {
MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED); MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED);
MOZ_ASSERT_IF(native, !enclosingDynamicScope); MOZ_ASSERT_IF(native, !enclosingDynamicScope);
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, enclosingDynamicScope));
RootedObject funobj(cx); RootedObject funobj(cx);
// Don't mark asm.js module functions as singleton since they are // Don't mark asm.js module functions as singleton since they are
@ -2009,6 +2035,17 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
// isSingleton implies isInterpreted. // isSingleton implies isInterpreted.
if (native && !IsAsmJSModuleNative(native)) if (native && !IsAsmJSModuleNative(native))
newKind = SingletonObject; newKind = SingletonObject;
#ifdef DEBUG
RootedObject nonScopeParent(cx, SkipScopeParent(enclosingDynamicScope));
// We'd like to assert that nonScopeParent is null-or-global, but
// js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
// Assert that it's one of those or a debug scope proxy or the unqualified
// var obj, since it should still be ok to parent to the global in that
// case.
MOZ_ASSERT(!nonScopeParent || nonScopeParent == cx->global() ||
nonScopeParent->is<DebugScopeObject>() ||
nonScopeParent->isUnqualifiedVarObj());
#endif
funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind, funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
newKind); newKind);
if (!funobj) if (!funobj)
@ -2042,8 +2079,8 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
} }
bool bool
js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, js::CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
HandleObject newParent) HandleObject newParent)
{ {
if (compartment != fun->compartment() || if (compartment != fun->compartment() ||
fun->isSingleton() || fun->isSingleton() ||
@ -2064,36 +2101,75 @@ js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun,
return true; return true;
// We need to clone the script if we're interpreted and not already marked // We need to clone the script if we're interpreted and not already marked
// as having a non-syntactic scope. If we're lazy, go ahead and clone the // as having a polluted scope. If we're lazy, go ahead and clone the
// script; see the big comment at the end of CopyScriptInternal for the // script; see the big comment at the end of CloneScript for the explanation
// explanation of what's going on there. // of what's going on there.
return !fun->isInterpreted() || return !fun->isInterpreted() ||
(fun->hasScript() && fun->nonLazyScript()->hasNonSyntacticScope()); (fun->hasScript() && fun->nonLazyScript()->hasPollutedGlobalScope());
} }
static inline JSFunction* JSFunction*
NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind, js::CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind allocKind, HandleObject proto) gc::AllocKind allocKind,
NewObjectKind newKindArg /* = GenericObject */,
HandleObject proto)
{ {
MOZ_ASSERT(parent);
MOZ_ASSERT(!fun->isBoundFunction());
bool useSameScript = CloneFunctionObjectUseSameScript(cx->compartment(), fun, parent);
NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
RootedObject cloneProto(cx, proto); RootedObject cloneProto(cx, proto);
if (!proto && fun->isStarGenerator()) { if (!cloneProto && fun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto) if (!cloneProto)
return nullptr; return nullptr;
} }
#ifdef DEBUG
RootedObject realParent(cx, SkipScopeParent(parent));
// We'd like to assert that realParent is null-or-global, but
// js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
// Assert that it's one of those or a debug scope proxy or the unqualified
// var obj, since it should still be ok to parent to the global in that
// case.
MOZ_ASSERT(!realParent || realParent == cx->global() ||
realParent->is<DebugScopeObject>() ||
realParent->isUnqualifiedVarObj());
#endif
JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto, JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
allocKind, newKind); allocKind, newKind);
if (!cloneobj) if (!cloneobj)
return nullptr; return nullptr;
RootedFunction clone(cx, &cloneobj->as<JSFunction>()); RootedFunction clone(cx, &cloneobj->as<JSFunction>());
JSScript::AutoDelazify funScript(cx);
if (!useSameScript && fun->isInterpretedLazy()) {
funScript = fun;
if (!funScript)
return nullptr;
}
MOZ_ASSERT(useSameScript || !fun->isInterpretedLazy());
uint16_t flags = fun->flags() & ~JSFunction::EXTENDED; uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
if (allocKind == AllocKind::FUNCTION_EXTENDED) if (allocKind == AllocKind::FUNCTION_EXTENDED)
flags |= JSFunction::EXTENDED; flags |= JSFunction::EXTENDED;
clone->setArgCount(fun->nargs()); clone->setArgCount(fun->nargs());
clone->setFlags(flags); clone->setFlags(flags);
if (fun->hasScript()) {
clone->initScript(fun->nonLazyScript());
clone->initEnvironment(parent);
} else if (fun->isInterpretedLazy()) {
MOZ_ASSERT(fun->compartment() == clone->compartment());
MOZ_ASSERT(useSameScript);
LazyScript* lazy = fun->lazyScriptOrNull();
clone->initLazyScript(lazy);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
}
clone->initAtom(fun->displayAtom()); clone->initAtom(fun->displayAtom());
if (allocKind == AllocKind::FUNCTION_EXTENDED) { if (allocKind == AllocKind::FUNCTION_EXTENDED) {
@ -2105,97 +2181,34 @@ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
} }
} }
return clone; if (useSameScript) {
} /*
* Clone the function, reusing its script. We can use the same group as
JSFunction* * the original function provided that its prototype is correct.
js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent, */
gc::AllocKind allocKind /* = FUNCTION */ , if (fun->getProto() == clone->getProto())
NewObjectKind newKind /* = GenericObject */, clone->setGroup(fun->group());
HandleObject proto /* = nullptr */) return clone;
{
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, parent));
MOZ_ASSERT(!fun->isBoundFunction());
MOZ_ASSERT(CanReuseScriptForClone(cx->compartment(), fun, parent));
RootedFunction clone(cx, NewFunctionClone(cx, fun, newKind, allocKind, proto));
if (!clone)
return nullptr;
if (fun->hasScript()) {
clone->initScript(fun->nonLazyScript());
clone->initEnvironment(parent);
} else if (fun->isInterpretedLazy()) {
MOZ_ASSERT(fun->compartment() == clone->compartment());
LazyScript* lazy = fun->lazyScriptOrNull();
clone->initLazyScript(lazy);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
} }
RootedFunction cloneRoot(cx, clone);
/* /*
* Clone the function, reusing its script. We can use the same group as * Across compartments or if we have to introduce a polluted scope we have
* the original function provided that its prototype is correct. * to clone the script for interpreted functions. Cross-compartment cloning
* only happens via JSAPI (JS::CloneFunctionObject) which dynamically
* ensures that 'script' has no enclosing lexical scope (only the global
* scope or other non-lexical scope).
*/ */
if (fun->getProto() == clone->getProto()) PollutedGlobalScopeOption globalScopeOption = parent->is<GlobalObject>() ?
clone->setGroup(fun->group()); HasCleanGlobalScope : HasPollutedGlobalScope;
return clone; if (cloneRoot->isInterpreted() &&
} !CloneFunctionScript(cx, fun, cloneRoot, globalScopeOption, newKindArg))
{
JSFunction*
js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
HandleObject newStaticScope,
gc::AllocKind allocKind /* = FUNCTION */,
HandleObject proto /* = nullptr */)
{
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, parent));
MOZ_ASSERT(!fun->isBoundFunction());
RootedFunction clone(cx, NewFunctionClone(cx, fun, SingletonObject, allocKind, proto));
if (!clone)
return nullptr; return nullptr;
if (fun->hasScript()) {
clone->initScript(nullptr);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
} }
/* return cloneRoot;
* Across compartments or if we have to introduce a non-syntactic scope we
* have to clone the script for interpreted functions. Cross-compartment
* cloning only happens via JSAPI (JS::CloneFunctionObject) which
* dynamically ensures that 'script' has no enclosing lexical scope (only
* the global scope or other non-lexical scope).
*/
#ifdef DEBUG
RootedObject terminatingScope(cx, parent);
while (IsSyntacticScope(terminatingScope))
terminatingScope = terminatingScope->enclosingScope();
MOZ_ASSERT_IF(!terminatingScope->is<GlobalObject>(),
HasNonSyntacticStaticScopeChain(newStaticScope));
#endif
if (clone->isInterpreted()) {
JSScript::AutoDelazify funScript(cx);
funScript = fun;
if (!funScript)
return nullptr;
RootedScript script(cx, fun->nonLazyScript());
MOZ_ASSERT(script->compartment() == fun->compartment());
MOZ_ASSERT(cx->compartment() == clone->compartment(),
"Otherwise we could relazify clone below!");
RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, newStaticScope, clone, script));
if (!clonedScript)
return nullptr;
Debugger::onNewScript(cx, clonedScript);
}
return clone;
} }
/* /*

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

@ -633,20 +633,14 @@ class FunctionExtended : public JSFunction
}; };
extern bool extern bool
CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent); CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
HandleObject newParent);
extern JSFunction* extern JSFunction*
CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent, CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = gc::AllocKind::FUNCTION, gc::AllocKind kind = gc::AllocKind::FUNCTION,
NewObjectKind newKindArg = GenericObject, NewObjectKind newKindArg = GenericObject,
HandleObject proto = nullptr); HandleObject proto = nullptr);
// Functions whose scripts are cloned are always given singleton types.
extern JSFunction*
CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
HandleObject newStaticScope,
gc::AllocKind kind = gc::AllocKind::FUNCTION,
HandleObject proto = nullptr);
extern bool extern bool
FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart, FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
@ -708,6 +702,10 @@ bool
XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
HandleScript enclosingScript, MutableHandleFunction objp); HandleScript enclosingScript, MutableHandleFunction objp);
extern JSObject*
CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
PollutedGlobalScopeOption polluted);
/* /*
* Report an error that call.thisv is not compatible with the specified class, * Report an error that call.thisv is not compatible with the specified class,
* assuming that the method (clasp->name).prototype.<name of callee function> * assuming that the method (clasp->name).prototype.<name of callee function>

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

@ -85,12 +85,7 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec
gc::AllocKind kind = fun->isExtended() gc::AllocKind kind = fun->isExtended()
? extendedFinalizeKind ? extendedFinalizeKind
: finalizeKind; : finalizeKind;
return CloneFunctionObject(cx, fun, parent, kind, newKind, proto);
if (CanReuseScriptForClone(cx->compartment(), fun, parent))
return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto);
RootedObject staticScope(cx, fun->getOrCreateScript(cx)->enclosingStaticScope());
return CloneFunctionAndScript(cx, fun, parent, staticScope, kind, proto);
} }
} /* namespace js */ } /* namespace js */

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

@ -1076,7 +1076,7 @@ NewObjectGCKind(const js::Class* clasp)
static inline JSObject* static inline JSObject*
NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind, NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
NewObjectKind newKind, uint32_t initialShapeFlags = 0) NewObjectKind newKind)
{ {
const Class* clasp = group->clasp(); const Class* clasp = group->clasp();
@ -1091,8 +1091,7 @@ NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp) ? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
: GetGCKindSlots(kind, clasp); : GetGCKindSlots(kind, clasp);
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(), nfixed, RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(), nfixed));
initialShapeFlags));
if (!shape) if (!shape)
return nullptr; return nullptr;
@ -1140,8 +1139,7 @@ NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto>
JSObject* JSObject*
js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp, js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
Handle<TaggedProto> proto, Handle<TaggedProto> proto,
gc::AllocKind allocKind, NewObjectKind newKind, gc::AllocKind allocKind, NewObjectKind newKind)
uint32_t initialShapeFlags)
{ {
if (CanBeFinalizedInBackground(allocKind, clasp)) if (CanBeFinalizedInBackground(allocKind, clasp))
allocKind = GetBackgroundAllocKind(allocKind); allocKind = GetBackgroundAllocKind(allocKind);
@ -1163,7 +1161,7 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
if (!group) if (!group)
return nullptr; return nullptr;
RootedObject obj(cxArg, NewObject(cxArg, group, allocKind, newKind, initialShapeFlags)); RootedObject obj(cxArg, NewObject(cxArg, group, allocKind, newKind));
if (!obj) if (!obj)
return nullptr; return nullptr;

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

@ -422,10 +422,10 @@ class JSObject : public js::gc::Cell
* slot of the object. For other scope objects, the chain goes directly to * slot of the object. For other scope objects, the chain goes directly to
* the global. * the global.
* *
* In code which is not marked hasNonSyntacticScope, scope chains can * In code which is not marked hasPollutedGlobalScope, scope chains can
* contain only syntactic scope objects (see IsSyntacticScope) with a global * contain only syntactic scope objects (see IsSyntacticScope) with a global
* object at the root as the scope of the outermost non-function script. In * object at the root as the scope of the outermost non-function script. In
* hasNonSyntacticScope code, the scope of the outermost non-function * hasPollutedGlobalScope code, the scope of the outermost non-function
* script might not be a global object, and can have a mix of other objects * script might not be a global object, and can have a mix of other objects
* above it before the global object is reached. * above it before the global object is reached.
*/ */

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

@ -224,9 +224,6 @@ JSObject::isQualifiedVarObj()
{ {
if (is<js::DebugScopeObject>()) if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isQualifiedVarObj(); return as<js::DebugScopeObject>().scope().isQualifiedVarObj();
// TODO: We would like to assert that only GlobalObject or
// NonSyntacticVariables object is a qualified varobj, but users of
// js::Execute still need to be vetted. See bug 1171177.
return hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ); return hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
} }
@ -235,9 +232,7 @@ JSObject::isUnqualifiedVarObj()
{ {
if (is<js::DebugScopeObject>()) if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isUnqualifiedVarObj(); return as<js::DebugScopeObject>().scope().isUnqualifiedVarObj();
bool rv = hasAllFlags(js::BaseShape::UNQUALIFIED_VAROBJ); return hasAllFlags(js::BaseShape::UNQUALIFIED_VAROBJ);
MOZ_ASSERT_IF(rv, is<js::GlobalObject>() || is<js::NonSyntacticVariablesObject>());
return rv;
} }
namespace js { namespace js {
@ -608,38 +603,25 @@ typedef AutoVectorRooter<PropertyDescriptor> AutoPropertyDescriptorVector;
*/ */
JSObject* JSObject*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto, NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
gc::AllocKind allocKind, NewObjectKind newKind, gc::AllocKind allocKind, NewObjectKind newKind);
uint32_t initialShapeFlags = 0);
inline JSObject* inline JSObject*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto, NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
NewObjectKind newKind = GenericObject, NewObjectKind newKind = GenericObject)
uint32_t initialShapeFlags = 0)
{ {
gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind, initialShapeFlags); return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind);
} }
template <typename T> template <typename T>
inline T* inline T*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, Handle<TaggedProto> proto, NewObjectWithGivenTaggedProto(ExclusiveContext* cx, Handle<TaggedProto> proto,
NewObjectKind newKind = GenericObject, NewObjectKind newKind = GenericObject)
uint32_t initialShapeFlags = 0)
{ {
JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind, JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind);
initialShapeFlags);
return obj ? &obj->as<T>() : nullptr; return obj ? &obj->as<T>() : nullptr;
} }
template <typename T>
inline T*
NewObjectWithNullTaggedProto(ExclusiveContext* cx, NewObjectKind newKind = GenericObject,
uint32_t initialShapeFlags = 0)
{
Rooted<TaggedProto> nullProto(cx, TaggedProto(nullptr));
return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
}
inline JSObject* inline JSObject*
NewObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto, NewObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
gc::AllocKind allocKind, NewObjectKind newKind) gc::AllocKind allocKind, NewObjectKind newKind)

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

@ -576,10 +576,10 @@ enum XDRClassKind {
template<XDRMode mode> template<XDRMode mode>
bool bool
js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript enclosingScript, js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
HandleFunction fun, MutableHandleScript scriptp) HandleFunction fun, MutableHandleScript scriptp)
{ {
/* NB: Keep this in sync with CopyScript. */ /* NB: Keep this in sync with CloneScript. */
enum ScriptBits { enum ScriptBits {
NoScriptRval, NoScriptRval,
@ -600,7 +600,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
HasSingleton, HasSingleton,
TreatAsRunOnce, TreatAsRunOnce,
HasLazyScript, HasLazyScript,
HasNonSyntacticScope, HasPollutedGlobalScope,
}; };
uint32_t length, lineno, column, nslots, staticLevel; uint32_t length, lineno, column, nslots, staticLevel;
@ -613,7 +613,6 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
JSContext* cx = xdr->cx(); JSContext* cx = xdr->cx();
RootedScript script(cx); RootedScript script(cx);
RootedObject enclosingScope(cx, enclosingScopeArg);
natoms = nsrcnotes = 0; natoms = nsrcnotes = 0;
nconsts = nobjects = nregexps = ntrynotes = nblockscopes = nyieldoffsets = 0; nconsts = nobjects = nregexps = ntrynotes = nblockscopes = nyieldoffsets = 0;
@ -733,8 +732,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
scriptBits |= (1 << TreatAsRunOnce); scriptBits |= (1 << TreatAsRunOnce);
if (script->isRelazifiable()) if (script->isRelazifiable())
scriptBits |= (1 << HasLazyScript); scriptBits |= (1 << HasLazyScript);
if (script->hasNonSyntacticScope()) if (script->hasPollutedGlobalScope())
scriptBits |= (1 << HasNonSyntacticScope); scriptBits |= (1 << HasPollutedGlobalScope);
} }
if (!xdr->codeUint32(&prologueLength)) if (!xdr->codeUint32(&prologueLength))
@ -802,26 +801,10 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
MOZ_ASSERT(enclosingScript->sourceObject()->is<ScriptSourceObject>()); MOZ_ASSERT(enclosingScript->sourceObject()->is<ScriptSourceObject>());
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>(); sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
} }
// If the outermost script has a non-syntactic scope, reflect that on
// the static scope chain.
if (scriptBits & (1 << HasNonSyntacticScope) && !enclosingScope) {
enclosingScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
if (!enclosingScope)
return false;
}
script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)), script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
options, /* staticLevel = */ 0, sourceObject, 0, 0); options, /* staticLevel = */ 0, sourceObject, 0, 0);
if (!script) if (!script)
return false; return false;
// Set the script in its function now so that inner scripts to be
// decoded may iterate the static scope chain.
if (fun) {
fun->initScript(script);
script->setFunction(fun);
}
} }
/* JSScript::partiallyInit assumes script->bindings is fully initialized. */ /* JSScript::partiallyInit assumes script->bindings is fully initialized. */
@ -866,8 +849,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
script->hasSingletons_ = true; script->hasSingletons_ = true;
if (scriptBits & (1 << TreatAsRunOnce)) if (scriptBits & (1 << TreatAsRunOnce))
script->treatAsRunOnce_ = true; script->treatAsRunOnce_ = true;
if (scriptBits & (1 << HasNonSyntacticScope)) if (scriptBits & (1 << HasPollutedGlobalScope))
script->hasNonSyntacticScope_ = true; script->hasPollutedGlobalScope_ = true;
if (scriptBits & (1 << IsLegacyGenerator)) { if (scriptBits & (1 << IsLegacyGenerator)) {
MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator))); MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
@ -999,7 +982,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
MOZ_ASSERT(enclosingStaticScopeIndex < i); MOZ_ASSERT(enclosingStaticScopeIndex < i);
enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex]; enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
} else { } else {
enclosingStaticScope = fun ? fun : enclosingScope; enclosingStaticScope = fun;
} }
} }
@ -1036,15 +1019,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
StaticScopeIter<NoGC> ssi(funEnclosingScope); StaticScopeIter<NoGC> ssi(funEnclosingScope);
// Starting from a nested function, hitting a non-syntactic if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::Function) {
// scope on the static scope chain means that its enclosing MOZ_ASSERT(ssi.done() == !fun);
// function has a non-syntactic scope. Nested functions
// themselves never have non-syntactic scope chains.
if (ssi.done() ||
ssi.type() == StaticScopeIter<NoGC>::NonSyntactic ||
ssi.type() == StaticScopeIter<NoGC>::Function)
{
MOZ_ASSERT_IF(ssi.done() || ssi.type() != StaticScopeIter<NoGC>::Function, !fun);
funEnclosingScopeIndex = UINT32_MAX; funEnclosingScopeIndex = UINT32_MAX;
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) { } else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block()); funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
@ -1060,7 +1036,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
if (funEnclosingScopeIndex == UINT32_MAX) { if (funEnclosingScopeIndex == UINT32_MAX) {
funEnclosingScope = fun ? fun : enclosingScope; funEnclosingScope = fun;
} else { } else {
MOZ_ASSERT(funEnclosingScopeIndex < i); MOZ_ASSERT(funEnclosingScopeIndex < i);
funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex]; funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
@ -1201,13 +1177,9 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript
return false; return false;
} }
if (mode == XDR_DECODE) { if (mode == XDR_DECODE)
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
packedFields, begin, end, lineno, column)); packedFields, begin, end, lineno, column));
if (!lazy)
return false;
fun->initLazyScript(lazy);
}
} }
// Code free variables. // Code free variables.
@ -2457,16 +2429,11 @@ JSScript::Create(ExclusiveContext* cx, HandleObject enclosingScope, bool savedCa
script->savedCallerFun_ = savedCallerFun; script->savedCallerFun_ = savedCallerFun;
script->initCompartment(cx); script->initCompartment(cx);
script->hasPollutedGlobalScope_ = options.hasPollutedGlobalScope;
script->selfHosted_ = options.selfHostingMode; script->selfHosted_ = options.selfHostingMode;
script->noScriptRval_ = options.noScriptRval; script->noScriptRval_ = options.noScriptRval;
script->treatAsRunOnce_ = options.isRunOnce; 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; script->version = options.version;
MOZ_ASSERT(script->getVersion() == options.version); // assert that no overflow occurred MOZ_ASSERT(script->getVersion() == options.version); // assert that no overflow occurred
@ -2701,13 +2668,10 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
RootedFunction fun(cx, nullptr); RootedFunction fun(cx, nullptr);
if (funbox) { 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()); MOZ_ASSERT(!bce->script->noScriptRval());
script->isGeneratorExp_ = funbox->inGenexpLambda; script->isGeneratorExp_ = funbox->inGenexpLambda;
script->setGeneratorKind(funbox->generatorKind()); script->setGeneratorKind(funbox->generatorKind());
script->setFunction(funbox->function());
if (bce->yieldOffsetList.length() != 0) if (bce->yieldOffsetList.length() != 0)
bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength); bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
} }
@ -3040,48 +3004,15 @@ Rebase(JSScript* dst, JSScript* src, T* srcp)
return reinterpret_cast<T*>(dst->data + off); return reinterpret_cast<T*>(dst->data + off);
} }
static JSObject* JSScript*
CloneInnerInterpretedFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun) js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
{ PollutedGlobalScopeOption polluted /* = HasCleanGlobalScope */,
/* NB: Keep this in sync with XDRInterpretedFunction. */ NewObjectKind newKind /* = GenericObject */)
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
gc::AllocKind allocKind = srcFun->getAllocKind();
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED, nullptr, nullptr,
cloneProto, allocKind, TenuredObject));
if (!clone)
return nullptr;
JSScript::AutoDelazify srcScript(cx, srcFun);
if (!srcScript)
return nullptr;
JSScript* cloneScript = CloneScriptIntoFunction(cx, enclosingScope, clone, srcScript);
if (!cloneScript)
return nullptr;
clone->setArgCount(srcFun->nargs());
clone->setFlags(srcFun->flags());
clone->initAtom(srcFun->displayAtom());
if (!JSFunction::setTypeForScriptedFunction(cx, clone))
return nullptr;
return clone;
}
bool
js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src,
HandleScript dst)
{ {
if (src->treatAsRunOnce() && !src->functionNonDelazifying()) { if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
// Toplevel run-once scripts may not be cloned. // Toplevel run-once scripts may not be cloned.
JS_ReportError(cx, "No cloning toplevel run-once scripts"); JS_ReportError(cx, "No cloning toplevel run-once scripts");
return false; return nullptr;
} }
/* NB: Keep this in sync with XDRScript. */ /* NB: Keep this in sync with XDRScript. */
@ -3100,7 +3031,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
size_t size = src->dataSize(); size_t size = src->dataSize();
uint8_t* data = AllocScriptData(cx->zone(), size); uint8_t* data = AllocScriptData(cx->zone(), size);
if (size && !data) if (size && !data)
return false; return nullptr;
/* Bindings */ /* Bindings */
@ -3108,7 +3039,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
InternalHandle<Bindings*> bindingsHandle = InternalHandle<Bindings*> bindingsHandle =
InternalHandle<Bindings*>::fromMarkedLocation(bindings.address()); InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
if (!Bindings::clone(cx, bindingsHandle, data, src)) if (!Bindings::clone(cx, bindingsHandle, data, src))
return false; return nullptr;
/* Objects */ /* Objects */
@ -3125,7 +3056,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope())
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)]; enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
else else
enclosingScope = scriptStaticScope; enclosingScope = fun;
clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock); clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
} else if (obj->is<JSFunction>()) { } else if (obj->is<JSFunction>()) {
@ -3134,36 +3065,32 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
if (cx->compartment() != innerFun->compartment()) { if (cx->compartment() != innerFun->compartment()) {
MOZ_ASSERT(innerFun->isAsmJSNative()); MOZ_ASSERT(innerFun->isAsmJSNative());
JS_ReportError(cx, "AsmJS modules do not yet support cloning."); JS_ReportError(cx, "AsmJS modules do not yet support cloning.");
return false; return nullptr;
} }
clone = innerFun; clone = innerFun;
} else { } else {
if (innerFun->isInterpretedLazy()) { if (innerFun->isInterpretedLazy()) {
AutoCompartment ac(cx, innerFun); AutoCompartment ac(cx, innerFun);
if (!innerFun->getOrCreateScript(cx)) if (!innerFun->getOrCreateScript(cx))
return false; return nullptr;
} }
RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope()); RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
StaticScopeIter<CanGC> ssi(cx, staticScope); StaticScopeIter<CanGC> ssi(cx, staticScope);
RootedObject enclosingScope(cx); RootedObject enclosingScope(cx);
if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::NonSyntactic) { if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::Function)
enclosingScope = scriptStaticScope; enclosingScope = fun;
} else if (ssi.type() == StaticScopeIter<CanGC>::Function) { else if (ssi.type() == StaticScopeIter<CanGC>::Block)
MOZ_ASSERT(scriptStaticScope->is<JSFunction>());
enclosingScope = scriptStaticScope;
} else if (ssi.type() == StaticScopeIter<CanGC>::Block) {
enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())]; enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
} else { else
enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())]; enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
}
clone = CloneInnerInterpretedFunction(cx, enclosingScope, innerFun); clone = CloneFunctionAndScript(cx, enclosingScope, innerFun, polluted);
} }
} else { } else {
clone = DeepCloneObjectLiteral(cx, obj, TenuredObject); clone = DeepCloneObjectLiteral(cx, obj, TenuredObject);
} }
if (!clone || !objects.append(clone)) if (!clone || !objects.append(clone))
return false; return nullptr;
} }
} }
@ -3175,11 +3102,50 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
for (unsigned i = 0; i < nregexps; i++) { for (unsigned i = 0; i < nregexps; i++) {
JSObject* clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>()); JSObject* clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
if (!clone || !regexps.append(clone)) if (!clone || !regexps.append(clone))
return false; return nullptr;
} }
} }
/* Now that all fallible allocation is complete, do the copying. */ /*
* Wrap the script source object as needed. Self-hosted scripts may be
* in another runtime, so lazily create a new script source object to
* use for them.
*/
RootedObject sourceObject(cx);
if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
if (!cx->compartment()->selfHostingScriptSource) {
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
ScriptSourceObject* obj = frontend::CreateScriptSourceObject(cx, options);
if (!obj)
return nullptr;
cx->compartment()->selfHostingScriptSource.set(obj);
}
sourceObject = cx->compartment()->selfHostingScriptSource;
} else {
sourceObject = src->sourceObject();
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
}
/* Now that all fallible allocation is complete, create the GC thing. */
CompileOptions options(cx);
options.setMutedErrors(src->mutedErrors())
.setHasPollutedScope(src->hasPollutedGlobalScope() ||
polluted == HasPollutedGlobalScope)
.setSelfHostingMode(src->selfHosted())
.setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion());
RootedScript dst(cx, JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
options, src->staticLevel(),
sourceObject, src->sourceStart(), src->sourceEnd()));
if (!dst) {
js_free(data);
return nullptr;
}
dst->bindings = bindings; dst->bindings = bindings;
@ -3241,107 +3207,61 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
/* /*
* Function delazification assumes that their script does not have a * Function delazification assumes that their script does not have a
* non-syntactic global scope. We ensure that as follows: * polluted global scope. We ensure that as follows:
* *
* 1) Initial parsing only creates lazy functions if * 1) Initial parsing only creates lazy functions if
* !hasNonSyntacticScope. * !hasPollutedGlobalScope.
* 2) Cloning a lazy function into a non-global scope will always require * 2) Cloning a lazy function into a non-global scope will always require
* that its script be cloned. See comments in * that its script be cloned. See comments in
* CloneFunctionObjectUseSameScript. * CloneFunctionObjectUseSameScript.
* 3) Cloning a script never sets a lazyScript on the clone, so the function * 3) Cloning a script never sets a lazyScript on the clone, so the function
* cannot be relazified. * cannot be relazified.
* *
* If you decide that lazy functions should be supported with a * If you decide that lazy functions should be supported with a polluted
* non-syntactic global scope, make sure delazification can deal. * global scope, make sure delazification can deal.
*/ */
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->maybeLazyScript()); MOZ_ASSERT_IF(dst->hasPollutedGlobalScope(), !dst->maybeLazyScript());
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->isRelazifiable()); MOZ_ASSERT_IF(dst->hasPollutedGlobalScope(), !dst->isRelazifiable());
return dst;
}
bool
js::CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
PollutedGlobalScopeOption polluted, NewObjectKind newKind)
{
RootedScript script(cx, clone->nonLazyScript());
MOZ_ASSERT(script);
MOZ_ASSERT(script->compartment() == original->compartment());
MOZ_ASSERT(cx->compartment() == clone->compartment(),
"Otherwise we could relazify clone below!");
// The only scripts with enclosing static scopes that may be cloned across
// compartments are non-strict, indirect eval scripts, as their dynamic
// scope chains terminate in the global scope immediately.
RootedObject scope(cx, script->enclosingStaticScope());
if (script->compartment() != cx->compartment() && scope) {
MOZ_ASSERT(!scope->as<StaticEvalObject>().isDirect() &&
!scope->as<StaticEvalObject>().isStrict());
scope = StaticEvalObject::create(cx, nullptr);
if (!scope)
return false;
}
clone->initScript(nullptr);
JSScript* cscript = CloneScript(cx, scope, clone, script, polluted, newKind);
if (!cscript)
return false;
clone->setScript(cscript);
cscript->setFunction(clone);
script = clone->nonLazyScript();
Debugger::onNewScript(cx, script);
return true; return true;
} }
static JSScript*
CreateEmptyScriptForClone(JSContext* cx, HandleObject enclosingScope, HandleScript src)
{
/*
* Wrap the script source object as needed. Self-hosted scripts may be
* in another runtime, so lazily create a new script source object to
* use for them.
*/
RootedObject sourceObject(cx);
if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
if (!cx->compartment()->selfHostingScriptSource) {
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
ScriptSourceObject* obj = frontend::CreateScriptSourceObject(cx, options);
if (!obj)
return nullptr;
cx->compartment()->selfHostingScriptSource.set(obj);
}
sourceObject = cx->compartment()->selfHostingScriptSource;
} else {
sourceObject = src->sourceObject();
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
}
CompileOptions options(cx);
options.setMutedErrors(src->mutedErrors())
.setSelfHostingMode(src->selfHosted())
.setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion());
return JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
options, src->staticLevel(),
sourceObject, src->sourceStart(), src->sourceEnd());
}
JSScript*
js::CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src)
{
// No enclosingScope means clean global.
MOZ_ASSERT(!enclosingScope || enclosingScope->is<StaticNonSyntacticScopeObjects>());
RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src));
if (!dst)
return nullptr;
if (!detail::CopyScript(cx, enclosingScope, src, dst))
return nullptr;
return dst;
}
JSScript*
js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
HandleScript src)
{
MOZ_ASSERT(fun->isInterpreted());
// Allocate the destination script up front and set it as the script of
// |fun|, which is to be its container.
//
// This is so that when cloning nested functions, they can walk the static
// scope chain via fun and correctly compute the presence of a
// non-syntactic global.
RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src));
if (!dst)
return nullptr;
dst->setFunction(fun);
if (fun->isInterpretedLazy())
fun->setUnlazifiedScript(dst);
else
fun->initScript(dst);
if (!detail::CopyScript(cx, fun, src, dst)) {
fun->setScript(nullptr);
return nullptr;
}
return dst;
}
DebugScript* DebugScript*
JSScript::debugScript() JSScript::debugScript()
{ {

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

@ -755,6 +755,16 @@ bool
XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript, XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
HandleFunction fun, MutableHandleScript scriptp); HandleFunction fun, MutableHandleScript scriptp);
enum PollutedGlobalScopeOption {
HasPollutedGlobalScope,
HasCleanGlobalScope
};
JSScript*
CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
PollutedGlobalScopeOption polluted = HasCleanGlobalScope,
NewObjectKind newKind = GenericObject);
template<XDRMode mode> template<XDRMode mode>
bool bool
XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript, XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
@ -767,16 +777,6 @@ template<XDRMode mode>
bool bool
XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp); XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp);
namespace detail {
// Do not call this directly! It is exposed for the friend declaration in
// JSScript.
bool
CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src, HandleScript dst);
} // namespace detail
} /* namespace js */ } /* namespace js */
class JSScript : public js::gc::TenuredCell class JSScript : public js::gc::TenuredCell
@ -784,13 +784,13 @@ class JSScript : public js::gc::TenuredCell
template <js::XDRMode mode> template <js::XDRMode mode>
friend friend
bool bool
js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope, js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript,
js::HandleScript enclosingScript,
js::HandleFunction fun, js::MutableHandleScript scriptp); js::HandleFunction fun, js::MutableHandleScript scriptp);
friend bool friend JSScript*
js::detail::CopyScript(JSContext* cx, js::HandleObject scriptStaticScope, js::HandleScript src, js::CloneScript(JSContext* cx, js::HandleObject enclosingScope, js::HandleFunction fun,
js::HandleScript dst); js::HandleScript src, js::PollutedGlobalScopeOption polluted,
js::NewObjectKind newKind);
public: public:
// //
@ -936,7 +936,7 @@ class JSScript : public js::gc::TenuredCell
// True if the script has a non-syntactic scope on its dynamic scope chain. // True if the script has a non-syntactic scope on its dynamic scope chain.
// That is, there are objects about which we know nothing between the // That is, there are objects about which we know nothing between the
// outermost syntactic scope and the global. // outermost syntactic scope and the global.
bool hasNonSyntacticScope_:1; bool hasPollutedGlobalScope_:1;
// see Parser::selfHostingMode. // see Parser::selfHostingMode.
bool selfHosted_:1; bool selfHosted_:1;
@ -1176,8 +1176,8 @@ class JSScript : public js::gc::TenuredCell
bool explicitUseStrict() const { return explicitUseStrict_; } bool explicitUseStrict() const { return explicitUseStrict_; }
bool hasNonSyntacticScope() const { bool hasPollutedGlobalScope() const {
return hasNonSyntacticScope_; return hasPollutedGlobalScope_;
} }
bool selfHosted() const { return selfHosted_; } bool selfHosted() const { return selfHosted_; }
@ -2278,12 +2278,9 @@ DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript maybeScr
uint32_t* pcOffset, bool* mutedErrors, uint32_t* pcOffset, bool* mutedErrors,
LineOption opt = NOT_CALLED_FROM_JSOP_EVAL); LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
JSScript* bool
CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
HandleScript src); PollutedGlobalScopeOption polluted, NewObjectKind newKind);
JSScript*
CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src);
} /* namespace js */ } /* namespace js */

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

@ -4318,36 +4318,6 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
#ifdef DEBUG
static bool
DumpStaticScopeChain(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
if (args.length() != 1) {
ReportUsageError(cx, callee, "Wrong number of arguments");
return false;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
ReportUsageError(cx, callee, "Argument must be an interpreted function");
return false;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (!fun->isInterpreted()) {
ReportUsageError(cx, callee, "Argument must be an interpreted function");
return false;
}
js::DumpStaticScopeChain(fun->getOrCreateScript(cx));
args.rval().setUndefined();
return true;
}
#endif
namespace js { namespace js {
namespace shell { namespace shell {
@ -4996,12 +4966,6 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
" any. If |fun| is not a scripted function or has not been compiled by\n" " any. If |fun| is not a scripted function or has not been compiled by\n"
" Ion, null is returned."), " Ion, null is returned."),
#ifdef DEBUG
JS_FN_HELP("dumpStaticScopeChain", DumpStaticScopeChain, 1, 0,
"dumpStaticScopeChain(fun)",
" Prints the static scope chain of an interpreted function fun."),
#endif
JS_FS_HELP_END JS_FS_HELP_END
}; };

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

@ -6261,14 +6261,12 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
* boundaries, and we are putting a DebugScopeProxy or non-syntactic With on * boundaries, and we are putting a DebugScopeProxy or non-syntactic With on
* the scope chain. * the scope chain.
*/ */
Rooted<ScopeObject*> enclosingStaticScope(cx); Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, nullptr));
if (!env->is<GlobalObject>())
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, enclosingStaticScope));
if (!staticScope) if (!staticScope)
return false; return false;
CompileOptions options(cx); CompileOptions options(cx);
options.setIsRunOnce(true) options.setHasPollutedScope(true)
.setIsRunOnce(true)
.setForEval(true) .setForEval(true)
.setNoScriptRval(false) .setNoScriptRval(false)
.setFileAndLine(filename, lineno) .setFileAndLine(filename, lineno)
@ -6277,8 +6275,8 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
.maybeMakeStrictMode(frame ? frame.script()->strict() : false); .maybeMakeStrictMode(frame ? frame.script()->strict() : false);
RootedScript callerScript(cx, frame ? frame.script() : nullptr); RootedScript callerScript(cx, frame ? frame.script() : nullptr);
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), SourceBufferHolder::NoOwnership); SourceBufferHolder srcBuf(chars.start().get(), chars.length(), SourceBufferHolder::NoOwnership);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, staticScope, RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, callerScript,
callerScript, options, srcBuf, staticScope, options, srcBuf,
/* source = */ nullptr, /* source = */ nullptr,
/* staticLevel = */ frame ? 1 : 0)); /* staticLevel = */ frame ? 1 : 0));
if (!script) if (!script)
@ -6419,8 +6417,14 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
return false; return false;
RootedObject dynamicScope(cx); RootedObject dynamicScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope)) // We ignore the static scope here. See comments about static
// scopes in EvaluateInEnv.
RootedObject unusedStaticScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope,
&unusedStaticScope))
{
return false; return false;
}
env = dynamicScope; env = dynamicScope;
} }

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

@ -304,9 +304,9 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s
*pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETNAME ||
*pc == JSOP_SETGNAME || *pc == JSOP_SETGNAME ||
*pc == JSOP_STRICTSETGNAME); *pc == JSOP_STRICTSETGNAME);
MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasNonSyntacticScope(), MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasPollutedGlobalScope(),
scope == cx->global()); scope == cx->global());
MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasNonSyntacticScope(), MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasPollutedGlobalScope(),
scope == cx->global()); scope == cx->global());
bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME; bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME;

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

@ -274,7 +274,7 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan
* the actual behavior even if the id could be found on the scope chain * the actual behavior even if the id could be found on the scope chain
* before the global object. * before the global object.
*/ */
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope()) if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasPollutedGlobalScope())
obj = &obj->global(); obj = &obj->global();
Shape* shape = nullptr; Shape* shape = nullptr;
@ -863,7 +863,7 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg, c
while (IsSyntacticScope(terminatingScope)) while (IsSyntacticScope(terminatingScope))
terminatingScope = terminatingScope->enclosingScope(); terminatingScope = terminatingScope->enclosingScope();
MOZ_ASSERT(terminatingScope->is<GlobalObject>() || MOZ_ASSERT(terminatingScope->is<GlobalObject>() ||
script->hasNonSyntacticScope()); script->hasPollutedGlobalScope());
#endif #endif
if (script->treatAsRunOnce()) { if (script->treatAsRunOnce()) {
@ -899,8 +899,8 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
RootedObject scopeChain(cx, &scopeChainArg); RootedObject scopeChain(cx, &scopeChainArg);
MOZ_ASSERT(scopeChain == GetInnerObject(scopeChain)); MOZ_ASSERT(scopeChain == GetInnerObject(scopeChain));
MOZ_RELEASE_ASSERT(scopeChain->is<GlobalObject>() || script->hasNonSyntacticScope(), MOZ_RELEASE_ASSERT(scopeChain->is<GlobalObject>() || script->hasPollutedGlobalScope(),
"Only scripts with non-syntactic scopes can be executed with " "Only scripts with polluted scopes can be executed with "
"interesting scopechains"); "interesting scopechains");
/* Ensure the scope chain is all same-compartment and terminates in a global. */ /* Ensure the scope chain is all same-compartment and terminates in a global. */
@ -1177,7 +1177,6 @@ PopScope(JSContext* cx, ScopeIter& si)
break; break;
case ScopeIter::Call: case ScopeIter::Call:
case ScopeIter::Eval: case ScopeIter::Eval:
case ScopeIter::NonSyntactic:
break; break;
} }
} }
@ -2316,7 +2315,7 @@ CASE(JSOP_BINDGNAME)
CASE(JSOP_BINDNAME) CASE(JSOP_BINDNAME)
{ {
JSOp op = JSOp(*REGS.pc); JSOp op = JSOp(*REGS.pc);
if (op == JSOP_BINDNAME || script->hasNonSyntacticScope()) { if (op == JSOP_BINDNAME || script->hasPollutedGlobalScope()) {
ReservedRooted<JSObject*> scopeChain(&rootObject0, REGS.fp()->scopeChain()); ReservedRooted<JSObject*> scopeChain(&rootObject0, REGS.fp()->scopeChain());
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc)); ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
@ -3056,7 +3055,7 @@ CASE(JSOP_IMPLICITTHIS)
CASE(JSOP_GIMPLICITTHIS) CASE(JSOP_GIMPLICITTHIS)
{ {
JSOp op = JSOp(*REGS.pc); JSOp op = JSOp(*REGS.pc);
if (op == JSOP_IMPLICITTHIS || script->hasNonSyntacticScope()) { if (op == JSOP_IMPLICITTHIS || script->hasPollutedGlobalScope()) {
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc)); ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
ReservedRooted<JSObject*> scopeObj(&rootObject0, REGS.fp()->scopeChain()); ReservedRooted<JSObject*> scopeObj(&rootObject0, REGS.fp()->scopeChain());
ReservedRooted<JSObject*> scope(&rootObject1); ReservedRooted<JSObject*> scope(&rootObject1);
@ -3935,7 +3934,7 @@ CASE(JSOP_SUPERBASE)
{ {
ScopeIter si(cx, REGS.fp()->scopeChain(), REGS.fp()->script()->innermostStaticScope(REGS.pc)); ScopeIter si(cx, REGS.fp()->scopeChain(), REGS.fp()->script()->innermostStaticScope(REGS.pc));
for (; !si.done(); ++si) { for (; !si.done(); ++si) {
if (si.hasSyntacticScopeObject() && si.type() == ScopeIter::Call) { if (si.hasScopeObject() && si.type() == ScopeIter::Call) {
JSFunction& callee = si.scope().as<CallObject>().callee(); JSFunction& callee = si.scope().as<CallObject>().callee();
// Arrow functions don't have the information we're looking for, // Arrow functions don't have the information we're looking for,

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

@ -1570,9 +1570,9 @@
macro(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, JOF_BYTE) \
\ \
/* /*
* Looks up name on global scope and pushes its value onto the stack, * Looks up name on global scope and pushes its value onto the stack, unless
* unless the script has a non-syntactic global scope, in which case it * the script has a polluted global, in which case it acts just like
* acts just like JSOP_NAME. * JSOP_NAME.
* *
* Free variable references that must either be found on the global or a * Free variable references that must either be found on the global or a
* ReferenceError. * ReferenceError.
@ -1586,7 +1586,7 @@
* Pops the top two values on the stack as 'val' and 'scope', sets property * Pops the top two values on the stack as 'val' and 'scope', sets property
* of 'scope' as 'val' and pushes 'val' back on the stack. * of 'scope' as 'val' and pushes 'val' back on the stack.
* *
* 'scope' should be the global scope unless the script has a non-syntactic * 'scope' should be the global scope unless the script has a polluted
* global scope, in which case acts like JSOP_SETNAME. * global scope, in which case acts like JSOP_SETNAME.
* Category: Variables and Scopes * Category: Variables and Scopes
* Type: Free Variables * Type: Free Variables
@ -1600,7 +1600,7 @@
* of 'scope' as 'val' and pushes 'val' back on the stack. Throws a * of 'scope' as 'val' and pushes 'val' back on the stack. Throws a
* TypeError if the set fails, per strict mode semantics. * TypeError if the set fails, per strict mode semantics.
* *
* 'scope' should be the global scope unless the script has a non-syntactic * 'scope' should be the global scope unless the script has a polluted
* global scope, in which case acts like JSOP_STRICTSETNAME. * global scope, in which case acts like JSOP_STRICTSETNAME.
* Category: Variables and Scopes * Category: Variables and Scopes
* Type: Free Variables * Type: Free Variables
@ -1871,7 +1871,7 @@
macro(JSOP_UNUSED213, 213, "unused213", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED213, 213, "unused213", NULL, 1, 0, 0, JOF_BYTE) \
/* /*
* Pushes the global scope onto the stack if the script doesn't have a * Pushes the global scope onto the stack if the script doesn't have a
* non-syntactic global scope. Otherwise will act like JSOP_BINDNAME. * polluted global scope. Otherwise will act like JSOP_BINDNAME.
* *
* 'nameIndex' is only used when acting like JSOP_BINDNAME. * 'nameIndex' is only used when acting like JSOP_BINDNAME.
* Category: Variables and Scopes * Category: Variables and Scopes

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

@ -84,8 +84,6 @@ StaticScopeIter<allowGC>::operator++(int)
obj = obj->template as<NestedScopeObject>().enclosingScopeForStaticScopeIter(); obj = obj->template as<NestedScopeObject>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticEvalObject>()) { } else if (obj->template is<StaticEvalObject>()) {
obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter(); obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
} else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) { } else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
onNamedLambda = false; onNamedLambda = false;
obj = obj->template as<JSFunction>().nonLazyScript()->enclosingStaticScope(); obj = obj->template as<JSFunction>().nonLazyScript()->enclosingStaticScope();
@ -94,32 +92,27 @@ StaticScopeIter<allowGC>::operator++(int)
} }
MOZ_ASSERT_IF(obj, obj->template is<NestedScopeObject>() || MOZ_ASSERT_IF(obj, obj->template is<NestedScopeObject>() ||
obj->template is<StaticEvalObject>() || obj->template is<StaticEvalObject>() ||
obj->template is<StaticNonSyntacticScopeObjects>() ||
obj->template is<JSFunction>()); obj->template is<JSFunction>());
MOZ_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>()); MOZ_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>());
} }
template <AllowGC allowGC> template <AllowGC allowGC>
inline bool inline bool
StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const StaticScopeIter<allowGC>::hasDynamicScopeObject() const
{ {
if (obj->template is<JSFunction>()) return obj->template is<StaticBlockObject>()
return obj->template as<JSFunction>().isHeavyweight(); ? obj->template as<StaticBlockObject>().needsClone()
if (obj->template is<StaticBlockObject>()) : (obj->template is<StaticEvalObject>()
return obj->template as<StaticBlockObject>().needsClone(); ? obj->template as<StaticEvalObject>().isStrict()
if (obj->template is<StaticWithObject>()) : (obj->template is<StaticWithObject>() ||
return true; obj->template as<JSFunction>().isHeavyweight()));
if (obj->template is<StaticEvalObject>())
return obj->template as<StaticEvalObject>().isStrict();
MOZ_ASSERT(obj->template is<StaticNonSyntacticScopeObjects>());
return false;
} }
template <AllowGC allowGC> template <AllowGC allowGC>
inline Shape* inline Shape*
StaticScopeIter<allowGC>::scopeShape() const StaticScopeIter<allowGC>::scopeShape() const
{ {
MOZ_ASSERT(hasSyntacticDynamicScopeObject()); MOZ_ASSERT(hasDynamicScopeObject());
MOZ_ASSERT(type() != NamedLambda && type() != Eval); MOZ_ASSERT(type() != NamedLambda && type() != Eval);
if (type() == Block) if (type() == Block)
return block().lastProperty(); return block().lastProperty();
@ -138,8 +131,6 @@ StaticScopeIter<allowGC>::type() const
? With ? With
: (obj->template is<StaticEvalObject>() : (obj->template is<StaticEvalObject>()
? Eval ? Eval
: (obj->template is<StaticNonSyntacticScopeObjects>())
? NonSyntactic
: Function)); : Function));
} }
@ -167,14 +158,6 @@ StaticScopeIter<allowGC>::eval() const
return obj->template as<StaticEvalObject>(); return obj->template as<StaticEvalObject>();
} }
template <AllowGC allowGC>
inline StaticNonSyntacticScopeObjects&
StaticScopeIter<allowGC>::nonSyntactic() const
{
MOZ_ASSERT(type() == NonSyntactic);
return obj->template as<StaticNonSyntacticScopeObjects>();
}
template <AllowGC allowGC> template <AllowGC allowGC>
inline JSScript* inline JSScript*
StaticScopeIter<allowGC>::funScript() const StaticScopeIter<allowGC>::funScript() const

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

@ -43,7 +43,7 @@ js::ScopeCoordinateToStaticScopeShape(JSScript* script, jsbytecode* pc)
uint32_t hops = ScopeCoordinate(pc).hops(); uint32_t hops = ScopeCoordinate(pc).hops();
while (true) { while (true) {
MOZ_ASSERT(!ssi.done()); MOZ_ASSERT(!ssi.done());
if (ssi.hasSyntacticDynamicScopeObject()) { if (ssi.hasDynamicScopeObject()) {
if (!hops) if (!hops)
break; break;
hops--; hops--;
@ -107,7 +107,7 @@ js::ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
StaticScopeIter<NoGC> ssi(script->innermostStaticScopeInScript(pc)); StaticScopeIter<NoGC> ssi(script->innermostStaticScopeInScript(pc));
uint32_t hops = ScopeCoordinate(pc).hops(); uint32_t hops = ScopeCoordinate(pc).hops();
while (true) { while (true) {
if (ssi.hasSyntacticDynamicScopeObject()) { if (ssi.hasDynamicScopeObject()) {
if (!hops) if (!hops)
break; break;
hops--; hops--;
@ -212,7 +212,7 @@ CallObject::create(JSContext* cx, HandleScript script, HandleObject enclosing, H
if (!callobj) if (!callobj)
return nullptr; return nullptr;
callobj->setEnclosingScope(enclosing); callobj->as<ScopeObject>().setEnclosingScope(enclosing);
callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
if (script->treatAsRunOnce()) { if (script->treatAsRunOnce()) {
@ -323,10 +323,22 @@ const Class DeclEnvObject::class_ = {
* scope and callee) or used as a template for jit compilation. * scope and callee) or used as a template for jit compilation.
*/ */
DeclEnvObject* DeclEnvObject*
DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObjectKind newKind) DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, gc::InitialHeap heap)
{ {
Rooted<DeclEnvObject*> obj(cx); MOZ_ASSERT(IsNurseryAllocable(FINALIZE_KIND));
obj = NewObjectWithNullTaggedProto<DeclEnvObject>(cx, newKind, BaseShape::DELEGATE);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape emptyDeclEnvShape(cx);
emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE);
if (!emptyDeclEnvShape)
return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND, heap,
emptyDeclEnvShape, group)));
if (!obj) if (!obj)
return nullptr; return nullptr;
@ -344,13 +356,13 @@ DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObject
return nullptr; return nullptr;
MOZ_ASSERT(!obj->hasDynamicSlots()); MOZ_ASSERT(!obj->hasDynamicSlots());
return obj; return &obj->as<DeclEnvObject>();
} }
DeclEnvObject* DeclEnvObject*
DeclEnvObject::create(JSContext* cx, HandleObject enclosing, HandleFunction callee) DeclEnvObject::create(JSContext* cx, HandleObject enclosing, HandleFunction callee)
{ {
Rooted<DeclEnvObject*> obj(cx, createTemplateObject(cx, callee, GenericObject)); Rooted<DeclEnvObject*> obj(cx, createTemplateObject(cx, callee, gc::DefaultHeap));
if (!obj) if (!obj)
return nullptr; return nullptr;
@ -388,7 +400,20 @@ js::XDRStaticWithObject(XDRState<XDR_DECODE>*, HandleObject, MutableHandle<Stati
StaticWithObject* StaticWithObject*
StaticWithObject::create(ExclusiveContext* cx) StaticWithObject::create(ExclusiveContext* cx)
{ {
return NewObjectWithNullTaggedProto<StaticWithObject>(cx, TenuredObject, BaseShape::DELEGATE); RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND));
if (!shape)
return nullptr;
RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, shape, group));
if (!obj)
return nullptr;
return &obj->as<StaticWithObject>();
} }
static JSObject* static JSObject*
@ -408,11 +433,18 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
HandleObject staticWith, WithKind kind) HandleObject staticWith, WithKind kind)
{ {
MOZ_ASSERT(staticWith->is<StaticWithObject>()); MOZ_ASSERT(staticWith->is<StaticWithObject>());
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_,
TaggedProto(staticWith.get())));
if (!group)
return nullptr;
Rooted<TaggedProto> proto(cx, TaggedProto(staticWith)); RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(staticWith),
Rooted<DynamicWithObject*> obj(cx); FINALIZE_KIND));
obj = NewObjectWithGivenTaggedProto<DynamicWithObject>(cx, proto, GenericObject, if (!shape)
BaseShape::DELEGATE); return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
gc::DefaultHeap, shape, group)));
if (!obj) if (!obj)
return nullptr; return nullptr;
@ -420,12 +452,12 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
if (!thisp) if (!thisp)
return nullptr; return nullptr;
obj->setEnclosingScope(enclosing); obj->as<ScopeObject>().setEnclosingScope(enclosing);
obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object)); obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object));
obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp)); obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
obj->setFixedSlot(KIND_SLOT, Int32Value(kind)); obj->setFixedSlot(KIND_SLOT, Int32Value(kind));
return obj; return &obj->as<DynamicWithObject>();
} }
static bool static bool
@ -535,14 +567,23 @@ const Class DynamicWithObject::class_ = {
/* static */ StaticEvalObject* /* static */ StaticEvalObject*
StaticEvalObject::create(JSContext* cx, HandleObject enclosing) StaticEvalObject::create(JSContext* cx, HandleObject enclosing)
{ {
StaticEvalObject* obj = RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
NewObjectWithNullTaggedProto<StaticEvalObject>(cx, TenuredObject, BaseShape::DELEGATE); if (!group)
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE));
if (!shape)
return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
gc::TenuredHeap, shape, group)));
if (!obj) if (!obj)
return nullptr; return nullptr;
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing)); obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
obj->setReservedSlot(STRICT_SLOT, BooleanValue(false)); obj->setReservedSlot(STRICT_SLOT, BooleanValue(false));
return obj; return &obj->as<StaticEvalObject>();
} }
const Class StaticEvalObject::class_ = { const Class StaticEvalObject::class_ = {
@ -551,50 +592,6 @@ const Class StaticEvalObject::class_ = {
JSCLASS_IS_ANONYMOUS JSCLASS_IS_ANONYMOUS
}; };
/* static */ StaticNonSyntacticScopeObjects*
StaticNonSyntacticScopeObjects::create(JSContext*cx, HandleObject enclosing)
{
StaticNonSyntacticScopeObjects* obj =
NewObjectWithNullTaggedProto<StaticNonSyntacticScopeObjects>(cx, TenuredObject,
BaseShape::DELEGATE);
if (!obj)
return nullptr;
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
return obj;
}
const Class StaticNonSyntacticScopeObjects::class_ = {
"StaticNonSyntacticScopeObjects",
JSCLASS_HAS_RESERVED_SLOTS(StaticNonSyntacticScopeObjects::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS
};
/* static */ NonSyntacticVariablesObject*
NonSyntacticVariablesObject::create(JSContext* cx, Handle<GlobalObject*> global)
{
Rooted<NonSyntacticVariablesObject*> obj(cx,
NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
BaseShape::DELEGATE));
if (!obj)
return nullptr;
if (!obj->setQualifiedVarObj(cx))
return nullptr;
if (!obj->setUnqualifiedVarObj(cx))
return nullptr;
obj->setEnclosingScope(global);
return obj;
}
const Class NonSyntacticVariablesObject::class_ = {
"NonSyntacticVariablesObject",
JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS
};
/*****************************************************************************/ /*****************************************************************************/
/* static */ ClonedBlockObject* /* static */ ClonedBlockObject*
@ -609,10 +606,7 @@ ClonedBlockObject::create(JSContext* cx, Handle<StaticBlockObject*> block, Handl
RootedShape shape(cx, block->lastProperty()); RootedShape shape(cx, block->lastProperty());
gc::AllocKind allocKind = gc::GetGCObjectKind(&BlockObject::class_); RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
if (CanBeFinalizedInBackground(allocKind, &BlockObject::class_))
allocKind = GetBackgroundAllocKind(allocKind);
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, allocKind,
gc::TenuredHeap, shape, group))); gc::TenuredHeap, shape, group)));
if (!obj) if (!obj)
return nullptr; return nullptr;
@ -686,7 +680,22 @@ ClonedBlockObject::clone(JSContext* cx, Handle<ClonedBlockObject*> clonedBlock)
StaticBlockObject* StaticBlockObject*
StaticBlockObject::create(ExclusiveContext* cx) StaticBlockObject::create(ExclusiveContext* cx)
{ {
return NewObjectWithNullTaggedProto<StaticBlockObject>(cx, TenuredObject, BaseShape::DELEGATE); RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &BlockObject::class_,
TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape emptyBlockShape(cx);
emptyBlockShape = EmptyShape::getInitialShape(cx, &BlockObject::class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE);
if (!emptyBlockShape)
return nullptr;
JSObject* obj = JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, emptyBlockShape, group);
if (!obj)
return nullptr;
return &obj->as<StaticBlockObject>();
} }
/* static */ Shape* /* static */ Shape*
@ -884,13 +893,22 @@ js::CloneNestedScopeObject(JSContext* cx, HandleObject enclosingScope, Handle<Ne
/* static */ UninitializedLexicalObject* /* static */ UninitializedLexicalObject*
UninitializedLexicalObject::create(JSContext* cx, HandleObject enclosing) UninitializedLexicalObject::create(JSContext* cx, HandleObject enclosing)
{ {
UninitializedLexicalObject* obj = RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
NewObjectWithNullTaggedProto<UninitializedLexicalObject>(cx, GenericObject, if (!group)
BaseShape::DELEGATE); return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND));
if (!shape)
return nullptr;
RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, gc::DefaultHeap, shape, group));
if (!obj) if (!obj)
return nullptr; return nullptr;
obj->setEnclosingScope(enclosing);
return obj; obj->as<ScopeObject>().setEnclosingScope(enclosing);
return &obj->as<UninitializedLexicalObject>();
} }
static void static void
@ -1027,14 +1045,7 @@ ScopeIter::ScopeIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
void void
ScopeIter::incrementStaticScopeIter() ScopeIter::incrementStaticScopeIter()
{ {
// If settled on a non-syntactic static scope, only increment ssi_ once ssi_++;
// we've iterated through all the non-syntactic dynamic ScopeObjects.
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
if (!hasNonSyntacticScopeObject())
ssi_++;
} else {
ssi_++;
}
// For named lambdas, DeclEnvObject scopes are always attached to their // For named lambdas, DeclEnvObject scopes are always attached to their
// CallObjects. Skip it here, as they are special cased in users of // CallObjects. Skip it here, as they are special cased in users of
@ -1061,7 +1072,7 @@ ScopeIter::settle()
frame_ = NullFramePtr(); frame_ = NullFramePtr();
#ifdef DEBUG #ifdef DEBUG
if (!ssi_.done() && hasAnyScopeObject()) { if (!ssi_.done() && hasScopeObject()) {
switch (ssi_.type()) { switch (ssi_.type()) {
case StaticScopeIter<CanGC>::Function: case StaticScopeIter<CanGC>::Function:
MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript()); MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript());
@ -1075,9 +1086,6 @@ ScopeIter::settle()
case StaticScopeIter<CanGC>::Eval: case StaticScopeIter<CanGC>::Eval:
MOZ_ASSERT(scope_->as<CallObject>().isForEval()); MOZ_ASSERT(scope_->as<CallObject>().isForEval());
break; break;
case StaticScopeIter<CanGC>::NonSyntactic:
MOZ_ASSERT(!IsSyntacticScope(scope_));
break;
case StaticScopeIter<CanGC>::NamedLambda: case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped"); MOZ_CRASH("named lambda static scopes should have been skipped");
} }
@ -1088,7 +1096,7 @@ ScopeIter::settle()
ScopeIter& ScopeIter&
ScopeIter::operator++() ScopeIter::operator++()
{ {
if (hasAnyScopeObject()) { if (hasScopeObject()) {
scope_ = &scope_->as<ScopeObject>().enclosingScope(); scope_ = &scope_->as<ScopeObject>().enclosingScope();
if (scope_->is<DeclEnvObject>()) if (scope_->is<DeclEnvObject>())
scope_ = &scope_->as<DeclEnvObject>().enclosingScope(); scope_ = &scope_->as<DeclEnvObject>().enclosingScope();
@ -1114,8 +1122,6 @@ ScopeIter::type() const
return With; return With;
case StaticScopeIter<CanGC>::Eval: case StaticScopeIter<CanGC>::Eval:
return Eval; return Eval;
case StaticScopeIter<CanGC>::NonSyntactic:
return NonSyntactic;
case StaticScopeIter<CanGC>::NamedLambda: case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped"); MOZ_CRASH("named lambda static scopes should have been skipped");
default: default:
@ -1126,7 +1132,7 @@ ScopeIter::type() const
ScopeObject& ScopeObject&
ScopeIter::scope() const ScopeIter::scope() const
{ {
MOZ_ASSERT(hasAnyScopeObject()); MOZ_ASSERT(hasScopeObject());
return scope_->as<ScopeObject>(); return scope_->as<ScopeObject>();
} }
@ -1145,8 +1151,6 @@ ScopeIter::maybeStaticScope() const
return &staticWith(); return &staticWith();
case StaticScopeIter<CanGC>::Eval: case StaticScopeIter<CanGC>::Eval:
return &staticEval(); return &staticEval();
case StaticScopeIter<CanGC>::NonSyntactic:
return &staticNonSyntactic();
case StaticScopeIter<CanGC>::NamedLambda: case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped"); MOZ_CRASH("named lambda static scopes should have been skipped");
default: default:
@ -1746,7 +1750,7 @@ const DebugScopeProxy DebugScopeProxy::singleton;
DebugScopeObject::create(JSContext* cx, ScopeObject& scope, HandleObject enclosing) DebugScopeObject::create(JSContext* cx, ScopeObject& scope, HandleObject enclosing)
{ {
MOZ_ASSERT(scope.compartment() == cx->compartment()); MOZ_ASSERT(scope.compartment() == cx->compartment());
MOZ_ASSERT(!enclosing->is<ScopeObject>()); MOZ_ASSERT(!IsSyntacticScope(enclosing));
RootedValue priv(cx, ObjectValue(scope)); RootedValue priv(cx, ObjectValue(scope));
JSObject* obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv, JSObject* obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv,
@ -2008,7 +2012,7 @@ DebugScopes::addDebugScope(JSContext* cx, ScopeObject& scope, DebugScopeObject&
DebugScopeObject* DebugScopeObject*
DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si) DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
{ {
MOZ_ASSERT(!si.hasSyntacticScopeObject()); MOZ_ASSERT(!si.hasScopeObject());
DebugScopes* scopes = cx->compartment()->debugScopes; DebugScopes* scopes = cx->compartment()->debugScopes;
if (!scopes) if (!scopes)
@ -2024,7 +2028,7 @@ DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
bool bool
DebugScopes::addDebugScope(JSContext* cx, const ScopeIter& si, DebugScopeObject& debugScope) DebugScopes::addDebugScope(JSContext* cx, const ScopeIter& si, DebugScopeObject& debugScope)
{ {
MOZ_ASSERT(!si.hasSyntacticScopeObject()); MOZ_ASSERT(!si.hasScopeObject());
MOZ_ASSERT(cx->compartment() == debugScope.compartment()); MOZ_ASSERT(cx->compartment() == debugScope.compartment());
MOZ_ASSERT_IF(si.withinInitialFrame() && si.initialFrame().isFunctionFrame(), MOZ_ASSERT_IF(si.withinInitialFrame() && si.initialFrame().isFunctionFrame(),
!si.initialFrame().callee()->isGenerator()); !si.initialFrame().callee()->isGenerator());
@ -2242,7 +2246,7 @@ DebugScopes::updateLiveScopes(JSContext* cx)
continue; continue;
for (ScopeIter si(cx, frame, i.pc()); si.withinInitialFrame(); ++si) { for (ScopeIter si(cx, frame, i.pc()); si.withinInitialFrame(); ++si) {
if (si.hasSyntacticScopeObject()) { if (si.hasScopeObject()) {
MOZ_ASSERT(si.scope().compartment() == cx->compartment()); MOZ_ASSERT(si.scope().compartment() == cx->compartment());
DebugScopes* scopes = ensureCompartmentData(cx); DebugScopes* scopes = ensureCompartmentData(cx);
if (!scopes) if (!scopes)
@ -2360,7 +2364,7 @@ GetDebugScopeForScope(JSContext* cx, const ScopeIter& si)
static DebugScopeObject* static DebugScopeObject*
GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si) GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
{ {
MOZ_ASSERT(!si.hasSyntacticScopeObject() && si.canHaveSyntacticScopeObject()); MOZ_ASSERT(!si.hasScopeObject() && si.canHaveScopeObject());
if (DebugScopeObject* debugScope = DebugScopes::hasDebugScope(cx, si)) if (DebugScopeObject* debugScope = DebugScopes::hasDebugScope(cx, si))
return debugScope; return debugScope;
@ -2427,8 +2431,6 @@ GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
case ScopeIter::With: case ScopeIter::With:
case ScopeIter::Eval: case ScopeIter::Eval:
MOZ_CRASH("should already have a scope"); MOZ_CRASH("should already have a scope");
case ScopeIter::NonSyntactic:
MOZ_CRASH("non-syntactic scopes cannot be synthesized");
} }
if (!debugScope) if (!debugScope)
return nullptr; return nullptr;
@ -2443,11 +2445,11 @@ static JSObject*
GetDebugScopeForNonScopeObject(const ScopeIter& si) GetDebugScopeForNonScopeObject(const ScopeIter& si)
{ {
JSObject& enclosing = si.enclosingScope(); JSObject& enclosing = si.enclosingScope();
MOZ_ASSERT(!enclosing.is<ScopeObject>()); MOZ_ASSERT(!IsSyntacticScope(&enclosing));
#ifdef DEBUG #ifdef DEBUG
JSObject* o = &enclosing; JSObject* o = &enclosing;
while ((o = o->enclosingScope())) while ((o = o->enclosingScope()))
MOZ_ASSERT(!o->is<ScopeObject>()); MOZ_ASSERT(!IsSyntacticScope(o));
#endif #endif
return &enclosing; return &enclosing;
} }
@ -2460,10 +2462,10 @@ GetDebugScope(JSContext* cx, const ScopeIter& si)
if (si.done()) if (si.done())
return GetDebugScopeForNonScopeObject(si); return GetDebugScopeForNonScopeObject(si);
if (si.hasAnyScopeObject()) if (si.hasScopeObject())
return GetDebugScopeForScope(cx, si); return GetDebugScopeForScope(cx, si);
if (si.canHaveSyntacticScopeObject()) if (si.canHaveScopeObject())
return GetDebugScopeForMissing(cx, si); return GetDebugScopeForMissing(cx, si);
ScopeIter copy(cx, si); ScopeIter copy(cx, si);
@ -2512,7 +2514,8 @@ js::GetObjectEnvironmentObjectForFunction(JSFunction* fun)
bool bool
js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
HandleObject dynamicTerminatingScope, HandleObject dynamicTerminatingScope,
MutableHandleObject dynamicScopeObj) MutableHandleObject dynamicScopeObj,
MutableHandleObject staticScopeObj)
{ {
#ifdef DEBUG #ifdef DEBUG
for (size_t i = 0; i < scopeChain.length(); ++i) { for (size_t i = 0; i < scopeChain.length(); ++i) {
@ -2542,55 +2545,12 @@ js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
} }
dynamicScopeObj.set(dynamicEnclosingScope); dynamicScopeObj.set(dynamicEnclosingScope);
staticScopeObj.set(staticEnclosingScope);
return true; return true;
} }
bool
js::HasNonSyntacticStaticScopeChain(JSObject* staticScope)
{
for (StaticScopeIter<NoGC> 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<NoGC>::Function)
return ssi.funScript()->hasNonSyntacticScope();
if (ssi.type() == StaticScopeIter<NoGC>::NonSyntactic)
return true;
}
return false;
}
#ifdef DEBUG #ifdef DEBUG
void
js::DumpStaticScopeChain(JSScript* script)
{
JSObject* enclosingScope = script->enclosingStaticScope();
for (StaticScopeIter<NoGC> ssi(enclosingScope); !ssi.done(); ssi++) {
switch (ssi.type()) {
case StaticScopeIter<NoGC>::Function:
fprintf(stdout, "function");
break;
case StaticScopeIter<NoGC>::Block:
fprintf(stdout, "block");
break;
case StaticScopeIter<NoGC>::With:
fprintf(stdout, "with");
break;
case StaticScopeIter<NoGC>::NamedLambda:
fprintf(stdout, "named lambda");
break;
case StaticScopeIter<NoGC>::Eval:
fprintf(stdout, "eval");
break;
case StaticScopeIter<NoGC>::NonSyntactic:
fprintf(stdout, "non-syntactic");
break;
}
fprintf(stdout, " -> ");
}
fprintf(stdout, "global\n");
}
typedef HashSet<PropertyName*> PropertyNameSet; typedef HashSet<PropertyName*> PropertyNameSet;
static bool static bool
@ -2623,7 +2583,7 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai
case JSOP_GETGNAME: case JSOP_GETGNAME:
case JSOP_SETGNAME: case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME: case JSOP_STRICTSETGNAME:
if (script->hasNonSyntacticScope()) if (script->hasPollutedGlobalScope())
name = script->getName(pc); name = script->getName(pc);
else else
name = nullptr; name = nullptr;

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

@ -22,7 +22,6 @@ namespace frontend { struct Definition; }
class StaticWithObject; class StaticWithObject;
class StaticEvalObject; class StaticEvalObject;
class StaticNonSyntacticScopeObjects;
/*****************************************************************************/ /*****************************************************************************/
@ -63,7 +62,6 @@ class StaticScopeIter
obj->is<StaticBlockObject>() || obj->is<StaticBlockObject>() ||
obj->is<StaticWithObject>() || obj->is<StaticWithObject>() ||
obj->is<StaticEvalObject>() || obj->is<StaticEvalObject>() ||
obj->is<StaticNonSyntacticScopeObjects>() ||
obj->is<JSFunction>()); obj->is<JSFunction>());
} }
@ -83,7 +81,6 @@ class StaticScopeIter
obj->is<StaticBlockObject>() || obj->is<StaticBlockObject>() ||
obj->is<StaticWithObject>() || obj->is<StaticWithObject>() ||
obj->is<StaticEvalObject>() || obj->is<StaticEvalObject>() ||
obj->is<StaticNonSyntacticScopeObjects>() ||
obj->is<JSFunction>()); obj->is<JSFunction>());
} }
@ -98,19 +95,16 @@ class StaticScopeIter
bool done() const; bool done() const;
void operator++(int); void operator++(int);
// Return whether this static scope will have a syntactic scope (i.e. a /* Return whether this static scope will be on the dynamic scope chain. */
// ScopeObject that isn't a non-syntactic With or bool hasDynamicScopeObject() const;
// NonSyntacticVariablesObject) on the dynamic scope chain.
bool hasSyntacticDynamicScopeObject() const;
Shape* scopeShape() const; Shape* scopeShape() const;
enum Type { Function, Block, With, NamedLambda, Eval, NonSyntactic }; enum Type { Function, Block, With, NamedLambda, Eval };
Type type() const; Type type() const;
StaticBlockObject& block() const; StaticBlockObject& block() const;
StaticWithObject& staticWith() const; StaticWithObject& staticWith() const;
StaticEvalObject& eval() const; StaticEvalObject& eval() const;
StaticNonSyntacticScopeObjects& nonSyntactic() const;
JSScript* funScript() const; JSScript* funScript() const;
JSFunction& fun() const; JSFunction& fun() const;
}; };
@ -181,28 +175,26 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
* scope objects is: * scope objects is:
* *
* JSObject Generic object * JSObject Generic object
* | * \
* ScopeObject---+---+ Engine-internal scope * ScopeObject Engine-internal scope
* | | | | | * \ \ \ \
* | | | | StaticNonSyntacticScopeObjects See NB2 * \ \ \ StaticEvalObject Placeholder so eval scopes may be iterated through
* | | | | * \ \ \
* | | | StaticEvalObject Placeholder so eval scopes may be iterated through * \ \ DeclEnvObject Holds name of recursive/heavyweight named lambda
* | | | * \ \
* | | DeclEnvObject Holds name of recursive/heavyweight named lambda * \ CallObject Scope of entire function or strict eval
* | | * \
* | CallObject Scope of entire function or strict eval * NestedScopeObject Scope created for a statement
* | * \ \ \
* NestedScopeObject Scope created for a statement * \ \ StaticWithObject Template for "with" object in static scope chain
* | | | * \ \
* | | StaticWithObject Template for "with" object in static scope chain * \ DynamicWithObject Run-time "with" object on scope chain
* | | * \
* | DynamicWithObject Run-time "with" object on scope chain * BlockObject Shared interface of cloned/static block objects
* | * \ \
* BlockObject Shared interface of cloned/static block objects * \ ClonedBlockObject let, switch, catch, for
* | | * \
* | ClonedBlockObject let, switch, catch, for * StaticBlockObject See NB
* |
* StaticBlockObject See NB
* *
* This hierarchy represents more than just the interface hierarchy: reserved * This hierarchy represents more than just the interface hierarchy: reserved
* slots in base classes are fixed for all derived classes. Thus, for example, * slots in base classes are fixed for all derived classes. Thus, for example,
@ -214,9 +206,6 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
* are cloned at runtime. These objects should never escape into the wild and * are cloned at runtime. These objects should never escape into the wild and
* support a restricted set of ScopeObject operations. * support a restricted set of ScopeObject operations.
* *
* NB2: StaticNonSyntacticScopeObjects notify either of 0+ non-syntactic
* DynamicWithObjects on the dynamic scope chain or a NonSyntacticScopeObject.
*
* See also "Debug scope objects" below. * See also "Debug scope objects" below.
*/ */
@ -351,10 +340,12 @@ class DeclEnvObject : public ScopeObject
public: public:
static const uint32_t RESERVED_SLOTS = 2; static const uint32_t RESERVED_SLOTS = 2;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
static const Class class_; static const Class class_;
static DeclEnvObject* static DeclEnvObject*
createTemplateObject(JSContext* cx, HandleFunction fun, NewObjectKind newKind); createTemplateObject(JSContext* cx, HandleFunction fun, gc::InitialHeap heap);
static DeclEnvObject* create(JSContext* cx, HandleObject enclosing, HandleFunction callee); static DeclEnvObject* create(JSContext* cx, HandleObject enclosing, HandleFunction callee);
@ -363,15 +354,16 @@ class DeclEnvObject : public ScopeObject
} }
}; };
// Static eval scope placeholder objects on the static scope chain. Created at // Static eval scope template objects on the static scope. Created at the
// the time of compiling the eval script, and set as its static enclosing // time of compiling the eval script, and set as its static enclosing scope.
// scope.
class StaticEvalObject : public ScopeObject class StaticEvalObject : public ScopeObject
{ {
static const uint32_t STRICT_SLOT = 1; static const uint32_t STRICT_SLOT = 1;
public: public:
static const unsigned RESERVED_SLOTS = 2; static const unsigned RESERVED_SLOTS = 2;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
static const Class class_; static const Class class_;
static StaticEvalObject* create(JSContext* cx, HandleObject enclosing); static StaticEvalObject* create(JSContext* cx, HandleObject enclosing);
@ -395,42 +387,6 @@ class StaticEvalObject : public ScopeObject
} }
}; };
// Static scope objects that stand in for one or more "polluting global"
// scopes on the dynamic scope chain.
//
// There are two flavors of polluting global scopes on the dynamic scope
// chain: either 0+ non-syntactic DynamicWithObjects, or 1
// NonSyntacticVariablesObject, created exclusively in
// js::ExecuteInGlobalAndReturnScope.
class StaticNonSyntacticScopeObjects : public ScopeObject
{
public:
static const unsigned RESERVED_SLOTS = 1;
static const Class class_;
static StaticNonSyntacticScopeObjects* create(JSContext* cx, HandleObject enclosing);
JSObject* enclosingScopeForStaticScopeIter() {
return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
}
};
// A non-syntactic dynamic scope object that captures non-lexical
// bindings. That is, a scope object that captures both qualified var
// assignments and unqualified bareword assignments. Its parent is always the
// real global.
//
// This is used in ExecuteInGlobalAndReturnScope and sits in front of the
// global scope to capture 'var' and bareword asignments.
class NonSyntacticVariablesObject : public ScopeObject
{
public:
static const unsigned RESERVED_SLOTS = 1;
static const Class class_;
static NonSyntacticVariablesObject* create(JSContext* cx, Handle<GlobalObject*> global);
};
class NestedScopeObject : public ScopeObject class NestedScopeObject : public ScopeObject
{ {
public: public:
@ -480,6 +436,8 @@ class StaticWithObject : public NestedScopeObject
{ {
public: public:
static const unsigned RESERVED_SLOTS = 1; static const unsigned RESERVED_SLOTS = 1;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
static const Class class_; static const Class class_;
static StaticWithObject* create(ExclusiveContext* cx); static StaticWithObject* create(ExclusiveContext* cx);
@ -494,6 +452,8 @@ class DynamicWithObject : public NestedScopeObject
public: public:
static const unsigned RESERVED_SLOTS = 4; static const unsigned RESERVED_SLOTS = 4;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT4_BACKGROUND;
static const Class class_; static const Class class_;
enum WithKind { enum WithKind {
@ -545,6 +505,8 @@ class BlockObject : public NestedScopeObject
public: public:
static const unsigned RESERVED_SLOTS = 2; static const unsigned RESERVED_SLOTS = 2;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT4_BACKGROUND;
static const Class class_; static const Class class_;
/* Return the abstract stack depth right before entering this nested scope. */ /* Return the abstract stack depth right before entering this nested scope. */
@ -631,7 +593,7 @@ class StaticBlockObject : public BlockObject
* variable of the block isAliased. * variable of the block isAliased.
*/ */
bool needsClone() { bool needsClone() {
return numVariables() > 0 && !getSlot(RESERVED_SLOTS).isFalse(); return !getFixedSlot(RESERVED_SLOTS).isFalse();
} }
/* Frontend-only functions ***********************************************/ /* Frontend-only functions ***********************************************/
@ -735,6 +697,8 @@ class UninitializedLexicalObject : public ScopeObject
{ {
public: public:
static const unsigned RESERVED_SLOTS = 1; static const unsigned RESERVED_SLOTS = 1;
static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT2_BACKGROUND;
static const Class class_; static const Class class_;
static UninitializedLexicalObject* create(JSContext* cx, HandleObject enclosing); static UninitializedLexicalObject* create(JSContext* cx, HandleObject enclosing);
@ -795,20 +759,17 @@ class ScopeIter
inline JSObject& enclosingScope() const; inline JSObject& enclosingScope() const;
// If !done(): // If !done():
enum Type { Call, Block, With, Eval, NonSyntactic }; enum Type { Call, Block, With, Eval };
Type type() const; Type type() const;
inline bool hasNonSyntacticScopeObject() const; inline bool hasScopeObject() const;
inline bool hasSyntacticScopeObject() const; inline bool canHaveScopeObject() const;
inline bool hasAnyScopeObject() const;
inline bool canHaveSyntacticScopeObject() const;
ScopeObject& scope() const; ScopeObject& scope() const;
JSObject* maybeStaticScope() const; JSObject* maybeStaticScope() const;
StaticBlockObject& staticBlock() const { return ssi_.block(); } StaticBlockObject& staticBlock() const { return ssi_.block(); }
StaticWithObject& staticWith() const { return ssi_.staticWith(); } StaticWithObject& staticWith() const { return ssi_.staticWith(); }
StaticEvalObject& staticEval() const { return ssi_.eval(); } StaticEvalObject& staticEval() const { return ssi_.eval(); }
StaticNonSyntacticScopeObjects& staticNonSyntactic() const { return ssi_.nonSyntactic(); }
JSFunction& fun() const { return ssi_.fun(); } JSFunction& fun() const { return ssi_.fun(); }
bool withinInitialFrame() const { return !!frame_; } bool withinInitialFrame() const { return !!frame_; }
@ -1048,8 +1009,7 @@ JSObject::is<js::ScopeObject>() const
return is<js::CallObject>() || return is<js::CallObject>() ||
is<js::DeclEnvObject>() || is<js::DeclEnvObject>() ||
is<js::NestedScopeObject>() || is<js::NestedScopeObject>() ||
is<js::UninitializedLexicalObject>() || is<js::UninitializedLexicalObject>();
is<js::NonSyntacticVariablesObject>();
} }
template<> template<>
@ -1081,8 +1041,8 @@ inline bool
IsSyntacticScope(JSObject* scope) IsSyntacticScope(JSObject* scope)
{ {
return scope->is<ScopeObject>() && return scope->is<ScopeObject>() &&
(!scope->is<DynamicWithObject>() || scope->as<DynamicWithObject>().isSyntactic()) && (!scope->is<DynamicWithObject>() ||
!scope->is<NonSyntacticVariablesObject>(); scope->as<DynamicWithObject>().isSyntactic());
} }
inline const Value& inline const Value&
@ -1106,54 +1066,16 @@ ScopeIter::done() const
} }
inline bool inline bool
ScopeIter::hasSyntacticScopeObject() const ScopeIter::hasScopeObject() const
{ {
return ssi_.hasSyntacticDynamicScopeObject(); return ssi_.hasDynamicScopeObject();
} }
inline bool inline bool
ScopeIter::hasNonSyntacticScopeObject() const ScopeIter::canHaveScopeObject() const
{ {
// The case we're worrying about here is a NonSyntactic static scope which // Non-strict eval scopes cannot have dynamic scope objects.
// has 0+ corresponding non-syntactic DynamicWithObject scopes or a return !ssi_.done() && (type() != Eval || staticEval().isStrict());
// NonSyntacticVariablesObject.
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
MOZ_ASSERT_IF(scope_->is<DynamicWithObject>(),
!scope_->as<DynamicWithObject>().isSyntactic());
return scope_->is<DynamicWithObject>() ||
scope_->is<NonSyntacticVariablesObject>();
}
return false;
}
inline bool
ScopeIter::hasAnyScopeObject() const
{
return hasSyntacticScopeObject() || hasNonSyntacticScopeObject();
}
inline bool
ScopeIter::canHaveSyntacticScopeObject() const
{
if (ssi_.done())
return false;
switch (type()) {
case Call:
return true;
case Block:
return true;
case With:
return true;
case Eval:
// Only strict eval scopes can have dynamic scope objects.
return staticEval().isStrict();
case NonSyntactic:
return false;
}
// Silence warnings.
return false;
} }
inline JSObject& inline JSObject&
@ -1171,12 +1093,10 @@ ScopeIter::enclosingScope() const
extern bool extern bool
CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain, CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
HandleObject dynamicTerminatingScope, HandleObject dynamicTerminatingScope,
MutableHandleObject dynamicScopeObj); MutableHandleObject dynamicScopeObj,
MutableHandleObject staticScopeObj);
bool HasNonSyntacticStaticScopeChain(JSObject* staticScope);
#ifdef DEBUG #ifdef DEBUG
void DumpStaticScopeChain(JSScript* script);
bool bool
AnalyzeEntrainedVariables(JSContext* cx, HandleScript script); AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
#endif #endif

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

@ -1722,9 +1722,7 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
js::gc::AllocKind kind = hasName js::gc::AllocKind kind = hasName
? gc::AllocKind::FUNCTION_EXTENDED ? gc::AllocKind::FUNCTION_EXTENDED
: selfHostedFunction->getAllocKind(); : selfHostedFunction->getAllocKind();
MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global())); clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
clone = CloneFunctionAndScript(cx, selfHostedFunction, cx->global(),
/* newStaticScope = */ nullptr, kind);
// To be able to re-lazify the cloned function, its name in the // To be able to re-lazify the cloned function, its name in the
// self-hosting compartment has to be stored on the clone. // self-hosting compartment has to be stored on the clone.
if (clone && hasName) if (clone && hasName)
@ -1808,17 +1806,22 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
// aren't any. // aren't any.
MOZ_ASSERT(!sourceFun->isGenerator()); MOZ_ASSERT(!sourceFun->isGenerator());
MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
// The target function might have been relazified after it's flags changed.
targetFun->setFlags((targetFun->flags() & ~JSFunction::INTERPRETED_LAZY) |
sourceFun->flags() | JSFunction::EXTENDED);
MOZ_ASSERT(targetFun->isExtended());
RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx)); RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
if (!sourceScript) if (!sourceScript)
return false; return false;
MOZ_ASSERT(!sourceScript->enclosingStaticScope()); MOZ_ASSERT(!sourceScript->enclosingStaticScope());
return !!CloneScriptIntoFunction(cx, /* enclosingScope = */ nullptr, targetFun, sourceScript); JSScript* cscript = CloneScript(cx, nullptr, targetFun, sourceScript);
if (!cscript)
return false;
cscript->setFunction(targetFun);
MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
// The target function might have been relazified after it's flags changed.
targetFun->setFlags((targetFun->flags() & ~JSFunction::INTERPRETED_LAZY) |
sourceFun->flags() | JSFunction::EXTENDED);
targetFun->setScript(cscript);
MOZ_ASSERT(targetFun->isExtended());
return true;
} }
bool bool

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

@ -153,12 +153,7 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
#ifdef DEBUG #ifdef DEBUG
RootedObject enclosingScope(cx, script->enclosingStaticScope()); RootedObject enclosingScope(cx, script->enclosingStaticScope());
for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) { for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
if (i.type() == StaticScopeIter<NoGC>::NonSyntactic) { if (i.hasDynamicScopeObject()) {
while (scope->is<DynamicWithObject>() || scope->is<NonSyntacticVariablesObject>()) {
MOZ_ASSERT(!IsSyntacticScope(scope));
scope = &scope->as<ScopeObject>().enclosingScope();
}
} else if (i.hasSyntacticDynamicScopeObject()) {
switch (i.type()) { switch (i.type()) {
case StaticScopeIter<NoGC>::Function: case StaticScopeIter<NoGC>::Function:
MOZ_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript()); MOZ_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
@ -178,14 +173,13 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
case StaticScopeIter<NoGC>::Eval: case StaticScopeIter<NoGC>::Eval:
scope = &scope->as<CallObject>().enclosingScope(); scope = &scope->as<CallObject>().enclosingScope();
break; break;
case StaticScopeIter<NoGC>::NonSyntactic:
MOZ_CRASH("NonSyntactic should not have a syntactic scope");
break;
} }
} }
} }
MOZ_ASSERT(scope->is<GlobalObject>() || scope->is<DebugScopeObject>()); // The scope chain is always ended by one or more non-syntactic
// ScopeObjects (viz. GlobalObject or a non-syntactic WithObject).
MOZ_ASSERT(!IsSyntacticScope(scope));
#endif #endif
} }
@ -251,7 +245,8 @@ InterpreterFrame::epilogue(JSContext* cx)
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
DebugScopes::onPopStrictEvalScope(this); DebugScopes::onPopStrictEvalScope(this);
} else if (isDirectEvalFrame()) { } else if (isDirectEvalFrame()) {
MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain())); if (isDebuggerEvalFrame())
MOZ_ASSERT(!IsSyntacticScope(scopeChain()));
} else { } else {
/* /*
* Debugger.Object.prototype.evalInGlobal creates indirect eval * Debugger.Object.prototype.evalInGlobal creates indirect eval
@ -1143,7 +1138,7 @@ FrameIter::matchCallee(JSContext* cx, HandleFunction fun) const
// expect both functions to have the same JSScript. If so, and if they are // expect both functions to have the same JSScript. If so, and if they are
// different, then they cannot be equal. // different, then they cannot be equal.
RootedObject global(cx, &fun->global()); RootedObject global(cx, &fun->global());
bool useSameScript = CanReuseScriptForClone(fun->compartment(), currentCallee, global); bool useSameScript = CloneFunctionObjectUseSameScript(fun->compartment(), currentCallee, global);
if (useSameScript && if (useSameScript &&
(currentCallee->hasScript() != fun->hasScript() || (currentCallee->hasScript() != fun->hasScript() ||
currentCallee->nonLazyScript() != fun->nonLazyScript())) currentCallee->nonLazyScript() != fun->nonLazyScript()))

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

@ -146,10 +146,8 @@ PrepareScript(nsIURI* uri,
} }
if (!reuseGlobal) { if (!reuseGlobal) {
if (JS_IsGlobalObject(targetObj)) options.setHasPollutedScope(!JS_IsGlobalObject(targetObj));
JS::Compile(cx, options, srcBuf, script); JS::Compile(cx, options, srcBuf, script);
else
JS::CompileForNonSyntacticScope(cx, options, srcBuf, script);
} else { } else {
AutoObjectVector scopeChain(cx); AutoObjectVector scopeChain(cx);
if (!JS_IsGlobalObject(targetObj) && if (!JS_IsGlobalObject(targetObj) &&
@ -164,11 +162,9 @@ PrepareScript(nsIURI* uri,
// We only use lazy source when no special encoding is specified because // We only use lazy source when no special encoding is specified because
// the lazy source loader doesn't know the encoding. // the lazy source loader doesn't know the encoding.
if (!reuseGlobal) { if (!reuseGlobal) {
options.setSourceIsLazy(true); options.setSourceIsLazy(true)
if (JS_IsGlobalObject(targetObj)) .setHasPollutedScope(!JS_IsGlobalObject(targetObj));
JS::Compile(cx, options, buf, len, script); JS::Compile(cx, options, buf, len, script);
else
JS::CompileForNonSyntacticScope(cx, options, buf, len, script);
} else { } else {
AutoObjectVector scopeChain(cx); AutoObjectVector scopeChain(cx);
if (!JS_IsGlobalObject(targetObj) && if (!JS_IsGlobalObject(targetObj) &&