зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170760 part 4. Change Promise::Constructor to run in the Xray compartment when new Promise happens over Xrays. r=peterv
This commit is contained in:
Родитель
c1ba24a868
Коммит
56a0511eb4
|
@ -7057,13 +7057,44 @@ class CGPerSignatureCall(CGThing):
|
||||||
needsUnwrap = False
|
needsUnwrap = False
|
||||||
argsPost = []
|
argsPost = []
|
||||||
if isConstructor:
|
if isConstructor:
|
||||||
needsUnwrap = True
|
|
||||||
needsUnwrappedVar = False
|
|
||||||
unwrappedVar = "obj"
|
|
||||||
if descriptor.name == "Promise" or descriptor.name == "MozAbortablePromise":
|
if descriptor.name == "Promise" or descriptor.name == "MozAbortablePromise":
|
||||||
# Hack for Promise for now: pass in our desired proto so the
|
# Hack for Promise for now: pass in our desired proto so the
|
||||||
# implementation can create the reflector with the right proto.
|
# implementation can create the reflector with the right proto.
|
||||||
argsPost.append("desiredProto")
|
argsPost.append("desiredProto")
|
||||||
|
# Also, we do not want to enter the content compartment when the
|
||||||
|
# Promise constructor is called via Xrays, because we want to
|
||||||
|
# create our callback functions that we will hand to our caller
|
||||||
|
# in the Xray compartment. The reason we want to do that is the
|
||||||
|
# following situation, over Xrays:
|
||||||
|
#
|
||||||
|
# contentWindow.Promise.race([Promise.resolve(5)])
|
||||||
|
#
|
||||||
|
# Ideally this would work. Internally, race() does a
|
||||||
|
# contentWindow.Promise.resolve() on everything in the array.
|
||||||
|
# Per spec, to support subclassing,
|
||||||
|
# contentWindow.Promise.resolve has to do:
|
||||||
|
#
|
||||||
|
# var resolve, reject;
|
||||||
|
# var p = new contentWindow.Promise(function(a, b) {
|
||||||
|
# resolve = a;
|
||||||
|
# reject = b;
|
||||||
|
# });
|
||||||
|
# resolve(arg);
|
||||||
|
# return p;
|
||||||
|
#
|
||||||
|
# where "arg" is, in this case, the chrome-side return value of
|
||||||
|
# Promise.resolve(5). But if the "resolve" function in that
|
||||||
|
# case were created in the content compartment, then calling it
|
||||||
|
# would wrap "arg" in an opaque wrapper, and that function tries
|
||||||
|
# to get .then off the argument, which would throw. So we need
|
||||||
|
# to create the "resolve" function in the chrome compartment,
|
||||||
|
# and hence want to be running the entire Promise constructor
|
||||||
|
# (which creates that function) in the chrome compartment in
|
||||||
|
# this case. So don't set needsUnwrap here.
|
||||||
|
else:
|
||||||
|
needsUnwrap = True
|
||||||
|
needsUnwrappedVar = False
|
||||||
|
unwrappedVar = "obj"
|
||||||
elif descriptor.interface.isJSImplemented():
|
elif descriptor.interface.isJSImplemented():
|
||||||
if not idlNode.isStatic():
|
if not idlNode.isStatic():
|
||||||
needsUnwrap = True
|
needsUnwrap = True
|
||||||
|
|
|
@ -124,12 +124,11 @@ TestInterfaceJS.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
testPromiseWithThrowingChromeThenable: function() {
|
testPromiseWithThrowingChromeThenable: function() {
|
||||||
// We need to produce a thing that has a "then" property in the page
|
var thenable = {
|
||||||
// compartment, since we plan to call the page-provided resolve function.
|
then: function() {
|
||||||
var thenable = new this._win.Object();
|
|
||||||
Cu.waiveXrays(thenable).then = function() {
|
|
||||||
noSuchMethodExistsYo3()
|
noSuchMethodExistsYo3()
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return new this._win.Promise(function(resolve) {
|
return new this._win.Promise(function(resolve) {
|
||||||
resolve(thenable)
|
resolve(thenable)
|
||||||
});
|
});
|
||||||
|
@ -144,13 +143,12 @@ TestInterfaceJS.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
testPromiseWithDOMExceptionThrowingThenable: function() {
|
testPromiseWithDOMExceptionThrowingThenable: function() {
|
||||||
// We need to produce a thing that has a "then" property in the page
|
var thenable = {
|
||||||
// compartment, since we plan to call the page-provided resolve function.
|
then: () => {
|
||||||
var thenable = new this._win.Object();
|
|
||||||
Cu.waiveXrays(thenable).then = () => {
|
|
||||||
throw new this._win.DOMException("We are a fourth DOMException",
|
throw new this._win.DOMException("We are a fourth DOMException",
|
||||||
"TypeMismatchError");
|
"TypeMismatchError");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return new this._win.Promise(function(resolve) {
|
return new this._win.Promise(function(resolve) {
|
||||||
resolve(thenable)
|
resolve(thenable)
|
||||||
});
|
});
|
||||||
|
|
|
@ -798,17 +798,22 @@ Promise::CallInitFunction(const GlobalObject& aGlobal,
|
||||||
aRv.WouldReportJSException();
|
aRv.WouldReportJSException();
|
||||||
|
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
// We want the same behavior as this JS implementation:
|
// There are two possibilities here. Either we've got a rethrown exception,
|
||||||
|
// or we reported that already and synthesized a generic NS_ERROR_FAILURE on
|
||||||
|
// the ErrorResult. In the former case, it doesn't much matter how we get
|
||||||
|
// the exception JS::Value from the ErrorResult to us, since we'll just end
|
||||||
|
// up wrapping it into the right compartment as needed if we hand it to
|
||||||
|
// someone. But in the latter case we have to ensure that the new exception
|
||||||
|
// object we create is created in our reflector compartment, not in our
|
||||||
|
// current compartment, because in the case when we're a Promise constructor
|
||||||
|
// called over Xrays creating it in the current compartment would mean
|
||||||
|
// rejecting with a value that can't be accessed by code that can call
|
||||||
|
// then() on this Promise.
|
||||||
//
|
//
|
||||||
// function Promise(arg) { try { arg(a, b); } catch (e) { this.reject(e); }}
|
// Luckily, MaybeReject(aRv) does exactly what we want here: it enters our
|
||||||
//
|
// reflector compartment before trying to produce a JS::Value from the
|
||||||
// In particular, that means not using MaybeReject(aRv) here, since that
|
// ErrorResult.
|
||||||
// would create the exception object in our reflector compartment, while we
|
MaybeReject(aRv);
|
||||||
// want to create it in whatever the current compartment on cx is.
|
|
||||||
JS::Rooted<JS::Value> value(cx);
|
|
||||||
DebugOnly<bool> conversionResult = ToJSValue(cx, aRv, &value);
|
|
||||||
MOZ_ASSERT(conversionResult);
|
|
||||||
MaybeRejectInternal(cx, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче