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

Reply via email to