/* Amount of space needed when GC requested */
extern unsigned long gc_space_needed;
+
+/* Number of new ephemerons requested from the GC. */
+extern unsigned long n_ephemerons_requested;
+extern bool ephemeron_request_hard_p;
\f
/* Arithmetic utilities */
extern SCHEME_OBJECT Mul (SCHEME_OBJECT, SCHEME_OBJECT);
extern SCHEME_OBJECT find_symbol (unsigned long, const char *);
extern void strengthen_symbol (SCHEME_OBJECT);
extern void weaken_symbol (SCHEME_OBJECT);
+extern unsigned long compute_extra_ephemeron_space (unsigned long);
+extern void guarantee_extra_ephemeron_space (unsigned long);
/* Random and OS utilities */
extern int strcmp_ci (const char *, const char *);
static
DEFINE_GC_HANDLER (handle_ephemeron)
{
- dumped_ephemeron_count += 1;
+ /* Count each one once by counting only if there is no borken heart. */
+ if (0 == (GC_PRECHECK_FROM (OBJECT_ADDRESS (object))))
+ dumped_ephemeron_count += 1;
return (gc_handle_unaligned_vector (scan, object));
}
\f
#define REQUIRED_HEAP(h) \
((FASLHDR_HEAP_SIZE (h)) \
+ (FASLHDR_N_PRIMITIVES (h)) \
- + (FASLHDR_PRIMITIVE_TABLE_SIZE (h)) \
- + (((FASLHDR_VERSION (h)) >= FASL_VERSION_EPHEMERONS) \
- ? (VECTOR_DATA + (FASLHDR_EPHEMERON_COUNT (h))) \
- : 0))
+ + (FASLHDR_PRIMITIVE_TABLE_SIZE (h)))
struct load_band_termination_state
{
fasl_file_handle_t handle;
static unsigned long failed_heap_length = 0;
unsigned long heap_length;
+ unsigned long n_ephemerons = 0;
+ unsigned long extra_ephemeron_space = 0;
SCHEME_OBJECT result;
PRIMITIVE_HEADER (1);
signal_error_from_primitive (ERR_FASL_FILE_TOO_BIG);
heap_length = (REQUIRED_HEAP (fh));
- if (GC_NEEDED_P (heap_length))
+ if ((FASLHDR_VERSION (fh)) >= FASL_VERSION_EPHEMERONS)
+ {
+ n_ephemerons = (FASLHDR_EPHEMERON_COUNT (fh));
+ extra_ephemeron_space
+ = (compute_extra_ephemeron_space (ephemeron_count + n_ephemerons));
+ }
+ if (GC_NEEDED_P (heap_length + extra_ephemeron_space))
{
if (heap_length == failed_heap_length)
signal_error_from_primitive (ERR_FASL_FILE_TOO_BIG);
failed_heap_length = heap_length;
+ n_ephemerons_requested = n_ephemerons;
+ ephemeron_request_hard_p = false;
REQUEST_GC (heap_length);
signal_interrupt_from_primitive ();
}
transaction_record_action (tat_abort, terminate_band_load, state);
init_fasl_file (file_name, true, (&handle));
- if (!allocations_ok_p ((FASLHDR_CONSTANT_SIZE (fh)),
- (REQUIRED_HEAP (fh)),
- (FASLHDR_HEAP_RESERVED (fh))))
+ if (!allocations_ok_p
+ ((FASLHDR_CONSTANT_SIZE (fh)),
+ ((REQUIRED_HEAP (fh))
+ + (((FASLHDR_VERSION (fh)) >= FASL_VERSION_EPHEMERONS)
+ ? (compute_extra_ephemeron_space (FASLHDR_EPHEMERON_COUNT (fh)))
+ : 0)),
+ (FASLHDR_HEAP_RESERVED (fh))))
signal_error_from_primitive (ERR_FASL_FILE_TOO_BIG);
/* Now read the file into memory. Past this point we can't abort
reset_allocator_parameters
((FASLHDR_CONSTANT_SIZE (fh)), (FASLHDR_HEAP_RESERVED (fh)));
+ /* We cleared the heap; the ephemeron array is now bogus. */
+ ephemeron_array = SHARP_F;
result = (load_file (handle, 0));
/* Done -- we have the new image. */
}
\f
static SCHEME_OBJECT
-load_file (fasl_file_handle_t handle, unsigned long prior_ephemeron_count)
+load_file (fasl_file_handle_t handle, unsigned long old_ephemeron_count)
{
new_heap_start = Free;
new_constant_start = constant_alloc_next;
#endif
if ((FASLHDR_VERSION (fh)) >= FASL_VERSION_EPHEMERONS)
- {
- ephemeron_count
- = (prior_ephemeron_count + (FASLHDR_EPHEMERON_COUNT (fh)));
- ephemeron_array = (make_vector (ephemeron_count, SHARP_F, false));
- }
+ guarantee_extra_ephemeron_space
+ (old_ephemeron_count + (FASLHDR_EPHEMERON_COUNT (fh)));
return
(* ((SCHEME_OBJECT *)
static gc_abort_handler_t abort_gc NORETURN;
static gc_walk_proc_t save_tospace_copy;
+static unsigned long compute_ephemeron_array_length (unsigned long);
+
/* Memory Allocation, sequential processor:
oo
history_register = (OBJECT_ADDRESS (*saved_to++));
saved_to = 0;
+ {
+ unsigned long length
+ = (compute_ephemeron_array_length
+ (ephemeron_count + n_ephemerons_requested));
+ if (!HEAP_AVAILABLE_P
+ ((VECTOR_DATA + length) + (n_ephemerons_requested * EPHEMERON_SIZE)))
+ {
+ if (ephemeron_request_hard_p)
+ gc_space_needed += (VECTOR_DATA + length);
+ length = (compute_ephemeron_array_length (ephemeron_count));
#ifdef ENABLE_GC_DEBUGGING_TOOLS
- /* This should never trigger, because we discard the previous
- ephemeron array, which always has at least as many slots as there
- are live ephemerons. Add one for the vector's manifest. */
- if (GC_NEEDED_P (ephemeron_count + 1))
- std_gc_death ("No room for ephemeron array");
+ /* This should never trigger, because we discard the previous
+ ephemeron array, which always has room for at least as many
+ ephemerons as are now live. */
+ if (!HEAP_AVAILABLE_P (VECTOR_DATA + length))
+ std_gc_death ("No room for ephemeron array");
#endif
- ephemeron_array = (make_vector (ephemeron_count, SHARP_F, false));
+ }
+ ephemeron_array = (make_vector (length, SHARP_F, false));
+ n_ephemerons_requested = 0;
+ ephemeron_request_hard_p = false;
+ }
CC_TRANSPORT_END ();
CLEAR_INTERRUPT (INT_GC);
};
static unsigned long
-compute_ephemeron_array_length (void)
+compute_ephemeron_array_length (unsigned long n)
{
unsigned int start = 0, end = ((sizeof primes) / (sizeof (*primes)));
unsigned int index;
- if ((primes [end - 1]) < ephemeron_count)
+ if ((primes [end - 1]) < n)
return (primes [end - 1]);
do {
index = (start + ((end - start) / 2));
- if ((primes [index]) < ephemeron_count)
+ if ((primes [index]) < n)
start = (index + 1);
- else if (ephemeron_count < (primes [index]))
+ else if (n < (primes [index]))
end = index;
else
return (primes [index]);
return (primes [start]);
}
-static void
-guarantee_ephemeron_space (void)
+static bool
+ephemeron_array_big_enough_p (unsigned long n)
+{
+ return
+ ((n == 0)
+ || ((VECTOR_P (ephemeron_array))
+ && (n <= (VECTOR_LENGTH (ephemeron_array)))));
+}
+
+unsigned long
+compute_extra_ephemeron_space (unsigned long n)
{
- /* Guarantee space after Free and in the ephemeron array for one
- ephemeron. */
- if ((VECTOR_P (ephemeron_array))
- && (ephemeron_count <= (VECTOR_LENGTH (ephemeron_array))))
- Primitive_GC_If_Needed (EPHEMERON_SIZE);
+ if (ephemeron_array_big_enough_p (n))
+ return (0);
else
+ return (VECTOR_DATA + (compute_ephemeron_array_length (n)));
+}
+
+void
+guarantee_extra_ephemeron_space (unsigned long n)
+{
+ ephemeron_count = n;
+ if (!ephemeron_array_big_enough_p (n))
{
- unsigned long length = (compute_ephemeron_array_length ());
- /* We could be cleverer about expanding the ephemeron array, and
- tell the GC (above) that we really want an ephemeron array
- that is one slot larger. */
- Primitive_GC_If_Needed (EPHEMERON_SIZE + VECTOR_DATA + length);
+ unsigned long length = (compute_ephemeron_array_length (n));
+ assert (HEAP_AVAILABLE_P (VECTOR_DATA + length));
ephemeron_array = (make_vector (length, SHARP_F, false));
}
}
+\f
+static void
+gc_if_needed_for_ephemeron (unsigned long extra_space)
+{
+ if (GC_NEEDED_P (EPHEMERON_SIZE + extra_space))
+ {
+ n_ephemerons_requested = 1;
+ ephemeron_request_hard_p = true;
+ Primitive_GC (EPHEMERON_SIZE);
+ }
+}
DEFINE_PRIMITIVE ("MAKE-EPHEMERON", Prim_make_ephemeron, 2, 2, 0)
{
PRIMITIVE_HEADER (2);
ephemeron_count += 1;
- guarantee_ephemeron_space ();
+ if (ephemeron_array_big_enough_p (ephemeron_count))
+ gc_if_needed_for_ephemeron (0);
+ else
+ {
+ unsigned long length
+ = (compute_ephemeron_array_length (ephemeron_count));
+ gc_if_needed_for_ephemeron (VECTOR_DATA + length);
+ ephemeron_array = (make_vector (length, SHARP_F, false));
+ }
{
SCHEME_OBJECT * addr = Free;
(*Free++) = MARKED_EPHEMERON_MANIFEST;
/* Amount of space needed when GC requested */
unsigned long gc_space_needed;
+/* Number of new ephemerons requested from the GC. */
+unsigned long n_ephemerons_requested;
+bool ephemeron_request_hard_p;
+
#ifndef HEAP_IN_LOW_MEMORY
SCHEME_OBJECT * memory_base;
#endif