Runtime Gotchas

Introduction

While working on the runtime I (user:manus) found a few things that need to be watched for when modifying the runtime. Below is a non-exhaustive list of bugs I've encountered that can easily be redone if not flagged anywhere for future references.

Objects

Size of objects

The size of objects must always be a multiple of ALIGNMAX, and the size of containers of objects too. That is to say that either the container is full (no non-used bytes), or if it is not full, there is at least ALIGNMAX bytes available. See the comments on ALIGNMAX to understand why it is important.


B_LAST flag

It is quite dangerous to play with the B_LAST flag as if you set it on an object which is at the beginning of chunk, then the memory allocation will consider the block as free if the object is no B_BUSY, and thus will free it. Usually the B_LAST operations are transparent to the GC writer except in one place: the incremental compaction done in `partial_scavenging'.

Is object alive?

When traversing the memory to find objects that are still alive (e.g. as done in `sweep_from_space') you need to be careful about the flags you are checking. First the object needs to have the B_BUSY flag, if not then it means that this block is part of the free list. Then it needs to be either marked with the B_FWD flag, and if B_BUSY and not B_FWD then it should have the EO_MARK flag.

Not doing this proper check could end up in a bug chasing that last for days....

Protecting objects and exceptions

This issue was first found while testing test#melt076. It showed a major design issue in the runtime when calling back Eiffel routines that may throw an exception (in the eweasel test case an invariant violation). Indeed we protect the C locals using RT_GC_PROTECT and when we are done we call RT_GC_WEAN. However if between the two calls an exception occurs, then we do not do the RT_GC_WEAN and the address of the C locals is not valid anymore since the C stacks rewinded. So later when the GC kicks in, it actually tries to follow an invalid reference and most likely a crash will occur. The solution is to perform the equivalent of an Eiffel rescue clause at the C level:

{
	jmp_buf exenv;
	EIF_REFERENCE obj;
 
	excatch(&exenv);		/* Record pseudo execution vector */
	if (setjmp(exenv)) {
		RT_GC_WEAN(obj);	/* Remove protection. */
		ereturn();		/* Propagate exception */
	}
 
		/* Automatic protection of `obj' */
	RT_GC_PROTECT(obj);
 
		/* .... Your code here .... */
 
		/* No more propection for `obj' */
	RT_GC_WEAN(obj);
 
		/* Restore exception stack. */
	expop(&eif_stack);
}