[Gc] workaround for C++ exceptions problem

Filip Pizlo pizlo at mac.com
Thu Jan 26 14:12:34 PST 2006


On Jan 26, 2006, at 3:14 AM, skaller wrote:

>> How would the machine stack be faster?  When you throw the exception,
>> you can't put it on the top of the stack, because the top of the
>> stack will be blown away and reused by destructors.  So where would
>> you put the exception?
>
> In a register whilst you're decrementing the stack.
>
> In the first case, you CAN push the exception onto the stack
> when you execute a destructor, and pop it off afterwards,
> pop the stack, push it onto the stack again to execute the
> next destructor.

What is this register that you speak of?  Are you saying the register  
is the exception, or a pointer to it?  If it is a pointer, then this  
is what I would call the linked-list approach.

> Such accesses are free of cost since the cache already
> contains the region of the stack, or it will on the
> very next instruction, which is a subroutine call to
> the destructor. SMLY on returning the subroutine pops
> the return address off the stack -- so again the stack
> is in the cache .. so the chance of a cache miss is extremely
> low. Operations on the cache take zero time (in effect).
>
> Also, it wastes only one machine word per 'in flight'
> exception, which is half the space required for a list.
>
> One register is required for scratch to cover the
> reduction of the stack pointer (usually an increment
> of SP reduces the stack .. so I say reduce the stack
> pointer rather than decrement it .. :)
>
> Something like:
>
> 	pop EAX           // save exception
> 	add SP,frame_size // unwind the stack
> 	push EAX          // restore exception

I don't see the point here.  If the value in EAX is a pointer to the  
exception, then there is no substantive difference from the linked  
list approach.  In particular, the fact that EAX and some stack  
location contain pointers to the exception changes nothing:

1) The object being pointed at is not allocated in the GC's heap  
unless we override allocation routines, so the fact that there is a  
pointer to it from the stack does no good for us, and

2) The existence of the pointer doesn't change the location of the  
actual exception slot, which is the only thing we care about.

> Basically stack unwinding is just a single instruction,
> with my layout it takes 3 instructions. This is probably
> enough except when checking to see if there is a matching
> handler (and there is some fiddling on exit from
> the handler ..)
>
> In fact, when a handler is called .. the current exception
> is right there on the stack like a subroutine call argument
> should be.

Like a subroutine call, what you get on the stack is a pointer to the  
current exception, since the current exception is almost certainly a  
complex C++ object.

Now, of course, we could be dealing with simple C++ exceptions like  
pointers or integers, but those are far less interesting.

>> I don't see any reasonable way of using the machine stack for
>> exceptions.
>
> Hope you can now! The point is that the top exception
> has to be somewhere special .. but the rest don't.

Actually, I think we were talking cross-purposes.  I hadn't  
considered the what I understand to be the technique you laid out  
because it doesn't actually change anything for us.

But maybe I still don't understand what you're getting at.  I'm sure  
you'll tell me if this is the case. :-)

>> Right, that's exactly what you do.  Users have to throw exceptions
>> using the GC_THROW function.  Every use of:
>>
>> throw e;
>>
>> must be replaced with:
>>
>> GC_THROW(e);
>
> What about exceptions thrown from inside the standard library?

Those don't contain pointers to the GC heap.  I suppose they would  
become problematic if the GC was put in override-malloc mode...  But  
so long as you don't have the GC overriding malloc, all is well.

>>>
>>> If the object has virtual bases such pointers always
>>> exist or can be constructed, even if the user didn't create them.
>>> If they're offsets, you'll get a different result to full
>>> pointers .. the pointer will point to the real exception.
>>>
>>> This is messy .. :)
>>
>> But why would those pointers cause trouble?
>
> Because thinking about it requires reasoning about C++
> which tends to twist my brain inside out :)
>
> In other words .. I don't know .. can you say why
> they *wouldn't* cause trouble? You can probably show
> many examples I could dream up can't cause a problem --
> can you prove it in general?

If an object contains a pointer into itself, then the GC can ignore  
it.  If we are copying the object just to get its pointers, then we  
don't care about preserving those pointers.

-Filip




More information about the Gc mailing list