Files
mercury/runtime/mercury_memory.c
Fergus Henderson 17d5aa732e Add support for interfacing Mercury with the MPS garbage collector.
Estimated hours taken: 20
Branches: main

Add support for interfacing Mercury with the MPS garbage collector.

This change is broken into three parts:

	1. Import version 1.100.1 of the MPS kit into the Mercury
	   CVS repository, in the directory `mps_gc'.

	2. Make some changes to the MPS kit for Mercury,
	   to support fully-conservative collection and tagged pointers,
	   and to wrap it in an interface that is similar to that of
	   the Boehm collector.

	3. Modify the rest of the Mercury implementation
	   to support linking with the MPS kit instead
	   of the Boehm collector.  This involved defining
	   `mps' as a new GC method and a new grade component.

This is part 3 of 3.

Mmake.workspace:
	Include the MPS directories in the header file and library search
	paths.

tools/bootcheck:
	Link the mps_gc directory into the stage2 and stage3 directories.

Mmake.workspace:
runtime/Mmakefile:
scripts/ml.in:
	For *.mps grades, link in mps.a.
	(XXX ml.in is linking in libmps.a, which is wrong.)

runtime/Mmakefile:
trace/Mmakefile:
	In the rule for `check_headers', which checks macro namespace
	cleanliness, allow names to start with `MPS_' or `mps_'.

runtime/RESERVED_MACRO_NAMES:
	Add `mercury_mps_h', which is used by mps_gc/code/mercury_mps.h
	for its header guard.  (Normally it would be better to use
	uppercase for header guard macro names, but that would be
	inconsistent with the coding style used in mps_gc/code.)

scripts/canonical_grade.sh-subr:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
scripts/canonical_grade.sh-subr:
	Handle the new `mps' GC method and grade component.

compiler/globals.m:
compiler/options.m:
doc/user_guide.texi:
	Replace gc_method `conservative' with two alternatives
	`boehm' and `mps'. ("--gc conservative" is still allowed,
	and treated as equivalent to "--gc boehm".)
	Add new function `gc_is_conservative' to globals.m.

compiler/mercury_compile.m:
compiler/handle_options.m:
	Use `gc_is_conservative' rather than `= conservative'.

compiler/handle_options.m:
	Handle the "mps" grade component.
	(XXX need to document this in options.m and user_guide.texi)

compiler/compile_target_code.m:
	Pass the appropriate C defines for the new GC methods.

compiler/mercury_compile.m:
	Wrap the work-around for a Boehm GC bug inside `#ifndef MR_MPS_GC'.

library/array.m:
	Use GC_FREE() rather than GC_free().
	This is needed for two reasons:
	- so that it works with MPS, which only defines GC_FREE
	- so that it works with then Boehm collector when
	  GC debugging is enabled

library/benchmarking.m:
	Output GC statistics for the MPS collector.

runtime/mercury.h:
runtime/mercury_heap.h:
runtime/mercury_init.h:
runtime/mercury_memory.h:
	If MR_MPS_GC is defined, use mercury_mps.h rather than gc.h.

runtime/mercury_conf_param.h:
	Add configuration macros MR_BOEHM_GC and MR_MPS_GC.
	Set MR_CONSERVATIVE_GC if either of these is set.
	Default to MR_BOEHM_GC if only MR_CONSERVATIVE_GC is set.

runtime/mercury_context.h:
runtime/mercury_deep_copy.h:
runtime/mercury_engine.h:
runtime/mercury_float.h:
runtime/mercury_heap.h:
	Explictly #include "mercury_conf.h", so that
	MR_CONSERVATIVE_GC will be set properly before it is tested.

runtime/mercury_grade.h:
	Handle the .mps grade component.

runtime/mercury_memory.c:
runtime/mercury_wrapper.c:
runtime/mercury_memory_handlers.c:
	Move the call to MR_setup_signals() earlier in the
	initialization sequence, so that the MPS signal handlers
	get installed after our signal handlers.  This is needed
	because our signal handlers assume that any signals that
	they can't handle are fatal errors, which interfere's
	with MPS's use of signal handlers for memory barriers.

runtime/mercury_wrapper.c:
	Add code to initialize the MPS collector.
	Put code which is specific to the Boehm collector inside
	#ifdef MR_BOEHM_GC rather than #ifdef MR_CONSERVATIVE_GC.

runtime/mercury_wrapper.h:
	Update a comment.
2002-08-21 11:28:01 +00:00

346 lines
8.1 KiB
C

/*
** Copyright (C) 1994-2000,2002 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/*
** This module defines the register array and data regions of the
** execution algorithm.
** They are defined together here to allow us to control how they map
** onto direct mapped caches.
** We allocate a large arena, preferably aligned on a boundary that
** is a multiple of both the page size and the primary cache size.
**
** We then allocate the heap and the stacks in such a way that
**
** the register array
** the bottom of the heap
** the bottom of the detstack
** the bottom of the nondstack
**
** all start at different offsets from multiples of the primary cache size.
** This should reduce cache conflicts (especially for small programs).
**
** If the operating system of the machine supports the mprotect syscall,
** we also protect a chunk at the end of each area against access,
** thus detecting area overflow.
**
** The code for handling the allocation and management of different
** memory zones is in mercury_memory_zones.{c,h}.
** The code for handling overflows and memory access errors in general
** is in mercury_memory_handlers.{c,h}.
*/
/*---------------------------------------------------------------------------*/
#include "mercury_imp.h"
/*
** This include must come before anything else that might include <signal.h>.
** See the commments in mercury_signal.h.
*/
#include "mercury_signal.h"
#ifdef MR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef MR_HAVE_SYS_SIGINFO_H
#include <sys/siginfo.h>
#endif
#ifdef MR_HAVE_MPROTECT
#include <sys/mman.h>
#endif
#ifdef MR_HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
#ifdef MR_HAVE_SYS_UCONTEXT_H
#include <sys/ucontext.h>
#endif
#include "mercury_imp.h"
#include "mercury_trace_base.h"
#include "mercury_memory_handlers.h"
/*---------------------------------------------------------------------------*/
#if defined(MR_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
#define getpagesize() sysconf(_SC_PAGESIZE)
#elif !defined(MR_HAVE_GETPAGESIZE)
#if defined(MR_WIN32_GETSYSTEMINFO)
#include <windows.h>
static size_t
getpagesize(void)
{
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
return (size_t) SysInfo.dwPageSize;
}
#else
#define getpagesize() 8192
#endif
#endif
/*---------------------------------------------------------------------------*/
#ifdef MR_HAVE_SIGINFO
static MR_bool try_munprotect(void *address, void *context);
static char *explain_context(void *context);
#endif /* MR_HAVE_SIGINFO */
/*
** Define the memory zones used by the Mercury runtime.
** (The trail zone is declared in mercury_trail.c.)
** XXX All the zones should be in mercury_engine.h
*/
#ifdef MR_USE_MINIMAL_MODEL
MR_MemoryZone *MR_generatorstack_zone;
MR_MemoryZone *MR_cutstack_zone;
#endif
size_t MR_unit;
size_t MR_page_size;
void
MR_init_memory(void)
{
static MR_bool already_initialized = MR_FALSE;
if (already_initialized != MR_FALSE)
return;
already_initialized = MR_TRUE;
/*
** Convert all the sizes are from kilobytes to bytes and
** make sure they are multiples of the page and cache sizes.
*/
MR_page_size = getpagesize();
MR_unit = MR_max(MR_page_size, MR_pcache_size);
#ifdef MR_CONSERVATIVE_GC
MR_heap_size = 0;
MR_heap_zone_size = 0;
MR_solutions_heap_size = 0;
MR_solutions_heap_zone_size = 0;
MR_global_heap_size = 0;
MR_global_heap_zone_size = 0;
MR_debug_heap_size = 0;
MR_debug_heap_zone_size = 0;
MR_heap_margin_size = 0;
#else
MR_heap_size = MR_round_up(MR_heap_size * 1024,
MR_unit);
MR_heap_zone_size = MR_round_up(MR_heap_zone_size * 1024,
MR_unit);
MR_solutions_heap_size = MR_round_up(MR_solutions_heap_size * 1024,
MR_unit);
MR_solutions_heap_zone_size = MR_round_up(
MR_solutions_heap_zone_size * 1024,
MR_unit);
MR_global_heap_size = MR_round_up(MR_global_heap_size * 1024,
MR_unit);
MR_global_heap_zone_size = MR_round_up(MR_global_heap_zone_size * 1024,
MR_unit);
MR_debug_heap_size = MR_round_up(MR_debug_heap_size * 1024,
MR_unit);
MR_debug_heap_zone_size = MR_round_up(MR_debug_heap_zone_size * 1024,
MR_unit);
/* Note that there's no need for the heap margin to be rounded up */
MR_heap_margin_size = MR_heap_margin_size * 1024;
#endif
MR_detstack_size = MR_round_up(MR_detstack_size * 1024,
MR_unit);
MR_detstack_zone_size = MR_round_up(MR_detstack_zone_size * 1024,
MR_unit);
MR_nondstack_size = MR_round_up(MR_nondstack_size * 1024,
MR_unit);
MR_nondstack_zone_size = MR_round_up(MR_nondstack_zone_size * 1024,
MR_unit);
#ifdef MR_USE_MINIMAL_MODEL
MR_generatorstack_size = MR_round_up(MR_generatorstack_size * 1024,
MR_unit);
MR_generatorstack_zone_size = MR_round_up(
MR_generatorstack_zone_size * 1024,
MR_unit);
MR_cutstack_size = MR_round_up(MR_cutstack_size * 1024,
MR_unit);
MR_cutstack_zone_size = MR_round_up(MR_cutstack_zone_size * 1024,
MR_unit);
#endif
#ifdef MR_USE_TRAIL
MR_trail_size = MR_round_up(MR_trail_size * 1024,
MR_unit);
MR_trail_zone_size = MR_round_up(MR_trail_zone_size * 1024,
MR_unit);
#else
MR_trail_size = 0;
MR_trail_zone_size = 0;
#endif
/*
** If the zone sizes were set to something too big, then
** set them to a single unit.
*/
#ifndef MR_CONSERVATIVE_GC
if (MR_heap_zone_size >= MR_heap_size) {
MR_heap_zone_size = MR_unit;
}
if (MR_solutions_heap_zone_size >= MR_solutions_heap_size) {
MR_solutions_heap_zone_size = MR_unit;
}
if (MR_global_heap_zone_size >= MR_global_heap_size) {
MR_global_heap_zone_size = MR_unit;
}
#endif
if (MR_detstack_zone_size >= MR_detstack_size) {
MR_detstack_zone_size = MR_unit;
}
if (MR_nondstack_zone_size >= MR_nondstack_size) {
MR_nondstack_zone_size = MR_unit;
}
#ifdef MR_USE_TRAIL
if (MR_trail_zone_size >= MR_trail_size) {
MR_trail_zone_size = MR_unit;
}
#endif
MR_init_zones();
if (MR_memdebug) {
MR_debug_memory();
}
} /* end MR_init_memory() */
/*---------------------------------------------------------------------------*/
/*
** These routines allocate memory that will NOT be scanned by the
** conservative garbage collector. You MUST NOT uses these to
** store pointers into GC'ed memory.
**
*/
void *
MR_malloc(size_t n)
{
void *ptr;
ptr = malloc(n);
if (ptr == NULL && n != 0) {
MR_fatal_error("ran out of memory");
}
return ptr;
}
void *
MR_realloc(void *old_ptr, size_t num_bytes)
{
void *ptr;
ptr = realloc(old_ptr, num_bytes);
if (ptr == NULL && num_bytes != 0) {
MR_fatal_error("ran out of memory");
}
return ptr;
}
char *
MR_copy_string(const char *s)
{
int len;
char *copy;
if (s == NULL) {
return NULL;
} else {
len = strlen(s);
copy = MR_malloc(len + 1);
strcpy(copy, s);
return copy;
}
}
/*---------------------------------------------------------------------------*/
/*
** These routines allocate memory that will be scanned by the
** conservative garbage collector.
**
** XXX This is inefficient. If MR_BOEHM_GC is enabled,
** we should set `GC_oom_fn' (see boehm_gc/gc.h) rather than
** testing the return value from GC_MALLOC() or GC_MALLOC_UNCOLLECTABLE().
*/
void *
MR_GC_malloc(size_t num_bytes)
{
void *ptr;
#ifdef MR_CONSERVATIVE_GC
ptr = GC_MALLOC(num_bytes);
#else
ptr = malloc(num_bytes);
#endif
if (ptr == NULL && num_bytes != 0) {
MR_fatal_error("could not allocate memory");
}
return ptr;
}
void *
MR_GC_malloc_uncollectable(size_t num_bytes)
{
void *ptr;
#ifdef MR_CONSERVATIVE_GC
ptr = GC_MALLOC_UNCOLLECTABLE(num_bytes);
#else
ptr = malloc(num_bytes);
#endif
if (ptr == NULL && num_bytes != 0) {
MR_fatal_error("could not allocate memory");
}
return ptr;
}
void *
MR_GC_realloc(void *old_ptr, size_t num_bytes)
{
void *ptr;
#ifdef MR_CONSERVATIVE_GC
ptr = GC_REALLOC(old_ptr, num_bytes);
#else
ptr = realloc(old_ptr, num_bytes);
#endif
if (ptr == NULL && num_bytes != 0) {
MR_fatal_error("ran out of memory");
}
return ptr;
}
/*---------------------------------------------------------------------------*/