> STRING * concat (STRING* a, STRING* b, STRING* c) { > PARROT_start(); > PARROT_str_params_3(a, b, c); > PARROT_str_local_2(d, e); > > d = string_concat(a, b); > e = string_concat(d, c); > > PARROT_return(e); > }
Yet more ideas. Woohoo! :) I considered this kind of approach myself, but discarded it due to the ton of extraneous code you have to write to do the simplest of things. :( I'm not sure if the other people have considered it, discarded it, or are still considering it. As far as the pros/cons... First, it requires you write in a pseudo-language to define your local PMC headers and how to return data. I'm sure the macro freaks that have been scarred by perl5 will jump on here and beat you down in a few hours or so. :) Can you provide an implementation of the macros you described above? I have a few concerns which I'm not sure if they are addressed. For example: PARROT_str_local(d) I'm assuming it puts a reference to d onto the rooted stack. It would also need to initialize d to NULL to avoid pointing at garbage buffers. PARROT_str_params_3(a, b, c); What's the point of this? With rule 5 that prevents function call nesting, you're guaranteed of all your arguments being rooted. I think you can lose either the nesting requirement or the str_params requirement. PARROT_return(e); I'm assuming this backs the stack up to the place pointed to by PARROT_start(), right? This means during a longjmp, the stack won't be backed up properly until another PARROT_return() is called, somewhere farther up the chain, right? Finally, I think Dan has already outlawed longjmp due to problems with threading, but he'll have to elaborate on that. I agree my most recently stated approach is not longjmp safe since it could leave neonate set on certain buffers/pmcs. Finally, in response to my original post, you asked: > Suppose your C code builds a nested datastructure. For instance, > it creates some strings and add them to a hash-table. The hash-table is > then returned. Should it clear the neonate flag of the strings? I think I'd have to say...don't do that. Ops and functions shouldn't be building large data structures, imo. Stuff like buliding large hashes and/or arrays of data should be done in opcode, in perl code, or whatever language is operating on parrot. If you *really* need to operate on a nested datastructure, and you're going to hold it against my proposal, then there are two options. a) write code like: base = newbasepmc #nenoate pmc other = newchildpmc #also neonate base->add(other) #even if collecting/dod'ing, can't collect above two done_with_pmc(other) #un-neonates it, since it's attached to a root (neonate0 set ....repeat... It works, and then you just need to worry about what to do with your 'base' at the end of the function (to un-neonate it or not). b) make a done_with_children_of_pmc() style function. it hijacks onto the tracing functionality inherent in the DOD code, and searches for a contiguous selection of neonate buffers and pointers eminating from the pmc we pass in, and un-neonates them, leaving the passed-in-pmc neonated. Since everything we do in the function is nenoate, everything we construct into this base pmc should be contiguously neonate, if that makes sense. Granted, it's a little bit expensive to do the tracing, but you shouldn't need to trace too deep at all, and its time is proportional to the size of the nested data structure you are creating. Does that help? Mike Lambert PS: Oh, and I forgot to mention in my previous proposal about the need for nenonating pmc headers, and to look into what functions need to un-neonate pmc headers. That should be localized to the vtable methods, which are sort of a mess right now anyway with the transmogrification of vtables and have other GC problems.