After a huge leap with QI, the outparam rewrite seems to be put on hold
pending exception and GC rewrites. This is a bit unfortunate, because
there was a word that outparamless QI alone provides 5% performance
boost. It also greatly improves code readability.
IIUC, the main reason for outparams introduction was leak prevention. In
the example below, GetC is not allow to return fooIC* because clients
may (and will) leak it, if the returned value is AddRefed, or the return
value may go away before is reaches nsCOMPtr<>, if it is not AddRefed.
--------
nsresult
fooD::GetB(fooIB **aB)
{
if (!mB)
return NS_ERROR_FAILURE;
NS_IF_ADDREF(*aB = mB);
return NS_OK;
}
nsresult
fooB::GetC(fooIC **aC)
{
NS_IF_ADDREF(*aC = mC);
return NS_OK;
}
nsresult
fooA::GetC(fooIC **aC)
{
nsresult rv;
if (!mD) {
*aC = nsnull;
return NS_OK;
}
nsCOMPtr<fooIB> b;
rv = mD->GetB(getter_AddRefs(b));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<fooIC> c;
rv = b->GetC(getter_AddRefs(c));
NS_ENSURE_SUCCESS(rv, rv);
NS_IF_ADDREF(*aC = c);
return NS_OK;
}
int
main()
{
nsresult rv;
nsCOMPtr<fooIC> c;
PRUint32 i;
gA = new fooA();
NS_ENSURE_TRUE(gA, 1);
rv = gA->GetC(getter_AddRefs(c));
NS_ENSURE_SUCCESS(rv, 1);
(void) c->GetI(&i);
printf("%u\n", i);
return 0;
}
--------
The idea is to:
1) switch nsresult and outparam,
2) keep the rule to return AddRefed,
3) require all clients to do an extra AddRef/Release,
4) require special getters to schedule Release on its thread.
'Special' getter is one which creates the object, or takes it from a
member variable. One of the ways to implement 'special' getters is to
add 'T* nsCOMPtr<T>::ret(nsresult &rv)' and 'T* nsCOMPtr<T>::ret()'.
Both versions of 'ret()' will increase the refcount and will post a
releaser event. The version with nsresult parameter will also check for
non-zero result.
The result will look much like GCed code:
--------
fooIB*
fooD::GetB(nsresult &rv)
{
return mB.ret(rv);
}
fooIC*
fooB::GetC(nsresult &rv)
{
return mC.ret();
}
fooIC*
fooA::GetC(nsresult &rv)
{
if (!mD || !mD->GetB(rv)) {
return nsnull;
}
return mD->GetB(rv)->GetC(rv); // no need for ret(), the getter isn't
// special
}
int
main()
{
nsresult rv;
gA = new fooA();
if (!gA || !gA->GetC(rv))
return 1;
printf("%u\n", gA->GetC(rv)->GetI(rv));
return 0;
}
--------
Later optimization will add 'throw' XPIDL qualifier, which will
explicitly add nsresult outparam only to methods that may actually
return anything other than NS_OK. So methods like QI or simple getters
in this example will cease to have nsresult outparam.
Finally, remaining nsresults will be evicted by exceptions, when the
latter are ready.
--
Sergey Yanovich
_______________________________________________
dev-static-analysis mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-static-analysis