Fix for bug 741267 (UserScript's XMLHttpRequest is undefined in 20120401 nightly).

Pass two objects when creating a DOM interface object, the global used to cache
the DOM interface objects and a receiver object on which the named property is
that points to the DOM interface object.

--HG--
extra : rebase_source : b462393e7376fdb68f3b279ccd08b3ab25ac154a
This commit is contained in:
Peter Van der Beken 2012-04-23 16:10:56 +02:00
parent f4589dfc73
commit 1780bb4050
12 changed files with 157 additions and 67 deletions

View File

@ -801,7 +801,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
Argument('JSObject*', 'aReceiver')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args)
self.properties = properties
def definition_body(self):
@ -810,7 +811,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
else:
parentProtoName = self.descriptor.prototypeChain[-2]
getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
getParentProto = "%s::GetProtoObject(aCx, aGlobal, aReceiver)" % (parentProtoName)
needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
@ -849,7 +850,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
" return NULL;\n"
"}") % getParentProto
call = CGGeneric(("return bindings::CreateInterfaceObjects(aCx, aGlobal, parentProto,\n"
call = CGGeneric(("return bindings::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
" %s, %s,\n"
" %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
" %s);") % (
@ -880,12 +881,20 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
constructor object).
"""
def __init__(self, descriptor, name, idPrefix=""):
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
Argument('JSObject*', 'aReceiver')]
CGAbstractMethod.__init__(self, descriptor, name,
'JSObject*', args, inline=True)
self.id = idPrefix + "id::" + self.descriptor.name
def definition_body(self):
return """
/* aGlobal and aReceiver are usually the same, but they can be different
too. For example a sandbox often has an xray wrapper for a window as the
prototype of the sandbox's global. In that case aReceiver is the xray
wrapper and aGlobal is the sandbox's global.
*/
/* Make sure our global is sane. Hopefully we can remove this sometime */
if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
return NULL;
@ -894,7 +903,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal);
JSObject* cachedObject = protoOrIfaceArray[%s];
if (!cachedObject) {
protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal);
protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
}
/* cachedObject might _still_ be null, but that's OK */
@ -905,7 +914,6 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
A method for getting the interface prototype object.
"""
def __init__(self, descriptor):
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject")
def definition_body(self):
return """
@ -917,14 +925,13 @@ class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
A method for getting the interface constructor object.
"""
def __init__(self, descriptor):
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject", "constructors::")
def definition_body(self):
return """
/* Get the interface object for this class. This will create the object as
needed. */""" + CGGetPerInterfaceObject.definition_body(self)
def CheckPref(descriptor, scopeName, varName, retval, wrapperCache = None):
def CheckPref(descriptor, globalName, varName, retval, wrapperCache = None):
"""
Check whether bindings should be enabled for this descriptor. If not, set
varName to false and return retval.
@ -936,11 +943,19 @@ def CheckPref(descriptor, scopeName, varName, retval, wrapperCache = None):
else:
wrapperCache = ""
return """
if (!%s->ExperimentalBindingsEnabled()) {
{
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s);
if (!scope) {
return %s;
}
if (!scope->ExperimentalBindingsEnabled()) {
%s %s = false;
return %s;
}
""" % (scopeName, wrapperCache, varName, retval)
}
""" % (globalName, retval, wrapperCache, varName, retval)
class CGDefineDOMInterfaceMethod(CGAbstractMethod):
"""
@ -948,7 +963,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
a given interface.
"""
def __init__(self, descriptor):
args = [Argument('JSContext*', 'aCx'), Argument('XPCWrappedNativeScope*', 'aScope'),
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aReceiver'),
Argument('bool*', 'aEnabled')]
CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)
@ -970,9 +985,11 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
else:
getter = "GetConstructorObject"
return CheckPref(self.descriptor, "aScope", "*aEnabled", "false") + """
return (" JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
CheckPref(self.descriptor, "global", "*aEnabled", "false") +
"""
*aEnabled = true;
return !!%s(aCx, aScope->GetGlobalJSObject());""" % (getter)
return !!%s(aCx, global, aReceiver);""" % (getter))
class CGNativeToSupportsMethod(CGAbstractStaticMethod):
"""
@ -1022,13 +1039,9 @@ class CGWrapMethod(CGAbstractMethod):
}
}
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::FindInJSObjectScope(aCx, parent);
if (!scope) {
return NULL;
}
JSObject* global = JS_GetGlobalForObject(aCx, parent);
%s
JSObject* proto = GetProtoObject(aCx, scope->GetGlobalJSObject());
JSObject* proto = GetProtoObject(aCx, global, global);
if (!proto) {
return NULL;
}
@ -1043,7 +1056,7 @@ class CGWrapMethod(CGAbstractMethod):
aObject->SetWrapper(obj);
return obj;""" % (CheckPref(self.descriptor, "scope", "*aTriedToWrap", "NULL", "aObject"))
return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aObject"))
builtinNames = {
IDLType.Tags.bool: 'bool',

View File

@ -25,7 +25,7 @@ DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
}
static JSObject*
CreateInterfaceObject(JSContext* cx, JSObject* global,
CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
JSClass* constructorClass, JSObject* proto,
JSFunctionSpec* staticMethods, ConstantSpec* constants,
const char* name)
@ -54,7 +54,7 @@ CreateInterfaceObject(JSContext* cx, JSObject* global,
}
// This is Enumerable: False per spec.
if (!JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor), NULL,
if (!JS_DefineProperty(cx, receiver, name, OBJECT_TO_JSVAL(constructor), NULL,
NULL, 0)) {
return NULL;
}
@ -91,11 +91,11 @@ CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
}
JSObject*
CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,
JSClass *protoClass, JSClass *constructorClass,
JSFunctionSpec *methods, JSPropertySpec *properties,
ConstantSpec *constants, JSFunctionSpec *staticMethods,
const char* name)
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
JSObject* protoProto, JSClass* protoClass,
JSClass* constructorClass, JSFunctionSpec* methods,
JSPropertySpec* properties, ConstantSpec* constants,
JSFunctionSpec* staticMethods, const char* name)
{
MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
MOZ_ASSERT(!(methods || properties) || protoClass,
@ -107,7 +107,7 @@ CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,
JSObject* proto;
if (protoClass) {
proto = CreateInterfacePrototypeObject(cx, global, parentProto, protoClass,
proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
methods, properties, constants);
if (!proto) {
return NULL;
@ -119,8 +119,8 @@ CreateInterfaceObjects(JSContext *cx, JSObject *global, JSObject *parentProto,
JSObject* interface;
if (constructorClass) {
interface = CreateInterfaceObject(cx, global, constructorClass, proto,
staticMethods, constants, name);
interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
proto, staticMethods, constants, name);
if (!interface) {
return NULL;
}

View File

@ -219,7 +219,11 @@ struct ConstantSpec
* Create a DOM interface object (if constructorClass is non-null) and/or a
* DOM interface prototype object (if protoClass is non-null).
*
* parentProto is the prototype to use for the interface prototype object.
* global is used as the parent of the interface object and the interface
* prototype object
* receiver is the object on which we need to define the interface object as a
* property
* protoProto is the prototype to use for the interface prototype object.
* protoClass is the JSClass to use for the interface prototype object.
* This is null if we should not create an interface prototype
* object.
@ -242,11 +246,11 @@ struct ConstantSpec
* returns the interface object.
*/
JSObject*
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* parentProto,
JSClass* protoClass, JSClass* constructorClass,
JSFunctionSpec* methods, JSPropertySpec* properties,
ConstantSpec* constants, JSFunctionSpec* staticMethods,
const char* name);
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
JSObject* protoProto, JSClass* protoClass,
JSClass* constructorClass, JSFunctionSpec* methods,
JSPropertySpec* properties, ConstantSpec* constants,
JSFunctionSpec* staticMethods, const char* name);
template <class T>
inline bool

View File

@ -78,6 +78,7 @@ _TEST_FILES = \
test_callback_wrapping.xul \
window_callback_wrapping.xul \
test_sandbox_postMessage.html \
test_sandbox_bindings.xul \
$(NULL)
ifeq (WINNT,$(OS_ARCH))

View File

@ -0,0 +1,52 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=741267
-->
<window title="Mozilla Bug 741267"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<iframe id="t"></iframe>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741267"
target="_blank">Mozilla Bug 741267</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 741267 **/
function doTest() {
var win = $("t").contentWindow;
var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
try {
var nl = Components.utils.evalInSandbox("NodeList", sandbox);
is(nl, "[object NodeList]", "'NodeList' in a sandbox should return the NodeList interface prototype object");
} catch (e) {
ok(false, "'NodeList' shouldn't throw in a sandbox");
}
try {
var et = Components.utils.evalInSandbox("EventTarget", sandbox);
ok(et, "'EventTarget' in a sandbox should return the EventTarget interface prototype object");
} catch (e) {
ok(false, "'EventTarget' shouldn't throw in a sandbox");
}
try {
var xhr = Components.utils.evalInSandbox("XMLHttpRequest()", sandbox);
is(xhr, "[object XMLHttpRequest]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object");
} catch (e) {
ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox");
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
]]>
</script>
</window>

View File

@ -37,7 +37,7 @@ struct WrapPrototypeTraits
GetProtoObject(JSContext* aCx, JSObject* aGlobal) \
{ \
using namespace mozilla::dom::bindings::prototypes; \
return _class##_workers::GetProtoObject(aCx, aGlobal); \
return _class##_workers::GetProtoObject(aCx, aGlobal, aGlobal); \
} \
};

View File

@ -449,7 +449,7 @@ ResolveWorkerClasses(JSContext* aCx, JSObject* aObj, jsid aId, unsigned aFlags,
return true;
}
JSObject* eventTarget = EventTarget_workers::GetProtoObject(aCx, aObj);
JSObject* eventTarget = EventTarget_workers::GetProtoObject(aCx, aObj, aObj);
if (!eventTarget) {
return false;
}

View File

@ -958,7 +958,8 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
// -> EventTarget
// -> Object
JSObject* eventTargetProto = EventTarget_workers::GetProtoObject(aCx, global);
JSObject* eventTargetProto =
EventTarget_workers::GetProtoObject(aCx, global, global);
if (!eventTargetProto) {
return NULL;
}
@ -1003,8 +1004,9 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
}
// Init other paris-bindings.
if (!XMLHttpRequest_workers::CreateInterfaceObjects(aCx, global) ||
!XMLHttpRequestUpload_workers::CreateInterfaceObjects(aCx, global)) {
if (!XMLHttpRequest_workers::CreateInterfaceObjects(aCx, global, global) ||
!XMLHttpRequestUpload_workers::CreateInterfaceObjects(aCx, global,
global)) {
return NULL;
}

View File

@ -208,7 +208,7 @@ bool
DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine, nsresult *aResult)
{
bool enabled;
bool defined = aDefine(cx, XPCWrappedNativeScope::FindInJSObjectScope(cx, obj), &enabled);
bool defined = aDefine(cx, obj, &enabled);
NS_ASSERTION(!defined || enabled,
"We defined a constructor but the new bindings are disabled?");
*aResult = defined ? NS_OK : NS_ERROR_FAILURE;
@ -414,7 +414,22 @@ InvalidateProtoShape_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, j
template<class LC>
JSObject *
ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
ListBase<LC>::getPrototype(JSContext *cx, JSObject *receiver, bool *enabled)
{
*enabled = true;
XPCWrappedNativeScope *scope =
XPCWrappedNativeScope::FindInJSObjectScope(cx, receiver);
if (!scope)
return false;
return getPrototype(cx, scope, receiver);
}
template<class LC>
JSObject *
ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope,
JSObject *receiver)
{
nsDataHashtable<nsDepCharHashKey, JSObject*> &cache =
scope->GetCachedDOMPrototypes();
@ -429,7 +444,7 @@ ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
return NULL;
}
JSObject* proto = Base::getPrototype(cx, scope);
JSObject* proto = Base::getPrototype(cx, scope, receiver);
if (!proto)
return NULL;
@ -468,7 +483,7 @@ ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
if (!JS_LinkConstructorAndPrototype(cx, interface, interfacePrototype))
return NULL;
if (!JS_DefineProperty(cx, global, sInterfaceClass.name, OBJECT_TO_JSVAL(interface), NULL,
if (!JS_DefineProperty(cx, receiver, sInterfaceClass.name, OBJECT_TO_JSVAL(interface), NULL,
NULL, 0))
return NULL;
@ -493,15 +508,15 @@ ListBase<LC>::create(JSContext *cx, JSObject *scope, ListType *aList,
if (!parent)
return NULL;
JSObject *global = js::GetGlobalForObjectCrossCompartment(parent);
JSAutoEnterCompartment ac;
if (js::GetGlobalForObjectCrossCompartment(parent) != scope) {
if (!ac.enter(cx, parent))
if (global != scope) {
if (!ac.enter(cx, global))
return NULL;
}
XPCWrappedNativeScope *xpcscope =
XPCWrappedNativeScope::FindInJSObjectScope(cx, parent);
JSObject *proto = getPrototype(cx, xpcscope, triedToWrap);
JSObject *proto = getPrototype(cx, global, triedToWrap);
if (!proto && !*triedToWrap)
aWrapperCache->ClearIsDOMBinding();
if (!proto)
@ -1244,12 +1259,12 @@ ListBase<LC>::finalize(JSFreeOp *fop, JSObject *proxy)
JSObject*
NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, JSObject *receiver)
{
// We need to pass the object prototype to JS_NewObject. If we pass NULL then the JS engine
// will look up a prototype on the global by using the class' name and we'll recurse into
// getPrototype.
return JS_GetObjectPrototype(cx, scope->GetGlobalJSObject());
return JS_GetObjectPrototype(cx, receiver);
}

View File

@ -108,7 +108,8 @@ public:
class NoBase {
public:
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope);
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope,
JSObject *receiver);
static bool shouldCacheProtoShape(JSContext *cx, JSObject *proto, bool *shouldCache)
{
*shouldCache = true;
@ -194,14 +195,10 @@ public:
static JSObject *create(JSContext *cx, JSObject *scope, ListType *list,
nsWrapperCache* cache, bool *triedToWrap);
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)
static JSObject *getPrototype(JSContext *cx, JSObject *receiver, bool *enabled);
static bool DefineDOMInterface(JSContext *cx, JSObject *receiver, bool *enabled)
{
*enabled = true;
return getPrototype(cx, scope);
}
static bool DefineDOMInterface(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)
{
return !!getPrototype(cx, scope, enabled);
return !!getPrototype(cx, receiver, enabled);
}
bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
@ -243,7 +240,8 @@ public:
}
static inline ListType *getListObject(JSObject *obj);
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope);
static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope,
JSObject *receiver);
static inline bool protoIsClean(JSContext *cx, JSObject *proto, bool *isClean);
static bool shouldCacheProtoShape(JSContext *cx, JSObject *proto, bool *shouldCache);
static bool resolveNativeName(JSContext *cx, JSObject *proxy, jsid id,

View File

@ -497,15 +497,20 @@ derivedClassTemplate = (
prefableClassTemplate = (
"template<>\n"
"JSObject *\n"
"${name}Wrapper::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled)\n"
"${name}Wrapper::getPrototype(JSContext *cx, JSObject *receiver, bool *enabled)\n"
"{\n"
" XPCWrappedNativeScope *scope =\n"
" XPCWrappedNativeScope::FindInJSObjectScope(cx, receiver);\n"
" if (!scope)\n"
" return false;\n"
"\n"
" if (!scope->NewDOMBindingsEnabled()) {\n"
" *enabled = false;\n"
" return NULL;\n"
" }\n"
"\n"
" *enabled = true;\n"
" return getPrototype(cx, scope);\n"
" return getPrototype(cx, scope, receiver);\n"
"}\n"
"\n")

View File

@ -315,7 +315,7 @@ inline bool instanceIsProxy(JSObject *obj)
}
typedef bool
(*DefineInterface)(JSContext *cx, XPCWrappedNativeScope *scope, bool *enabled);
(*DefineInterface)(JSContext *cx, JSObject *global, bool *enabled);
extern bool
DefineStaticJSVals(JSContext *cx);