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

Reply via email to