Okay, I've checked in the final bits needed to do memory allocations
and such within Parrot. Here's the scoop.
For memory you need to allocate from the system, use
mem_sys_allocate. Takes a size, returns a void pointer to the
allocated memory. Free it up with mem_sys_free, or it leaks. To
resize, call mem_sys_realloc. You may *only* free or realloc memory
this way if it came from mem_sys_allocate. Otherwise Bad Things
Happen. (These are small wrappers around malloc, free, and realloc)
You generally should *not* do that if you can avoid it, and do *not*
hang this memory off a PMC or a buffer unless you set flag bits
properly.
For GCable memory, it's a little easier.
All GCable memory must hang off something that looks like a Buffer.
(As defined in string.h at the moment) A base Buffer structure has a
memory pointer, buffer length, and flag field. You may have anything
after this that you like. (More on that later)
To allocate a buffer header, call new_tracked_header(interpreter,
size). The interpreter is the interpreter you're allocating the
buffer from (Better be the current one) and size is how big the
buffer header should be in bytes. Anything after the first three
fields is yours to play with if you need it.
To allocate a string header, call new_string_header(interpreter).
This is equivalent to calling new_tracked_header(interpreter,
sizeof(struct STRING)) with some extra setup after the buffer header
has been allocated.
To allocate memory that is GCable, call Parrot_allocate(interpreter,
size). Then stash the pointer and size in your buffer header, or
it'll go missing later. To resize a chunk of memory, call
mem_realloc(interpreter, from, oldsize, newsize).
If your buffer points to non-moveable memory, set the
BUFFER_immobile_FLAG bit in the buffer struct. The memory then won't
be moved. Do *not* set this for memory allocated with
Parrot_allocate! If the memory is system memory and should be freed
when the buffer is GC'd, set the BUFFER_sysmem_FLAG bit. Generally
you'll set both. (The exception is for memory owned externally, in
which case immobile will be set but sysmem won't be. In that case the
buffer will be neither moved nor freed on cleanup)
When you're done with memory or a buffer header or a string header,
just let them fall on the floor. The GC will pick them up. You may
call free_string or free_tracked if you want, in which case the GC
won't need to do any work. Only do this if you're sure that nobody is
pointing to the string/buffer header.
If your memory cleanup routine is called from within the GC (we'll
get to that in another message), call gc_used on the memory you want
to retain. The parameters are the same as for mem_realloc, which
gives you the chance to shrink (*not* grow) the chunk of memory you
have. Call it even if things don't change--if there's a compacting
collector your memory will be moved.
Possible bugs:
==============
If you're not careful, here's what can happen.
If your buffer header can't be reached from the root set, you'll end
up having it reclaimed when a sweep is made.
If you store a pointer to memory but don't have it hanging off a
reachable buffer header, it'll get stomped on and reused.
If you do have memory in a buffer but cache the pointer, you can find
it yanked out from under you by the GC system. (I.e. the pointer not
in the buffer may be invalid)
--
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
[EMAIL PROTECTED] have teddy bears and even
teddy bears get drunk