Bug in Jitter

Godmar Back gback at cs.utah.edu
Tue Jul 7 22:13:07 PDT 1998

> 3. It *does not* clean any registers nor does it flush the floating point
> stack (on the x86).
> Point (3) is crucial here - sync_registers is used to optimise (or hack
> depending on how you look at it) some test and branch conditions which cause
> exceptions.  The exception code must flush the registers before the exception
> is actually called, but the main code shouldn't suffer from the performance
> hit of turning this into a basic-block.   

I also didn't see where it would flush the floating point stack.
As far as I can see, sync_registers is used four times in icode.c:

in check_array_index and check_array_constindex before the exception is
	actually called, as Tim says.

in softcall_nullpointer	before call_soft(soft_nullpointer)
	softcall_nullpointer is only used in CHECK_NULL if 
	CREATE_NULLPOINTER_CHECKS is defined, that is, in the mode where 
	we do not rely on the hardware to catch them.

in softcall_nosuchmethod:  here it is immediately followed by a 
	prepare_function_call, which seems superfluous?

The difference between sync_registers and prepare_function_call
is that sync_registers saves and restores the "enable_readonce" flag
and that prepare_function_call flag "cleans" the register by resetting 
the modified flag.  (As Tim says.)

To add another tiny data point: I counted how often spill code was actually
emitted in a CHECK_NULL modified as described for my (non-representative)
javac example.  Here is the result:

NPSPILL: spilled 3959 times, didn't need to spill 19416 times

That's roughly 1 in 5.  Also, for the example, the number of *additional*
spill instructions was 5153.  That means that we pay on average an additional
1.3 store instructions for the ability to retain correct state when a
null pointer exception occurs (in one non-representative benchmark).

It might also be worth checking out how the explicit checking would
behave performance-wise.  The number of emitted instructions is certainly 
higher, but the instructions are mostly register moves and tests for zero, 
the sync_register would be off the critical path (as Tim describes above
for badarrayindex),  and these simple instructions should be faster than 
stores to memory.  On the other hand, the code size of the program increases.
I'm not somebody who counts cycles, but somebody who does might find this
an interesting topic.

Tim also said:
> You cannot use sync_registers() in a
> position where the control flow will join another control flow 'cause it'll
> break sometimes.

I wonder when--and I guess that applies to prepare_function_call then as well...
so that fix wouldn't work after all?

	- Godmar

More information about the kaffe mailing list