mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1165486 - Restructure function and script cloning in light of PollutingGlobal scope changes. (r=Waldo)
CloneFunctionObject is split into the following: - CloneFunctionAndScript, which deep clones the function and its script, giving the cloned script a new static scope chain. This is used for cloning singleton lambdas and JSAPI cloning. For singleton lambdas, the original and the clone script have the same static scope chain. For JSAPI cloning, a new static scope is provided (either null, for a clean global, or StaticPollutingGlobalObject, for a polluted global). - CloneFunctionReuseScript, which clones the function but reuses the script, and thus keeps the same static scope chain. CloneScript is split into the following: - CloneGlobalScript, which clones a script with and gives it a new static scope. - CloneScriptIntoFunction, which clones a script into a JSFunction and gives it a new static scope. Cloning a script into a new function container requires slightly different logic to hook up the static scope chain before cloning inner scripts.
This commit is contained in:
parent
1aa1600b4e
commit
eefda67985
@ -3325,11 +3325,23 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
|
||||
|
||||
// If a function was compiled to be lexically nested inside some other
|
||||
// script, we cannot clone it without breaking the compiler's assumptions.
|
||||
JSObject* scope = fun->nonLazyScript()->enclosingStaticScope();
|
||||
if (scope && (!scope->is<StaticEvalObject>() ||
|
||||
scope->as<StaticEvalObject>().isDirect() ||
|
||||
scope->as<StaticEvalObject>().isStrict()))
|
||||
{
|
||||
if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) {
|
||||
// If the script already deals with a non-syntactic scope, we can clone
|
||||
// it.
|
||||
if (scope->is<StaticNonSyntacticScopeObjects>())
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3337,7 +3349,8 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope)
|
||||
CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope,
|
||||
Handle<ScopeObject*> staticScope)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
@ -3374,7 +3387,21 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScop
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CloneFunctionObject(cx, fun, dynamicScope, fun->getAllocKind());
|
||||
if (CanReuseScriptForClone(cx->compartment(), fun, dynamicScope)) {
|
||||
// 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 {
|
||||
@ -3382,18 +3409,18 @@ namespace JS {
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
CloneFunctionObject(JSContext* cx, JS::Handle<JSObject*> funobj)
|
||||
{
|
||||
return CloneFunctionObject(cx, funobj, cx->global());
|
||||
return CloneFunctionObject(cx, funobj, cx->global(), /* staticScope = */ nullptr);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain)
|
||||
{
|
||||
RootedObject dynamicScope(cx);
|
||||
RootedObject unusedStaticScope(cx);
|
||||
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
|
||||
Rooted<ScopeObject*> staticScope(cx);
|
||||
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope))
|
||||
return nullptr;
|
||||
|
||||
return CloneFunctionObject(cx, funobj, dynamicScope);
|
||||
return CloneFunctionObject(cx, funobj, dynamicScope, staticScope);
|
||||
}
|
||||
|
||||
} // namespace JS
|
||||
@ -4238,7 +4265,7 @@ ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptAr
|
||||
return false;
|
||||
|
||||
RootedScript script(cx, scriptArg);
|
||||
if (!script->hasNonSyntacticScope()) {
|
||||
if (!script->hasNonSyntacticScope() && !dynamicScope->is<GlobalObject>()) {
|
||||
script = CloneGlobalScript(cx, staticScope, script);
|
||||
if (!script)
|
||||
return false;
|
||||
@ -4279,7 +4306,7 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg)
|
||||
CHECK_REQUEST(cx);
|
||||
RootedScript script(cx, scriptArg);
|
||||
if (script->compartment() != cx->compartment()) {
|
||||
script = CloneScript(cx, nullptr, nullptr, script);
|
||||
script = CloneGlobalScript(cx, /* enclosingScope = */ nullptr, script);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
231
js/src/jsfun.cpp
231
js/src/jsfun.cpp
@ -35,6 +35,7 @@
|
||||
#include "jit/JitFrameIterator.h"
|
||||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/Shape.h"
|
||||
@ -524,7 +525,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
|
||||
HasSingletonType = 0x8
|
||||
};
|
||||
|
||||
/* NB: Keep this in sync with CloneFunctionAndScript. */
|
||||
/* NB: Keep this in sync with CloneInnerInterpretedFunction. */
|
||||
RootedAtom atom(xdr->cx());
|
||||
uint32_t firstword = 0; /* bitmask of FirstWordFlag */
|
||||
uint32_t flagsword = 0; /* word for argument count and fun->flags */
|
||||
@ -615,10 +616,9 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
|
||||
fun->setFlags(uint16_t(flagsword));
|
||||
fun->initAtom(atom);
|
||||
if (firstword & IsLazy) {
|
||||
fun->initLazyScript(lazy);
|
||||
MOZ_ASSERT(fun->lazyScript() == lazy);
|
||||
} else {
|
||||
fun->initScript(script);
|
||||
script->setFunction(fun);
|
||||
MOZ_ASSERT(fun->nonLazyScript() == script);
|
||||
MOZ_ASSERT(fun->nargs() == script->bindings.numArgs());
|
||||
}
|
||||
|
||||
@ -637,44 +637,6 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleObject, HandleScript, Mu
|
||||
template bool
|
||||
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
|
||||
* property of its 'this' parameter, and walks the prototype chain of v (only
|
||||
@ -828,7 +790,7 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
|
||||
/*
|
||||
* The default 'new' group of Function.prototype is required by type
|
||||
* inference to have unknown properties, to simplify handling of e.g.
|
||||
* CloneFunctionObject.
|
||||
* NewFunctionClone.
|
||||
*/
|
||||
if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto))
|
||||
return nullptr;
|
||||
@ -1423,16 +1385,13 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
|
||||
|
||||
if (script) {
|
||||
RootedObject enclosingScope(cx, lazy->enclosingScope());
|
||||
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
|
||||
RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, enclosingScope, fun, script));
|
||||
if (!clonedScript)
|
||||
return false;
|
||||
|
||||
clonedScript->setSourceObject(lazy->sourceObject());
|
||||
|
||||
fun->initAtom(script->functionNonDelazifying()->displayAtom());
|
||||
clonedScript->setFunction(fun);
|
||||
|
||||
fun->setUnlazifiedScript(clonedScript);
|
||||
|
||||
if (!lazy->maybeScript())
|
||||
lazy->initScript(clonedScript);
|
||||
@ -2086,8 +2045,8 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
|
||||
}
|
||||
|
||||
bool
|
||||
js::CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
|
||||
HandleObject newParent)
|
||||
js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun,
|
||||
HandleObject newParent)
|
||||
{
|
||||
if (compartment != fun->compartment() ||
|
||||
fun->isSingleton() ||
|
||||
@ -2108,75 +2067,52 @@ js::CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction
|
||||
return true;
|
||||
|
||||
// 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 non-syntactic scope. If we're lazy, go ahead and clone the
|
||||
// script; see the big comment at the end of CopyScriptInternal for the
|
||||
// explanation of what's going on there.
|
||||
return !fun->isInterpreted() ||
|
||||
(fun->hasScript() && fun->nonLazyScript()->hasNonSyntacticScope());
|
||||
}
|
||||
|
||||
JSFunction*
|
||||
js::CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind allocKind,
|
||||
NewObjectKind newKindArg /* = GenericObject */,
|
||||
HandleObject proto)
|
||||
static bool
|
||||
FunctionCloneScopeIsWellFormed(JSContext* cx, HandleObject parent)
|
||||
{
|
||||
MOZ_ASSERT(parent);
|
||||
MOZ_ASSERT(!fun->isBoundFunction());
|
||||
|
||||
bool useSameScript = CloneFunctionObjectUseSameScript(cx->compartment(), fun, parent);
|
||||
|
||||
NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
|
||||
RootedObject cloneProto(cx, proto);
|
||||
if (!cloneProto && fun->isStarGenerator()) {
|
||||
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
|
||||
if (!cloneProto)
|
||||
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
|
||||
return !realParent || realParent == cx->global() ||
|
||||
realParent->is<DebugScopeObject>() ||
|
||||
realParent->isUnqualifiedVarObj();
|
||||
}
|
||||
|
||||
|
||||
static inline JSFunction*
|
||||
NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
|
||||
gc::AllocKind allocKind, HandleObject proto)
|
||||
{
|
||||
RootedObject cloneProto(cx, proto);
|
||||
if (!proto && fun->isStarGenerator()) {
|
||||
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
|
||||
if (!cloneProto)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
|
||||
allocKind, newKind);
|
||||
if (!cloneobj)
|
||||
return nullptr;
|
||||
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;
|
||||
if (allocKind == AllocKind::FUNCTION_EXTENDED)
|
||||
flags |= JSFunction::EXTENDED;
|
||||
|
||||
clone->setArgCount(fun->nargs());
|
||||
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());
|
||||
|
||||
if (allocKind == AllocKind::FUNCTION_EXTENDED) {
|
||||
@ -2188,34 +2124,103 @@ js::CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
}
|
||||
}
|
||||
|
||||
if (useSameScript) {
|
||||
/*
|
||||
* Clone the function, reusing its script. We can use the same group as
|
||||
* the original function provided that its prototype is correct.
|
||||
*/
|
||||
if (fun->getProto() == clone->getProto())
|
||||
clone->setGroup(fun->group());
|
||||
return clone;
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
RootedFunction cloneRoot(cx, clone);
|
||||
JSFunction*
|
||||
js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind allocKind /* = FUNCTION */ ,
|
||||
NewObjectKind newKind /* = GenericObject */,
|
||||
HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(FunctionCloneScopeIsWellFormed(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());
|
||||
}
|
||||
|
||||
/*
|
||||
* Across compartments or if we have to introduce a polluted 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).
|
||||
* Clone the function, reusing its script. We can use the same group as
|
||||
* the original function provided that its prototype is correct.
|
||||
*/
|
||||
PollutedGlobalScopeOption globalScopeOption = parent->is<GlobalObject>() ?
|
||||
HasCleanGlobalScope : HasPollutedGlobalScope;
|
||||
if (cloneRoot->isInterpreted() &&
|
||||
!CloneFunctionScript(cx, fun, cloneRoot, globalScopeOption, newKindArg))
|
||||
{
|
||||
if (fun->getProto() == clone->getProto())
|
||||
clone->setGroup(fun->group());
|
||||
return clone;
|
||||
}
|
||||
|
||||
JSFunction*
|
||||
js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
HandleObject newStaticScope,
|
||||
gc::AllocKind allocKind /* = FUNCTION */,
|
||||
HandleObject proto /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(FunctionCloneScopeIsWellFormed(cx, parent));
|
||||
MOZ_ASSERT(!fun->isBoundFunction());
|
||||
|
||||
RootedFunction clone(cx, NewFunctionClone(cx, fun, SingletonObject, allocKind, proto));
|
||||
if (!clone)
|
||||
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()) {
|
||||
// The self-hosting compartment is shared across processes, and
|
||||
// AutoDelazify enters fun->compartment(). We would get races if the
|
||||
// self-hosting compartment has lazy interpreted functions.
|
||||
MOZ_ASSERT_IF(fun->compartment()->isSelfHosting, !fun->isInterpretedLazy());
|
||||
JSScript::AutoDelazify funScript(cx);
|
||||
if (fun->isInterpretedLazy()) {
|
||||
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,14 +633,20 @@ class FunctionExtended : public JSFunction
|
||||
};
|
||||
|
||||
extern bool
|
||||
CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
|
||||
HandleObject newParent);
|
||||
CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
|
||||
|
||||
extern JSFunction*
|
||||
CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind kind = gc::AllocKind::FUNCTION,
|
||||
NewObjectKind newKindArg = GenericObject,
|
||||
HandleObject proto = nullptr);
|
||||
CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind kind = gc::AllocKind::FUNCTION,
|
||||
NewObjectKind newKindArg = GenericObject,
|
||||
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
|
||||
FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
|
||||
@ -702,10 +708,6 @@ bool
|
||||
XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
|
||||
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,
|
||||
* assuming that the method (clasp->name).prototype.<name of callee function>
|
||||
|
@ -85,7 +85,12 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec
|
||||
gc::AllocKind kind = fun->isExtended()
|
||||
? extendedFinalizeKind
|
||||
: 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 */
|
||||
|
@ -576,10 +576,10 @@ enum XDRClassKind {
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
|
||||
js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript enclosingScript,
|
||||
HandleFunction fun, MutableHandleScript scriptp)
|
||||
{
|
||||
/* NB: Keep this in sync with CloneScript. */
|
||||
/* NB: Keep this in sync with CopyScript. */
|
||||
|
||||
enum ScriptBits {
|
||||
NoScriptRval,
|
||||
@ -613,6 +613,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
|
||||
|
||||
JSContext* cx = xdr->cx();
|
||||
RootedScript script(cx);
|
||||
RootedObject enclosingScope(cx, enclosingScopeArg);
|
||||
natoms = nsrcnotes = 0;
|
||||
nconsts = nobjects = nregexps = ntrynotes = nblockscopes = nyieldoffsets = 0;
|
||||
|
||||
@ -801,10 +802,26 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
|
||||
MOZ_ASSERT(enclosingScript->sourceObject()->is<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)),
|
||||
options, /* staticLevel = */ 0, sourceObject, 0, 0);
|
||||
if (!script)
|
||||
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. */
|
||||
@ -982,7 +999,12 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
|
||||
MOZ_ASSERT(enclosingStaticScopeIndex < i);
|
||||
enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
|
||||
} else {
|
||||
enclosingStaticScope = fun;
|
||||
// This is not ternary because MSVC can't typecheck the
|
||||
// ternary.
|
||||
if (fun)
|
||||
enclosingStaticScope = fun;
|
||||
else
|
||||
enclosingStaticScope = enclosingScope;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1019,8 +1041,15 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
|
||||
|
||||
StaticScopeIter<NoGC> ssi(funEnclosingScope);
|
||||
|
||||
if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::Function) {
|
||||
MOZ_ASSERT(ssi.done() == !fun);
|
||||
// Starting from a nested function, hitting a non-syntactic
|
||||
// scope on the static scope chain means that its enclosing
|
||||
// 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;
|
||||
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
|
||||
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
|
||||
@ -1036,7 +1065,12 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enc
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
if (funEnclosingScopeIndex == UINT32_MAX) {
|
||||
funEnclosingScope = fun;
|
||||
// This is not ternary because MSVC can't typecheck the
|
||||
// ternary.
|
||||
if (fun)
|
||||
funEnclosingScope = fun;
|
||||
else
|
||||
funEnclosingScope = enclosingScope;
|
||||
} else {
|
||||
MOZ_ASSERT(funEnclosingScopeIndex < i);
|
||||
funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
|
||||
@ -1177,9 +1211,13 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == XDR_DECODE)
|
||||
if (mode == XDR_DECODE) {
|
||||
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
|
||||
packedFields, begin, end, lineno, column));
|
||||
if (!lazy)
|
||||
return false;
|
||||
fun->initLazyScript(lazy);
|
||||
}
|
||||
}
|
||||
|
||||
// Code free variables.
|
||||
@ -3013,15 +3051,48 @@ Rebase(JSScript* dst, JSScript* src, T* srcp)
|
||||
return reinterpret_cast<T*>(dst->data + off);
|
||||
}
|
||||
|
||||
JSScript*
|
||||
js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
|
||||
PollutedGlobalScopeOption polluted /* = HasCleanGlobalScope */,
|
||||
NewObjectKind newKind /* = GenericObject */)
|
||||
static JSObject*
|
||||
CloneInnerInterpretedFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun)
|
||||
{
|
||||
/* 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;
|
||||
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()) {
|
||||
// Toplevel run-once scripts may not be cloned.
|
||||
JS_ReportError(cx, "No cloning toplevel run-once scripts");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* NB: Keep this in sync with XDRScript. */
|
||||
@ -3040,7 +3111,7 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
size_t size = src->dataSize();
|
||||
uint8_t* data = AllocScriptData(cx->zone(), size);
|
||||
if (size && !data)
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
/* Bindings */
|
||||
|
||||
@ -3048,7 +3119,7 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
InternalHandle<Bindings*> bindingsHandle =
|
||||
InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
|
||||
if (!Bindings::clone(cx, bindingsHandle, data, src))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
/* Objects */
|
||||
|
||||
@ -3065,7 +3136,7 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope())
|
||||
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
|
||||
else
|
||||
enclosingScope = fun;
|
||||
enclosingScope = scriptStaticScope;
|
||||
|
||||
clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
|
||||
} else if (obj->is<JSFunction>()) {
|
||||
@ -3074,32 +3145,36 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
if (cx->compartment() != innerFun->compartment()) {
|
||||
MOZ_ASSERT(innerFun->isAsmJSNative());
|
||||
JS_ReportError(cx, "AsmJS modules do not yet support cloning.");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
clone = innerFun;
|
||||
} else {
|
||||
if (innerFun->isInterpretedLazy()) {
|
||||
AutoCompartment ac(cx, innerFun);
|
||||
if (!innerFun->getOrCreateScript(cx))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
|
||||
StaticScopeIter<CanGC> ssi(cx, staticScope);
|
||||
RootedObject enclosingScope(cx);
|
||||
if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::Function)
|
||||
enclosingScope = fun;
|
||||
else if (ssi.type() == StaticScopeIter<CanGC>::Block)
|
||||
if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::NonSyntactic) {
|
||||
enclosingScope = scriptStaticScope;
|
||||
} else if (ssi.type() == StaticScopeIter<CanGC>::Function) {
|
||||
MOZ_ASSERT(scriptStaticScope->is<JSFunction>());
|
||||
enclosingScope = scriptStaticScope;
|
||||
} else if (ssi.type() == StaticScopeIter<CanGC>::Block) {
|
||||
enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
|
||||
else
|
||||
} else {
|
||||
enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
|
||||
}
|
||||
|
||||
clone = CloneFunctionAndScript(cx, enclosingScope, innerFun, polluted);
|
||||
clone = CloneInnerInterpretedFunction(cx, enclosingScope, innerFun);
|
||||
}
|
||||
} else {
|
||||
clone = DeepCloneObjectLiteral(cx, obj, TenuredObject);
|
||||
}
|
||||
if (!clone || !objects.append(clone))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3111,50 +3186,11 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
for (unsigned i = 0; i < nregexps; i++) {
|
||||
JSObject* clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
|
||||
if (!clone || !regexps.append(clone))
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
/* Now that all fallible allocation is complete, do the copying. */
|
||||
|
||||
dst->bindings = bindings;
|
||||
|
||||
@ -3231,44 +3267,90 @@ js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
*/
|
||||
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->maybeLazyScript());
|
||||
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->isRelazifiable());
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
js::CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
|
||||
PollutedGlobalScopeOption polluted, NewObjectKind newKind)
|
||||
JSScript*
|
||||
js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
HandleScript src)
|
||||
{
|
||||
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!");
|
||||
MOZ_ASSERT(fun->isInterpreted());
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 dst;
|
||||
}
|
||||
|
||||
DebugScript*
|
||||
|
@ -755,11 +755,6 @@ bool
|
||||
XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
|
||||
HandleFunction fun, MutableHandleScript scriptp);
|
||||
|
||||
JSScript*
|
||||
CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
|
||||
PollutedGlobalScopeOption polluted = HasCleanGlobalScope,
|
||||
NewObjectKind newKind = GenericObject);
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
|
||||
@ -772,6 +767,16 @@ template<XDRMode mode>
|
||||
bool
|
||||
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 */
|
||||
|
||||
class JSScript : public js::gc::TenuredCell
|
||||
@ -779,13 +784,13 @@ class JSScript : public js::gc::TenuredCell
|
||||
template <js::XDRMode mode>
|
||||
friend
|
||||
bool
|
||||
js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript,
|
||||
js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope,
|
||||
js::HandleScript enclosingScript,
|
||||
js::HandleFunction fun, js::MutableHandleScript scriptp);
|
||||
|
||||
friend JSScript*
|
||||
js::CloneScript(JSContext* cx, js::HandleObject enclosingScope, js::HandleFunction fun,
|
||||
js::HandleScript src, js::PollutedGlobalScopeOption polluted,
|
||||
js::NewObjectKind newKind);
|
||||
friend bool
|
||||
js::detail::CopyScript(JSContext* cx, js::HandleObject scriptStaticScope, js::HandleScript src,
|
||||
js::HandleScript dst);
|
||||
|
||||
public:
|
||||
//
|
||||
@ -2288,9 +2293,12 @@ DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript maybeScr
|
||||
uint32_t* pcOffset, bool* mutedErrors,
|
||||
LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
|
||||
|
||||
bool
|
||||
CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
|
||||
PollutedGlobalScopeOption polluted, NewObjectKind newKind);
|
||||
JSScript*
|
||||
CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
HandleScript src);
|
||||
|
||||
JSScript*
|
||||
CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
@ -1722,7 +1722,9 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
|
||||
js::gc::AllocKind kind = hasName
|
||||
? gc::AllocKind::FUNCTION_EXTENDED
|
||||
: selfHostedFunction->getAllocKind();
|
||||
clone = CloneFunctionObject(cx, selfHostedFunction, cx->global(), kind, TenuredObject);
|
||||
MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global()));
|
||||
clone = CloneFunctionAndScript(cx, selfHostedFunction, cx->global(),
|
||||
/* newStaticScope = */ nullptr, kind);
|
||||
// To be able to re-lazify the cloned function, its name in the
|
||||
// self-hosting compartment has to be stored on the clone.
|
||||
if (clone && hasName)
|
||||
@ -1806,22 +1808,17 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
|
||||
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
|
||||
// aren't any.
|
||||
MOZ_ASSERT(!sourceFun->isGenerator());
|
||||
RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
|
||||
if (!sourceScript)
|
||||
return false;
|
||||
MOZ_ASSERT(!sourceScript->enclosingStaticScope());
|
||||
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;
|
||||
|
||||
RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
|
||||
if (!sourceScript)
|
||||
return false;
|
||||
MOZ_ASSERT(!sourceScript->enclosingStaticScope());
|
||||
return !!CloneScriptIntoFunction(cx, /* enclosingScope = */ nullptr, targetFun, sourceScript);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1126,7 +1126,7 @@ FrameIter::matchCallee(JSContext* cx, HandleFunction fun) const
|
||||
// expect both functions to have the same JSScript. If so, and if they are
|
||||
// different, then they cannot be equal.
|
||||
RootedObject global(cx, &fun->global());
|
||||
bool useSameScript = CloneFunctionObjectUseSameScript(fun->compartment(), currentCallee, global);
|
||||
bool useSameScript = CanReuseScriptForClone(fun->compartment(), currentCallee, global);
|
||||
if (useSameScript &&
|
||||
(currentCallee->hasScript() != fun->hasScript() ||
|
||||
currentCallee->nonLazyScript() != fun->nonLazyScript()))
|
||||
|
Loading…
Reference in New Issue
Block a user