Re: GC safety and return values Michael Sperber 27 Dec 2003 16:10 UTC

>>>>> "Tom" == Tom Lord <xxxxxx@emf.net> writes:

Tom> jimb is correct.

Right.  I misunderstood him.  Thanks for the clarifying example!

Tom> Consider the code:

Tom>         scheme_value x;

Tom>         [...]

Tom>         GCPRO(&x);

Tom>         [...]

Tom>         z = SCHEME_CONS (x, y);         /* XXX */

Tom> during execution of the the statement marked "XXX", the sequence
Tom> over time of operations may be:

Tom>         thread 1:                       thread 2:
Tom>                                                       |
Tom>         reg1 = x;                       -             t
Tom>         reg2 = y;                       -             i
Tom>         -                               trigger GC    m
Tom>         call SCHEME_CONS                -             e
Tom>         (on return,                     -             |
Tom>         reg1 holds new pair)            -             V
Tom>         -                               trigger GC
Tom>         z = reg1                        -

Tom> At the first GC, a stop-and-copy GC will want to modify the values
Tom> stored in x and y, but it won't find reg1 and reg2.

Tom> At the second GC, a stop-and-copy GC will want to modify the value
Tom> about to be stored in z, but it won't find reg1.

Tom> That is one reason why it isn't sufficient to make sure that protected
Tom> scheme values are always stored in GCPROtected locations -- you must
Tom> also make sure that, other than in the internals of the FFI
Tom> implementation, they are not stored anywhere else.

Tom> You can make that guarantee by not passing or returning those values
Tom> directly at all -- but instead passing and returning "handles" for
Tom> those values.

Tom> Jimb and I have each shown a technique (so now you have two available)
Tom> for always passing and returning handles:  in jimb's approach, handles
Tom> are separately allocated objects;  in my approach, handles are the
Tom> addresses of GCPROtected values.    So you have either:

Tom>         scheme_value_handle x = 0;
Tom>         scheme_value_handle y = 0;
Tom>         scheme_value_handle z = 0;

Tom>         [....]

Tom>         z = SCHEME_CONS (this_call, x, y);

Tom>         /* caller frees any handles allocated above. */

Tom> or:

Tom>         struct my_frame
Tom>         {
Tom>           scheme_value x;
Tom>           scheme_value y;
Tom>           scheme_value z;
Tom>         } f;

Tom>         GCPRO_FRAME (f);

Tom>         [...]

Tom>         SCHEME_CONS (&f.z, this_instance, &f.x, &f.y);

Tom>         /* eventual GCUNPRO_FRAME needed */

Tom> (As I said elsewhere, I think that there are some performance and,
Tom> more importantly, GC-precision advantages to the second approach.)

Tom> Either approach also has advantages for single-threaded systems simply
Tom> because they both make it harder to make certain kinds of mistakes
Tom> that will lead to subtle and difficult-to-reproduce GC bugs.

Tom> -t

--
Cheers =8-} Mike
Friede, Völkerverständigung und überhaupt blabla