mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1125423 part 1 - Attach WindowProxies to globals instead of using innerObject/outerObject hooks. r=bz,luke
This commit is contained in:
parent
ce3739bf35
commit
68d1fa5c75
@ -988,7 +988,7 @@ bool
|
||||
nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal));
|
||||
MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsWindowProxy(aGlobal));
|
||||
|
||||
// Check the bits on the compartment private.
|
||||
return xpc::Scriptability::Get(aGlobal).Allowed();
|
||||
|
@ -1102,6 +1102,7 @@ NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
|
||||
isChrome ? &nsChromeOuterWindowProxy::singleton
|
||||
: &nsOuterWindowProxy::singleton,
|
||||
options);
|
||||
MOZ_ASSERT_IF(obj, js::IsWindowProxy(obj));
|
||||
|
||||
NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
|
||||
return obj;
|
||||
@ -2659,6 +2660,11 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
// Enter the new global's compartment.
|
||||
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
|
||||
|
||||
{
|
||||
JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
|
||||
js::SetWindowProxy(cx, newInnerGlobal, outer);
|
||||
}
|
||||
|
||||
// Set scriptability based on the state of the docshell.
|
||||
bool allow = GetDocShell()->GetCanExecuteScripts();
|
||||
xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
|
||||
|
@ -3124,7 +3124,7 @@ DeprecationWarning(JSContext* aCx, JSObject* aObject,
|
||||
bool
|
||||
ObjectToOuterObjectValue(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
JSObject* outer = JS_ObjectToOuterObject(cx, obj);
|
||||
JSObject* outer = js::ToWindowProxyIfWindow(obj);
|
||||
vp.setObject(*outer);
|
||||
return true;
|
||||
}
|
||||
|
@ -776,13 +776,9 @@ CouldBeDOMBinding(nsWrapperCache* aCache)
|
||||
inline bool
|
||||
TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
if (js::IsInnerObject(&rval.toObject())) {
|
||||
JS::Rooted<JSObject*> obj(cx, &rval.toObject());
|
||||
obj = JS_ObjectToOuterObject(cx, obj);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (js::IsWindow(&rval.toObject())) {
|
||||
JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
|
||||
MOZ_ASSERT(obj);
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
}
|
||||
|
||||
|
@ -1350,10 +1350,8 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = JS_ObjectToInnerObject(cx, obj);
|
||||
MOZ_ASSERT(obj,
|
||||
"JS_ObjectToInnerObject should never return null with non-null "
|
||||
"input.");
|
||||
obj = js::ToWindowIfWindowProxy(obj);
|
||||
MOZ_ASSERT(obj, "ToWindowIfWindowProxy should never return null");
|
||||
|
||||
if (result) {
|
||||
// Initialize the out param to void
|
||||
|
@ -537,9 +537,8 @@ JavaScriptShared::findObjectById(JSContext* cx, const ObjectId& objId)
|
||||
if (objId.hasXrayWaiver()) {
|
||||
{
|
||||
JSAutoCompartment ac2(cx, obj);
|
||||
obj = JS_ObjectToOuterObject(cx, obj);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
obj = js::ToWindowProxyIfWindow(obj);
|
||||
MOZ_ASSERT(obj);
|
||||
}
|
||||
if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj))
|
||||
return nullptr;
|
||||
|
@ -737,7 +737,7 @@ struct JSClass {
|
||||
// application.
|
||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT \
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 36)
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 37)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
@ -33,7 +33,7 @@ AssertInnerizedScopeChain(JSContext* cx, JSObject& scopeobj)
|
||||
#ifdef DEBUG
|
||||
RootedObject obj(cx);
|
||||
for (obj = &scopeobj; obj; obj = obj->enclosingScope())
|
||||
MOZ_ASSERT(GetInnerObject(obj) == obj);
|
||||
MOZ_ASSERT(!IsWindowProxy(obj));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -5551,13 +5551,15 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecod
|
||||
const Class* outerClass = nullptr;
|
||||
if (!isDOMProxy && !obj->isNative()) {
|
||||
outerClass = obj->getClass();
|
||||
DebugOnly<JSObject*> outer = obj.get();
|
||||
obj = GetInnerObject(obj);
|
||||
MOZ_ASSERT(script->global().isNative());
|
||||
if (obj != &script->global())
|
||||
if (!IsWindowProxy(obj))
|
||||
return true;
|
||||
// ICGetProp_CallNative*::Compiler::generateStubCode depends on this.
|
||||
MOZ_ASSERT(&((GetProxyDataLayout(outer)->values->privateSlot).toObject()) == obj);
|
||||
|
||||
// This must be a WindowProxy for the current Window/global. Else it'd
|
||||
// be a cross-compartment wrapper and IsWindowProxy returns false for
|
||||
// those.
|
||||
MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx->global());
|
||||
obj = cx->global();
|
||||
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
|
||||
&domProxyShadowsResult, &domProxyHasGeneration))
|
||||
{
|
||||
@ -6471,13 +6473,9 @@ ICGetPropCallNativeCompiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
if (outerClass_) {
|
||||
ValueOperand val = regs.takeAnyValue();
|
||||
Register tmp = regs.takeAny();
|
||||
masm.branchTestObjClass(Assembler::NotEqual, objReg, tmp, outerClass_, &failure);
|
||||
masm.loadPtr(Address(objReg, ProxyDataOffset + offsetof(ProxyDataLayout, values)), tmp);
|
||||
masm.loadValue(Address(tmp, offsetof(ProxyValueArray, privateSlot)), val);
|
||||
masm.movePtr(masm.extractObject(val, ExtractTemp0), objReg);
|
||||
regs.add(val);
|
||||
masm.movePtr(ImmGCPtr(cx->global()), objReg);
|
||||
regs.add(tmp);
|
||||
}
|
||||
}
|
||||
|
@ -11847,11 +11847,14 @@ IonBuilder::tryInnerizeWindow(MDefinition* obj)
|
||||
if (!singleton)
|
||||
return obj;
|
||||
|
||||
JSObject* inner = GetInnerObject(singleton);
|
||||
if (inner == singleton || inner != &script()->global())
|
||||
if (!IsWindowProxy(singleton))
|
||||
return obj;
|
||||
|
||||
// When we navigate, the outer object is brain transplanted and we'll mark
|
||||
// This must be a WindowProxy for the current Window/global. Else it'd be
|
||||
// a cross-compartment wrapper and IsWindowProxy returns false for those.
|
||||
MOZ_ASSERT(ToWindowIfWindowProxy(singleton) == &script()->global());
|
||||
|
||||
// When we navigate, the WindowProxy is brain transplanted and we'll mark
|
||||
// its ObjectGroup as having unknown properties. The type constraint we add
|
||||
// here will invalidate JIT code when this happens.
|
||||
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(singleton);
|
||||
|
@ -56,6 +56,8 @@ static const JSWrapObjectCallbacks WrapObjectCallbacks = {
|
||||
|
||||
BEGIN_TEST(testBug604087)
|
||||
{
|
||||
js::SetWindowProxyClass(cx->runtime(), &OuterWrapperClass);
|
||||
|
||||
js::WrapperOptions options;
|
||||
options.setClass(&OuterWrapperClass);
|
||||
options.setSingleton(true);
|
||||
|
@ -403,7 +403,7 @@ JSCompartment::wrap(JSContext* cx, MutableHandleObject obj, HandleObject existin
|
||||
const JSWrapObjectCallbacks* cb = cx->runtime()->wrapObjectCallbacks;
|
||||
|
||||
if (obj->compartment() == this) {
|
||||
obj.set(GetOuterObject(cx, obj));
|
||||
obj.set(ToWindowProxyIfWindow(obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ JSCompartment::wrap(JSContext* cx, MutableHandleObject obj, HandleObject existin
|
||||
obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true));
|
||||
|
||||
if (obj->compartment() == this) {
|
||||
MOZ_ASSERT(obj == GetOuterObject(cx, obj));
|
||||
MOZ_ASSERT(!IsWindow(obj));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -442,7 +442,7 @@ JSCompartment::wrap(JSContext* cx, MutableHandleObject obj, HandleObject existin
|
||||
if (!obj)
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(obj == GetOuterObject(cx, obj));
|
||||
MOZ_ASSERT(!IsWindow(obj));
|
||||
|
||||
if (obj->compartment() == this)
|
||||
return true;
|
||||
|
@ -82,10 +82,10 @@ JS_FindCompilationScope(JSContext* cx, HandleObject objArg)
|
||||
obj = UncheckedUnwrap(obj);
|
||||
|
||||
/*
|
||||
* Innerize the target_obj so that we compile in the correct (inner)
|
||||
* scope.
|
||||
* Get the Window if `obj` is a WindowProxy so that we compile in the
|
||||
* correct (global) scope.
|
||||
*/
|
||||
return GetInnerObject(obj);
|
||||
return ToWindowIfWindowProxy(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSFunction*)
|
||||
@ -1282,3 +1282,53 @@ js::GetPropertyNameFromPC(JSScript* script, jsbytecode* pc)
|
||||
return nullptr;
|
||||
return script->getName(pc);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::SetWindowProxyClass(JSRuntime* rt, const js::Class* clasp)
|
||||
{
|
||||
MOZ_ASSERT(!rt->maybeWindowProxyClass());
|
||||
rt->setWindowProxyClass(clasp);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::SetWindowProxy(JSContext* cx, HandleObject global, HandleObject windowProxy)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
assertSameCompartment(cx, global, windowProxy);
|
||||
|
||||
MOZ_ASSERT(IsWindowProxy(windowProxy));
|
||||
global->as<GlobalObject>().setWindowProxy(windowProxy);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
js::ToWindowIfWindowProxy(JSObject* obj)
|
||||
{
|
||||
if (IsWindowProxy(obj))
|
||||
return &obj->global();
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
js::ToWindowProxyIfWindow(JSObject* obj)
|
||||
{
|
||||
if (IsWindow(obj))
|
||||
return obj->as<GlobalObject>().windowProxy();
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsWindowProxy(JSObject* obj)
|
||||
{
|
||||
// Note: simply checking `obj == obj->global().windowProxy()` is not
|
||||
// sufficient: we may have transplanted the window proxy with a CCW.
|
||||
// Check the Class to ensure we really have a window proxy.
|
||||
return obj->getClass() == obj->runtimeFromAnyThread()->maybeWindowProxyClass();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::detail::IsWindowSlow(JSObject* obj)
|
||||
{
|
||||
return obj->as<GlobalObject>().maybeWindowProxy();
|
||||
}
|
||||
|
@ -148,14 +148,6 @@ JS_GetScriptPrincipals(JSScript* script);
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_ScriptHasMutedErrors(JSScript* script);
|
||||
|
||||
/* Safe to call with input obj == nullptr. Returns non-nullptr iff obj != nullptr. */
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
JS_ObjectToInnerObject(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
/* Requires obj != nullptr. */
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
JS_ObjectToOuterObject(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
|
||||
|
||||
@ -676,16 +668,6 @@ ParentKeyForStandardClass(JSProtoKey key)
|
||||
return JSProto_Object;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsInnerObject(JSObject* obj) {
|
||||
return !!GetObjectClass(obj)->ext.outerObject;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsOuterObject(JSObject* obj) {
|
||||
return !!GetObjectClass(obj)->ext.innerObject;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsFunctionObject(JSObject* obj);
|
||||
|
||||
@ -2859,6 +2841,77 @@ ReportIsNotFunction(JSContext* cx, JS::HandleValue v);
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args);
|
||||
|
||||
/**
|
||||
* Window and WindowProxy
|
||||
*
|
||||
* The functions below have to do with Windows and WindowProxies. There's an
|
||||
* invariant that actual Window objects (the global objects of web pages) are
|
||||
* never directly exposed to script. Instead we often substitute a WindowProxy.
|
||||
*
|
||||
* The scope chain, on the other hand, contains the Window and never its
|
||||
* WindowProxy.
|
||||
*
|
||||
* As a result, we have calls to these "substitute-this-object-for-that-object"
|
||||
* functions sprinkled at apparently arbitrary (but actually *very* carefully
|
||||
* and nervously selected) places throughout the engine and indeed the
|
||||
* universe.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tell the JS engine which Class is used for WindowProxy objects. Used by the
|
||||
* functions below.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
SetWindowProxyClass(JSRuntime* rt, const Class* clasp);
|
||||
|
||||
/**
|
||||
* Associates a WindowProxy with a Window (global object). `windowProxy` must
|
||||
* have the Class set by SetWindowProxyClass.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
SetWindowProxy(JSContext* cx, JS::HandleObject global, JS::HandleObject windowProxy);
|
||||
|
||||
namespace detail {
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsWindowSlow(JSObject* obj);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Returns true iff `obj` is a global object with an associated WindowProxy,
|
||||
* see SetWindowProxy.
|
||||
*/
|
||||
inline bool
|
||||
IsWindow(JSObject* obj)
|
||||
{
|
||||
if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL)
|
||||
return detail::IsWindowSlow(obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff `obj` has the WindowProxy Class (see SetWindowProxyClass).
|
||||
*/
|
||||
JS_FRIEND_API(bool)
|
||||
IsWindowProxy(JSObject* obj);
|
||||
|
||||
/**
|
||||
* If `obj` is a Window, get its associated WindowProxy (or a CCW if the
|
||||
* page was navigated away from), else return `obj`. This function is
|
||||
* infallible and never returns nullptr.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
ToWindowProxyIfWindow(JSObject* obj);
|
||||
|
||||
/**
|
||||
* If `obj` is a WindowProxy, get its associated Window (the compartment's
|
||||
* global), else return `obj`. This function is infallible and never returns
|
||||
* nullptr.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
ToWindowIfWindowProxy(JSObject* obj);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
|
@ -76,23 +76,6 @@ using mozilla::DebugOnly;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
JS_ObjectToInnerObject(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
if (!obj) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INACTIVE);
|
||||
return nullptr;
|
||||
}
|
||||
return GetInnerObject(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject*)
|
||||
JS_ObjectToOuterObject(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
assertSameCompartment(cx, obj);
|
||||
return GetOuterObject(cx, obj);
|
||||
}
|
||||
|
||||
void
|
||||
js::ReportNotObject(JSContext* cx, const Value& v)
|
||||
{
|
||||
@ -2484,14 +2467,14 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
|
||||
|
||||
/*
|
||||
* ES6 9.1.2 step 6 forbids generating cyclical prototype chains. But we
|
||||
* have to do this comparison on the observable outer objects, not on the
|
||||
* possibly-inner object we're setting the proto on.
|
||||
* have to do this comparison on the observable WindowProxy, not on the
|
||||
* possibly-Window object we're setting the proto on.
|
||||
*/
|
||||
RootedObject outerObj(cx, GetOuterObject(cx, obj));
|
||||
RootedObject objMaybeWindowProxy(cx, ToWindowProxyIfWindow(obj));
|
||||
RootedObject obj2(cx);
|
||||
for (obj2 = proto; obj2; ) {
|
||||
MOZ_ASSERT(GetOuterObject(cx, obj2) == obj2);
|
||||
if (obj2 == outerObj)
|
||||
MOZ_ASSERT(!IsWindow(obj2));
|
||||
if (obj2 == objMaybeWindowProxy)
|
||||
return result.fail(JSMSG_CANT_SET_PROTO_CYCLE);
|
||||
|
||||
if (!GetPrototype(cx, obj2, &obj2))
|
||||
@ -2767,7 +2750,7 @@ js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
||||
bool
|
||||
js::WatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id, JS::HandleObject callable)
|
||||
{
|
||||
RootedObject obj(cx, GetInnerObject(origObj));
|
||||
RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
|
||||
if (obj->isNative()) {
|
||||
// Use sparse indexes for watched objects, as dense elements can be
|
||||
// written to without checking the watchpoint map.
|
||||
@ -2796,7 +2779,7 @@ js::UnwatchGuts(JSContext* cx, JS::HandleObject origObj, JS::HandleId id)
|
||||
{
|
||||
// Looking in the map for an unsupported object will never hit, so we don't
|
||||
// need to check for nativeness or watchable-ness here.
|
||||
RootedObject obj(cx, GetInnerObject(origObj));
|
||||
RootedObject obj(cx, ToWindowIfWindowProxy(origObj));
|
||||
if (WatchpointMap* wpmap = cx->compartment()->watchpointMap)
|
||||
wpmap->unwatch(obj, id, nullptr, nullptr);
|
||||
return true;
|
||||
|
@ -1035,59 +1035,6 @@ ToPrimitive(JSContext* cx, JSType preferredType, MutableHandleValue vp)
|
||||
extern const char*
|
||||
GetObjectClassName(JSContext* cx, HandleObject obj);
|
||||
|
||||
/*
|
||||
* Inner and outer objects
|
||||
*
|
||||
* GetInnerObject and GetOuterObject (and also GetThisValue, somewhat) have to
|
||||
* do with Windows and WindowProxies. There's a screwy invariant that actual
|
||||
* Window objects (the global objects of web pages) are never directly exposed
|
||||
* to script. Instead we often substitute a WindowProxy.
|
||||
*
|
||||
* As a result, we have calls to these three "substitute-this-object-for-that-
|
||||
* object" functions sprinkled at apparently arbitrary (but actually *very*
|
||||
* carefully and nervously selected) places throughout the engine and indeed
|
||||
* the universe.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If obj is a WindowProxy, return its current inner Window. Otherwise return
|
||||
* obj. This function can't fail and never returns nullptr.
|
||||
*
|
||||
* GetInnerObject is called when we need a scope chain; you never want a
|
||||
* WindowProxy on a scope chain.
|
||||
*
|
||||
* It's also called in a few places where an object comes in from script, and
|
||||
* the user probably intends to operate on the Window, not the
|
||||
* WindowProxy. Object.prototype.watch and various Debugger features do
|
||||
* this. (Users can't simply pass the Window, because the Window isn't exposed
|
||||
* to scripts.)
|
||||
*/
|
||||
inline JSObject*
|
||||
GetInnerObject(JSObject* obj)
|
||||
{
|
||||
if (InnerObjectOp op = obj->getClass()->ext.innerObject) {
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
return op(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* If obj is a Window object, return the WindowProxy. Otherwise return obj.
|
||||
* This function can't fail; it never sets an exception or returns nullptr.
|
||||
*
|
||||
* This must be called before passing an object to script, if the object might
|
||||
* be a Window. (But usually those cases involve scope objects, and for those,
|
||||
* it is better to call GetThisValue instead.)
|
||||
*/
|
||||
inline JSObject*
|
||||
GetOuterObject(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
if (ObjectOp op = obj->getClass()->ext.outerObject)
|
||||
return op(cx, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an object that may be used as `this` in place of obj. For most
|
||||
* objects this just returns obj.
|
||||
|
@ -261,12 +261,10 @@ Proxy::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
|
||||
}
|
||||
|
||||
static Value
|
||||
OuterizeValue(JSContext* cx, HandleValue v)
|
||||
ValueToWindowProxyIfWindow(Value v)
|
||||
{
|
||||
if (v.isObject()) {
|
||||
RootedObject obj(cx, &v.toObject());
|
||||
return ObjectValue(*GetOuterObject(cx, obj));
|
||||
}
|
||||
if (v.isObject())
|
||||
return ObjectValue(*ToWindowProxyIfWindow(&v.toObject()));
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -281,9 +279,9 @@ Proxy::get(JSContext* cx, HandleObject proxy, HandleValue receiver_, HandleId id
|
||||
if (!policy.allowed())
|
||||
return policy.returnValue();
|
||||
|
||||
// Outerize the receiver. Proxy handlers shouldn't have to know about
|
||||
// the Window/WindowProxy distinction.
|
||||
RootedValue receiver(cx, OuterizeValue(cx, receiver_));
|
||||
// Use the WindowProxy as receiver if receiver_ is a Window. Proxy handlers
|
||||
// shouldn't have to know about the Window/WindowProxy distinction.
|
||||
RootedValue receiver(cx, ValueToWindowProxyIfWindow(receiver_));
|
||||
|
||||
if (handler->hasPrototype()) {
|
||||
bool own;
|
||||
@ -315,9 +313,9 @@ Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, Handle
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
// Outerize the receiver. Proxy handlers shouldn't have to know about
|
||||
// the Window/WindowProxy distinction.
|
||||
RootedValue receiver(cx, OuterizeValue(cx, receiver_));
|
||||
// Use the WindowProxy as receiver if receiver_ is a Window. Proxy handlers
|
||||
// shouldn't have to know about the Window/WindowProxy distinction.
|
||||
RootedValue receiver(cx, ValueToWindowProxyIfWindow(receiver_));
|
||||
|
||||
// Special case. See the comment on BaseProxyHandler::mHasPrototype.
|
||||
if (handler->hasPrototype())
|
||||
|
@ -2553,9 +2553,8 @@ EvalInContext(JSContext* cx, unsigned argc, Value* vp)
|
||||
ac.emplace(cx, sobj);
|
||||
}
|
||||
|
||||
sobj = GetInnerObject(sobj);
|
||||
if (!sobj)
|
||||
return false;
|
||||
sobj = ToWindowIfWindowProxy(sobj);
|
||||
|
||||
if (!(sobj->getClass()->flags & JSCLASS_IS_GLOBAL)) {
|
||||
JS_ReportError(cx, "Invalid scope argument to evalcx");
|
||||
return false;
|
||||
|
@ -3064,10 +3064,8 @@ Debugger::unwrapDebuggeeArgument(JSContext* cx, const Value& v)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* If that produced an outer window, innerize it. */
|
||||
obj = GetInnerObject(obj);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
/* If that produced a WindowProxy, get the Window (global). */
|
||||
obj = ToWindowIfWindowProxy(obj);
|
||||
|
||||
/* If that didn't produce a global object, it's an error. */
|
||||
if (!obj->is<GlobalObject>()) {
|
||||
@ -7696,8 +7694,8 @@ RequireGlobalObject(JSContext* cx, HandleValue dbgobj, HandleObject referent)
|
||||
}
|
||||
|
||||
/* ... and WindowProxies around Windows. */
|
||||
if (IsOuterObject(obj)) {
|
||||
obj = JS_ObjectToInnerObject(cx, obj);
|
||||
if (IsWindowProxy(obj)) {
|
||||
obj = ToWindowIfWindowProxy(obj);
|
||||
isWindowProxy = "a WindowProxy referring to ";
|
||||
}
|
||||
|
||||
@ -7799,8 +7797,8 @@ DebuggerObject_unsafeDereference(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!cx->compartment()->wrap(cx, args.rval()))
|
||||
return false;
|
||||
|
||||
// Wrapping should outerize inner objects.
|
||||
MOZ_ASSERT(!IsInnerObject(&args.rval().toObject()));
|
||||
// Wrapping should return the WindowProxy.
|
||||
MOZ_ASSERT(!IsWindow(&args.rval().toObject()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ class GlobalObject : public NativeObject
|
||||
INT32X4_TYPE_DESCR,
|
||||
FOR_OF_PIC_CHAIN,
|
||||
MODULE_RESOLVE_HOOK,
|
||||
WINDOW_PROXY,
|
||||
|
||||
/* Total reserved-slot count for global objects. */
|
||||
RESERVED_SLOTS
|
||||
@ -747,6 +748,18 @@ class GlobalObject : public NativeObject
|
||||
}
|
||||
static NativeObject* getOrCreateForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
|
||||
|
||||
JSObject* windowProxy() const {
|
||||
return &getReservedSlot(WINDOW_PROXY).toObject();
|
||||
}
|
||||
JSObject* maybeWindowProxy() const {
|
||||
Value v = getReservedSlot(WINDOW_PROXY);
|
||||
MOZ_ASSERT(v.isObject() || v.isUndefined());
|
||||
return v.isObject() ? &v.toObject() : nullptr;
|
||||
}
|
||||
void setWindowProxy(JSObject* windowProxy) {
|
||||
setReservedSlot(WINDOW_PROXY, ObjectValue(*windowProxy));
|
||||
}
|
||||
|
||||
void setModuleResolveHook(HandleFunction hook) {
|
||||
MOZ_ASSERT(hook);
|
||||
setSlot(MODULE_RESOLVE_HOOK, ObjectValue(*hook));
|
||||
|
@ -570,11 +570,7 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg, c
|
||||
MOZ_ASSERT_IF(type == EXECUTE_GLOBAL, IsGlobalLexicalScope(&scopeChainArg) ||
|
||||
!IsSyntacticScope(&scopeChainArg));
|
||||
#ifdef DEBUG
|
||||
if (thisv.isObject()) {
|
||||
RootedObject thisObj(cx, &thisv.toObject());
|
||||
AutoSuppressGC nogc(cx);
|
||||
MOZ_ASSERT(GetOuterObject(cx, thisObj) == thisObj);
|
||||
}
|
||||
MOZ_ASSERT_IF(thisv.isObject(), !IsWindow(&thisv.toObject()));
|
||||
RootedObject terminatingScope(cx, &scopeChainArg);
|
||||
while (IsSyntacticScope(terminatingScope))
|
||||
terminatingScope = terminatingScope->enclosingScope();
|
||||
@ -613,7 +609,7 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
|
||||
/* The scope chain is something we control, so we know it can't
|
||||
have any outer objects on it. */
|
||||
RootedObject scopeChain(cx, &scopeChainArg);
|
||||
MOZ_ASSERT(scopeChain == GetInnerObject(scopeChain));
|
||||
MOZ_ASSERT(!IsWindowProxy(scopeChain));
|
||||
|
||||
if (script->module()) {
|
||||
MOZ_RELEASE_ASSERT(scopeChain == script->module()->environment(),
|
||||
|
@ -226,6 +226,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
ionPcScriptCache(nullptr),
|
||||
scriptEnvironmentPreparer(nullptr),
|
||||
ctypesActivityCallback(nullptr),
|
||||
windowProxyClass_(nullptr),
|
||||
offthreadIonCompilationEnabled_(true),
|
||||
parallelParsingEnabled_(true),
|
||||
autoWritableJitCodeActive_(false),
|
||||
|
@ -1399,6 +1399,7 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
|
||||
private:
|
||||
JS::RuntimeOptions options_;
|
||||
const js::Class* windowProxyClass_;
|
||||
|
||||
// Settings for how helper threads can be used.
|
||||
bool offthreadIonCompilationEnabled_;
|
||||
@ -1436,6 +1437,13 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
return options_;
|
||||
}
|
||||
|
||||
const js::Class* maybeWindowProxyClass() const {
|
||||
return windowProxyClass_;
|
||||
}
|
||||
void setWindowProxyClass(const js::Class* clasp) {
|
||||
windowProxyClass_ = clasp;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
public:
|
||||
js::AutoEnterPolicy* enteredPolicy;
|
||||
|
@ -3461,6 +3461,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
js::SetScriptEnvironmentPreparer(runtime, &mEnvironmentPreparer);
|
||||
js::SetActivityCallback(runtime, ActivityCallback, this);
|
||||
JS_SetInterruptCallback(runtime, InterruptCallback);
|
||||
js::SetWindowProxyClass(runtime, &OuterWindowProxyClass);
|
||||
|
||||
// The JS engine needs to keep the source code around in order to implement
|
||||
// Function.prototype.toSource(). It'd be nice to not have to do this for
|
||||
|
@ -42,8 +42,7 @@ XPCVariant::XPCVariant(JSContext* cx, Value aJSVal)
|
||||
// thing, but I'm saving the cleanup here for another day. Blake thinks
|
||||
// that we should just not store the WN if we're creating a variant for
|
||||
// an outer window.
|
||||
JS::RootedObject obj(cx, &mJSVal.toObject());
|
||||
obj = JS_ObjectToInnerObject(cx, obj);
|
||||
JSObject* obj = js::ToWindowIfWindowProxy(&mJSVal.toObject());
|
||||
mJSVal = JS::ObjectValue(*obj);
|
||||
|
||||
JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
|
@ -98,7 +98,7 @@ WrapperFactory::WaiveXray(JSContext* cx, JSObject* objArg)
|
||||
{
|
||||
RootedObject obj(cx, objArg);
|
||||
obj = UncheckedUnwrap(obj);
|
||||
MOZ_ASSERT(!js::IsInnerObject(obj));
|
||||
MOZ_ASSERT(!js::IsWindow(obj));
|
||||
|
||||
JSObject* waiver = GetXrayWaiver(obj);
|
||||
if (waiver)
|
||||
@ -155,20 +155,20 @@ WrapperFactory::PrepareForWrapping(JSContext* cx, HandleObject scope,
|
||||
RootedObject obj(cx, objArg);
|
||||
// Outerize any raw inner objects at the entry point here, so that we don't
|
||||
// have to worry about them for the rest of the wrapping code.
|
||||
if (js::IsInnerObject(obj)) {
|
||||
if (js::IsWindow(obj)) {
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
obj = JS_ObjectToOuterObject(cx, obj);
|
||||
NS_ENSURE_TRUE(obj, nullptr);
|
||||
// The outerization hook wraps, which means that we can end up with a
|
||||
// CCW here if |obj| was a navigated-away-from inner. Strip any CCWs.
|
||||
obj = js::ToWindowProxyIfWindow(obj);
|
||||
MOZ_ASSERT(obj);
|
||||
// ToWindowProxyIfWindow can return a CCW if |obj| was a
|
||||
// navigated-away-from Window. Strip any CCWs.
|
||||
obj = js::UncheckedUnwrap(obj);
|
||||
MOZ_ASSERT(js::IsOuterObject(obj));
|
||||
MOZ_ASSERT(js::IsWindowProxy(obj));
|
||||
}
|
||||
|
||||
// If we've got an outer window, there's nothing special that needs to be
|
||||
// If we've got a WindowProxy, there's nothing special that needs to be
|
||||
// done here, and we can move on to the next phase of wrapping. We handle
|
||||
// this case first to allow us to assert against wrappers below.
|
||||
if (js::IsOuterObject(obj))
|
||||
if (js::IsWindowProxy(obj))
|
||||
return waive ? WaiveXray(cx, obj) : obj;
|
||||
|
||||
// Here are the rules for wrapping:
|
||||
@ -400,7 +400,7 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
||||
js::GetObjectClass(obj)->ext.innerObject,
|
||||
"wrapped object passed to rewrap");
|
||||
MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
|
||||
MOZ_ASSERT(!js::IsInnerObject(obj));
|
||||
MOZ_ASSERT(!js::IsWindow(obj));
|
||||
// We sometimes end up here after nsContentUtils has been shut down but before
|
||||
// XPConnect has been shut down, so check the context stack the roundabout way.
|
||||
MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == cx);
|
||||
@ -542,7 +542,7 @@ WrapperFactory::WaiveXrayAndWrap(JSContext* cx, MutableHandleObject argObj)
|
||||
{
|
||||
MOZ_ASSERT(argObj);
|
||||
RootedObject obj(cx, js::UncheckedUnwrap(argObj));
|
||||
MOZ_ASSERT(!js::IsInnerObject(obj));
|
||||
MOZ_ASSERT(!js::IsWindow(obj));
|
||||
if (js::IsObjectInContextCompartment(obj, cx)) {
|
||||
argObj.set(obj);
|
||||
return true;
|
||||
|
@ -970,9 +970,9 @@ CycleCollectedJSRuntime::UsefulToMergeZones() const
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(js::IsOuterObject(obj));
|
||||
// Grab the inner from the outer.
|
||||
obj = JS_ObjectToInnerObject(cx, obj);
|
||||
MOZ_ASSERT(js::IsWindowProxy(obj));
|
||||
// Grab the global from the WindowProxy.
|
||||
obj = js::ToWindowIfWindowProxy(obj);
|
||||
MOZ_ASSERT(JS_IsGlobalObject(obj));
|
||||
if (JS::ObjectIsMarkedGray(obj) &&
|
||||
!js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
|
||||
|
Loading…
Reference in New Issue
Block a user