Tuesday, July 8, 2008

Easier tracking of transient objects

My API for tracking transient objects in MM is a little different from Nickle's. Consider the three following functions.
char *a (int n)
{
assert(n>=0);
char *s = mm_allocv(mt_blob, n+1);
s[n] = '\0';
return s;
}

char *b (date_t d)
{
char *s = a(127);
sprintf(s, "Hello world on %s.\n", date2str(d));
return s;
}

char *c (date_t d)
{
MM_ANCHORED;
char *s = a(127);
sprintf(s, "Hello world on %s.\n", date2str(d));
MM_RETURN(s);
}

Functions b and c are almost the same, except that in c the body is what I call an "anchored scope". Neither b nor c call an allocation function directly, but a does.

Now, will mm_allocv in a push the address of the allocated memory onto the transient object stack or not? It depends. If you are not in an anchored scope and call a or b, then it won't. If you call c, it will. In other words, the allocation functions have context-dependent behavior: they push new addresses when executed in an anchored scope and don't push otherwise. Along the same lines, when exiting an anchored scope with MM_RETURN, the returned object will be pushed only if the return is into an(other) anchored scope.

I believe this behavior is more useful than that of the Nickle system. There are lots of little functions in Lush who create a new object. They typically do one or a small number of allocations and then initialize the object. I do not need to fortify all these functions with MM_ANCHORED, it is good enough to do it to the functions that call such constructor functions. In essence, I believe I will need to use MM_ANCHORED and company less often and will find it easier to write correct code when using it.

No comments: