Bug 883683 - Leak with DOM promises. r=bz

This commit is contained in:
Andrea Marchesini 2013-06-26 09:44:21 -04:00
parent 7f4d63c6b8
commit 12938be54b
4 changed files with 75 additions and 15 deletions

View File

@ -108,6 +108,17 @@ Future::PrefEnabled()
return Preferences::GetBool("dom.future.enabled", false); return Preferences::GetBool("dom.future.enabled", false);
} }
static void
EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue)
{
// FIXME Bug 878849
if (aValue.WasPassed() && aValue.Value().isObject()) {
JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
aAc.construct(aCx, rooted);
}
}
/* static */ already_AddRefed<Future> /* static */ already_AddRefed<Future>
Future::Constructor(const GlobalObject& aGlobal, JSContext* aCx, Future::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
FutureInit& aInit, ErrorResult& aRv) FutureInit& aInit, ErrorResult& aRv)
@ -129,6 +140,9 @@ Future::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
if (aRv.IsJSException()) { if (aRv.IsJSException()) {
Optional<JS::Handle<JS::Value> > value(aCx); Optional<JS::Handle<JS::Value> > value(aCx);
aRv.StealJSException(aCx, &value.Value()); aRv.StealJSException(aCx, &value.Value());
Maybe<JSAutoCompartment> ac;
EnterCompartment(ac, aCx, value);
future->mResolver->Reject(aCx, value); future->mResolver->Reject(aCx, value);
} }

View File

@ -34,6 +34,17 @@ FutureCallback::~FutureCallback()
MOZ_COUNT_DTOR(FutureCallback); MOZ_COUNT_DTOR(FutureCallback);
} }
static void
EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue)
{
// FIXME Bug 878849
if (aValue.WasPassed() && aValue.Value().isObject()) {
JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
aAc.construct(aCx, rooted);
}
}
// ResolveFutureCallback // ResolveFutureCallback
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ResolveFutureCallback, NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ResolveFutureCallback,
@ -63,12 +74,8 @@ ResolveFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{ {
// Run resolver's algorithm with value and the synchronous flag set. // Run resolver's algorithm with value and the synchronous flag set.
AutoJSContext cx; AutoJSContext cx;
// FIXME Bug 878849
Maybe<JSAutoCompartment> ac; Maybe<JSAutoCompartment> ac;
if (aValue.WasPassed() && aValue.Value().isObject()) { EnterCompartment(ac, cx, aValue);
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
ac.construct(cx, rooted);
}
mResolver->ResolveInternal(cx, aValue, FutureResolver::SyncTask); mResolver->ResolveInternal(cx, aValue, FutureResolver::SyncTask);
} }
@ -102,12 +109,8 @@ RejectFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{ {
// Run resolver's algorithm with value and the synchronous flag set. // Run resolver's algorithm with value and the synchronous flag set.
AutoJSContext cx; AutoJSContext cx;
// FIXME Bug 878849
Maybe<JSAutoCompartment> ac; Maybe<JSAutoCompartment> ac;
if (aValue.WasPassed() && aValue.Value().isObject()) { EnterCompartment(ac, cx, aValue);
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
ac.construct(cx, rooted);
}
mResolver->RejectInternal(cx, aValue, FutureResolver::SyncTask); mResolver->RejectInternal(cx, aValue, FutureResolver::SyncTask);
} }
@ -142,12 +145,8 @@ void
WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue) WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{ {
AutoJSContext cx; AutoJSContext cx;
// FIXME Bug 878849
Maybe<JSAutoCompartment> ac; Maybe<JSAutoCompartment> ac;
if (aValue.WasPassed() && aValue.Value().isObject()) { EnterCompartment(ac, cx, aValue);
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
ac.construct(cx, rooted);
}
ErrorResult rv; ErrorResult rv;
@ -162,12 +161,17 @@ WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
if (rv.Failed() && rv.IsJSException()) { if (rv.Failed() && rv.IsJSException()) {
Optional<JS::Handle<JS::Value> > value(cx); Optional<JS::Handle<JS::Value> > value(cx);
rv.StealJSException(cx, &value.Value()); rv.StealJSException(cx, &value.Value());
Maybe<JSAutoCompartment> ac2;
EnterCompartment(ac2, cx, value);
mNextResolver->RejectInternal(cx, value, FutureResolver::SyncTask); mNextResolver->RejectInternal(cx, value, FutureResolver::SyncTask);
return; return;
} }
// Otherwise, run resolver's resolve with value and the synchronous flag // Otherwise, run resolver's resolve with value and the synchronous flag
// set. // set.
Maybe<JSAutoCompartment> ac2;
EnterCompartment(ac2, cx, value);
mNextResolver->ResolveInternal(cx, value, FutureResolver::SyncTask); mNextResolver->ResolveInternal(cx, value, FutureResolver::SyncTask);
} }

View File

@ -14,6 +14,7 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \ MOCHITEST_FILES = \
test_future.html \ test_future.html \
test_resolve.html \ test_resolve.html \
test_bug883683.html \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,41 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Future - bug 883683</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript"><!--
function runTest() {
[{}, {}, {}, {}, {}].reduce(Future.reject);
ok(true, "No leaks with reject?");
[{}, {}, {}, {}, {}].reduce(Future.resolve);
ok(true, "No leaks with resolve?");
[{}, {}, {}, {}, {}].reduce(function(a, b, c, d) { return new Future(function(r) { throw a; }); });
ok(true, "No leaks with exception?");
[{}, {}, {}, {}, {}].reduce(function(a, b, c, d) { return new Future(function(r) { }); });
ok(true, "No leaks with empty future?");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.future.enabled", true]]}, runTest);
// -->
</script>
</pre>
</body>
</html>