Files
mercury/runtime/mercury_memory.h
Zoltan Somogyi 0bf54e14ed Specify what happens at memory exhaustion.
runtime/mercury_memory.h:
    State explicitly that the C functions in this module all abort
    when they cannot allocate the memory they were asked to allocate.

    Put the documentation of some functions in the same order as their
    definitions.
2025-04-20 20:50:07 +10:00

390 lines
16 KiB
C

// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 1994-2000,2002, 2004, 2006, 2008 The University of Melbourne.
// Copyright (C) 2014-2016, 2018, 2025 The Mercury Team.
// This file is distributed under the terms specified in COPYING.LIB.
// mercury_memory.h:
// general memory-allocation related stuff for the Mercury runtime.
//
// This defines the different memory areas used by the Mercury runtime,
// including the det & nondet stacks, the heap (and solutions heap),
// and the fake_reg array for holding Mercury virtual registers.
// It also provides interfaces for constructing new memory zones,
// and for allocating (possibly shared) memory.
#ifndef MERCURY_MEMORY_H
#define MERCURY_MEMORY_H
#include "mercury_memory_zones.h"
#include <stddef.h> // for size_t
#include "mercury_types.h" // for MR_Word
#include "mercury_std.h" // for MR_bool
#include "mercury_conf.h" // for MR_CONSERVATIVE_GC, etc.
#if defined(MR_CONSERVATIVE_GC)
#if defined(MR_BOEHM_GC)
#define GC_I_HIDE_POINTERS
#include "gc.h" // for GC_FREE
#endif
#endif
// MR_round_up(amount, align) returns `amount' rounded up to the nearest
// alignment boundary. `align' must be a power of 2.
#define MR_round_up(amount, align) ((((amount) - 1) | ((align) - 1)) + 1)
// MR_kilobytes_to_bytes_and_round_up(var) takes an original value in var
// which represents an memory size measured in kilobytes, and converts it to
// a memory size measured in bytes, and then rounds it up to be the next
// multiple of MR_unit.
#define MR_kilobytes_to_bytes_and_round_up(var) \
do { \
var = MR_round_up(var * 1024, MR_unit); \
} while (0)
// For these functions, see the comments in mercury_memory.c and
// mercury_engine.c
extern void MR_init_memory(void);
extern void MR_init_heap(void);
#ifdef MR_CONSERVATIVE_GC
extern void MR_init_conservative_GC(void);
#endif
////////////////////////////////////////////////////////////////////////////
// MR_malloc() and MR_realloc() are like the standard C malloc() and realloc()
// functions, except that the return values are checked.
//
// Structures allocated with MR_malloc() and MR_realloc() must NOT contain
// pointers into GC'ed memory, because those pointers will never be traced
// by the conservative GC. Use MR_GC_malloc() or MR_GC_malloc_uncollectable()
// for that.
//
// MR_NEW(type):
// Allocates space for an object of the specified type.
//
// MR_NEW_ARRAY(type, num):
// Allocates space for an array of objects of the specified type.
//
// MR_RESIZE_ARRAY(ptr, type, num):
// Resizes the array, as with realloc().
//
// MR_malloc(bytes):
// Allocates the given number of bytes.
//
// MR_realloc(old, bytes):
// Allocates the given number of bytes, copies over the old contents of
// the previously allocated block pointed to by old, and then frees that
// old block.
//
// MR_ensure_big_enough_buffer(buffer_ptr, buffer_size_ptr, needed_size):
// Given a character buffer pointed to by buffer_ptr whose is given by
// *buffer_size_ptr, ensure that the buffer is big enough to hold
// needed_size characters. If it needs to make the block bigger,
// this function will update both *buffer_ptr and *buffer_size_ptr.
//
// MR_free(ptr):
// Deallocates the memory.
extern void *MR_malloc(size_t n);
extern void *MR_realloc(void *old, size_t n);
extern void MR_ensure_big_enough_buffer(char **buffer_ptr,
int *buffer_size_ptr, int needed_size);
#define MR_free(ptr) free(ptr)
#define MR_free_func free
#define MR_NEW(type) \
((type *) MR_malloc(sizeof(type)))
#define MR_NEW_ARRAY(type, num) \
((type *) MR_malloc((num) * sizeof(type)))
#define MR_RESIZE_ARRAY(ptr, type, num) \
((type *) MR_realloc((ptr), (num) * sizeof(type)))
// These routines all allocate memory that will be traced by the
// conservative garbage collector, if conservative GC is enabled.
// (For the native GC, you need to call MR_add_root() to register roots.)
// The pointer values they return are all guaranteed to be non-NULL.
// (If they cannot allocate the requested amount of memory,
// they abort the program instead of returning NULL.)
//
// MR_GC_NEW(type):
// Allocates space for an object of the specified type.
// If conservative GC is enabled, the object will be garbage collected
// when it is no longer referenced from GC-traced memory.
// Memory allocated with malloc() (or MR_malloc() or MR_NEW())
// is not GC-traced. Nor is thread-local storage.
//
// MR_GC_NEW_UNCOLLECTABLE(type):
// Allocates space for an object of the specified type.
// The object will not be garbage collected even if it is not referenced,
// or only referenced from thread-local storage or storage allocated
// with malloc(). It should be explicitly deallocated with MR_GC_free().
//
// MR_GC_NEW_ARRAY(type, num):
// Allocates space for an array of objects of the specified type.
//
// MR_GC_RESIZE_ARRAY(ptr, type, num):
// Resizes the array, as with realloc().
//
// MR_GC_malloc(num_bytes):
// Allocates the given number of bytes.
// If conservative GC is enabled, the memory will be garbage collected
// when it is no longer referenced from GC-traced memory (see above).
//
// MR_GC_malloc_atomic(num_bytes):
// Allocates the given number of bytes.
// Pointers to GC objects may not be stored in this object. This allows
// the GC to optimize its marking phase.
//
// MR_GC_malloc_uncollectable(num_bytes):
// Allocates the given number of bytes.
// The memory will not be garbage collected, and so it should be
// explicitly deallocated using MR_GC_free().
//
// MR_GC_realloc(ptr, num_bytes):
// Reallocates the memory block pointed to by ptr.
//
// MR_GC_free(ptr):
// Deallocates the memory.
//
// MR_GC_register_finalizer(ptr, finalize_func, data):
// When ptr is garbage collected invoke (*finalize_func)(ptr, data).
// ptr must have be a pointer to space allocated by the garbage collector.
// data is a pointer to some user-defined data.
// XXX currently this only works with the Boehm collector, i.e. in .gc
// grades, it is a no-op in non .gc grades.
//
// XXX this interface is subject to change.
//
// Note: consider using the _attrib variants below.
//
// MR_new_weak_ptr(ptr, object):
// Create a weak pointer to object and store it in the memory pointed to by
// ptr (a double pointer). object must have been allocated using one of
// the MR_GC methods. Weak pointers only work with the Boehm collector
// (.gc grades). In other grades this is an ordinary pointer.
//
// MR_weak_ptr_read(weak_ptr):
// Dereference a weak pointer. Returns NULL of the pointed to object has
// been deallocated. If weak_ptr is NULL then NULL is returned, so the
// programmer doesn't need to do an extra NULL check in case their pointer
// is deliberately NULL;
extern void *MR_GC_malloc(size_t num_bytes);
extern void *MR_GC_malloc_uncollectable(size_t num_bytes);
extern void *MR_GC_malloc_atomic(size_t num_bytes);
extern void *MR_GC_realloc(void *ptr, size_t num_bytes);
typedef void (*MR_GC_finalizer)(void *ptr, void *data);
#define MR_GC_NEW(type) \
((type *) MR_GC_malloc(sizeof(type)))
#define MR_GC_NEW_UNCOLLECTABLE(type) \
((type *) MR_GC_malloc_uncollectable(sizeof(type)))
#define MR_GC_NEW_ARRAY(type, num) \
((type *) MR_GC_malloc((num) * sizeof(type)))
#define MR_GC_RESIZE_ARRAY(ptr, type, num) \
((type *) MR_GC_realloc((ptr), (num) * sizeof(type)))
#ifdef MR_CONSERVATIVE_GC
#define MR_GC_free(ptr) GC_FREE(ptr)
#else
#define MR_GC_free(ptr) free(ptr)
#endif
#if defined(MR_CONSERVATIVE_GC) && defined(MR_BOEHM_GC)
#define MR_GC_register_finalizer(ptr, finalizer, data) \
GC_REGISTER_FINALIZER((ptr), (finalizer), (data), 0, 0)
#else
#define MR_GC_register_finalizer(ptr, finalizer, data)
#endif
// Don't dereference a weak pointer directly, it won't work as the pointer
// is hidden from the GC by storing its negated bits.
#ifdef MR_BOEHM_GC
#define MR_NULL_WEAK_PTR 0
typedef GC_hidden_pointer MR_weak_ptr;
#else
#define MR_NULL_WEAK_PTR NULL
typedef void* MR_weak_ptr;
#endif
// Create a weak pointer to obj and store the pointer in the memory pointed
// to by weak_ptr, which must be a pointer to an MR_weak_ptr. obj must not
// be an internal pointer and weak_ptr must be located within a heap object
// managed by the GC.
#ifdef MR_BOEHM_GC
#define MR_new_weak_ptr(weak_ptr, obj) \
do { \
int result; \
\
*(weak_ptr) = GC_HIDE_POINTER((obj)); \
/* \
** This call takes a double pointer, so it can clear the \
** user's pointer. Recall that *weak_ptr is a hidden pointer \
** a pointer cast to an int. \
*/ \
\
result = \
GC_general_register_disappearing_link((void**)(weak_ptr), (obj)); \
\
if (GC_DUPLICATE == result) { \
MR_fatal_error( \
"Error registering weak pointer: already registered"); \
} else if (GC_NO_MEMORY == result) { \
MR_fatal_error( \
"Error registering weak pointer: out of memory"); \
} \
} while (0)
#else
#define MR_new_weak_ptr(weak_ptr, obj) \
do { \
*(weak_ptr) = (obj); \
} while (0)
#endif
// Don't call this directly. It must be protected by Boehm's allocation lock,
// see MR_weak_ptr_read below.
#ifdef MR_BOEHM_GC
extern void*
MR_weak_ptr_read_unsafe(void* weak_ptr);
#endif
// Use this before dereferencing a weak pointer. weak_ptr must be a pointer
// to an MR_weak_ptr. This returns the real pointer that the weak pointer
// represents.
#ifdef MR_BOEHM_GC
#define MR_weak_ptr_read(weak_ptr) \
((MR_NULL_WEAK_PTR != *(weak_ptr)) ? \
GC_call_with_alloc_lock(MR_weak_ptr_read_unsafe, (weak_ptr)) : \
NULL)
#else
#define MR_weak_ptr_read(weak_ptr) \
(*(weak_ptr))
#endif
// MR_GC_NEW_ATTRIB(type, attrib):
// MR_GC_NEW_UNCOLLECTABLE_ATTRIB(type, attrib):
// MR_GC_NEW_ARRAY_ATTRIB(type, attrib):
// MR_GC_malloc_attrib(bytes, attrib):
// MR_GC_malloc_uncollectable_attrib(bytes, attrib):
// MR_GC_realloc_attrib(ptr, num_bytes):
// In grades with memory attribution support, these variants will allocate
// an extra word before the object. The value stored `attrib' is stored
// in that extra word.
//
// MR_GC_RESIZE_ARRAY_ATTRIB(ptr, type, num):
// MR_GC_free_attrib(ptr):
// These variants take into account the extra word before ptr.
// You must NOT pass pointers which were returned by non-"attrib"
// functions or macros to these "attrib" variants, and vice versa.
#define MR_GC_NEW_ATTRIB(type, attrib) \
((type *) MR_GC_malloc_attrib(sizeof(type), (attrib)))
#define MR_GC_NEW_UNCOLLECTABLE_ATTRIB(type, attrib) \
((type *) MR_GC_malloc_uncollectable_attrib(sizeof(type), (attrib)))
#define MR_GC_NEW_ARRAY_ATTRIB(type, num, attrib) \
((type *) MR_GC_malloc_attrib((num) * sizeof(type), (attrib)))
#define MR_GC_RESIZE_ARRAY_ATTRIB(ptr, type, num) \
((type *) MR_GC_realloc_attrib((ptr), (num) * sizeof(type)))
extern void *MR_GC_malloc_attrib(size_t num_bytes, void *attrib);
extern void *MR_GC_malloc_uncollectable_attrib(size_t num_bytes,
void *attrib);
extern void *MR_GC_realloc_attrib(void *ptr, size_t num_bytes);
extern void MR_GC_free_attrib(void *ptr);
struct MR_AllocSiteInfo_Struct {
MR_Code *MR_asi_proc;
const char *MR_asi_file_name;
const int MR_asi_line_number;
const char *MR_asi_type;
const int MR_asi_words;
};
// Builtin allocation site ids for use in the runtime and other
// hand-written code when context-specific ids are unavailable.
// MR_ALLOC_SITE_RUNTIME is a catch-all for internal runtime structures;
// these are hidden by default in `mprof -s' output.
#define MR_ALLOC_SITE_NONE ((void *) 0)
#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION
// These must match the entries in mercury_heap_profile.c.
extern MR_AllocSiteInfo MR_builtin_alloc_sites[9];
#define MR_ALLOC_SITE_RUNTIME ((void *) &MR_builtin_alloc_sites[0])
#define MR_ALLOC_SITE_FLOAT ((void *) &MR_builtin_alloc_sites[1])
#define MR_ALLOC_SITE_STRING ((void *) &MR_builtin_alloc_sites[2])
#define MR_ALLOC_SITE_TYPE_INFO ((void *) &MR_builtin_alloc_sites[3])
#define MR_ALLOC_SITE_FOREIGN ((void *) &MR_builtin_alloc_sites[4])
#define MR_ALLOC_SITE_TABLING ((void *) &MR_builtin_alloc_sites[5])
#define MR_ALLOC_SITE_STM ((void *) &MR_builtin_alloc_sites[6])
#define MR_ALLOC_SITE_INT64 ((void *) &MR_builtin_alloc_sites[7])
#define MR_ALLOC_SITE_UINT64 ((void *) &MR_builtin_alloc_sites[8])
#else
#define MR_ALLOC_ID MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_RUNTIME MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_FLOAT MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_STRING MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_TYPE_INFO MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_FOREIGN MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_TABLING MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_STM MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_INT64 MR_ALLOC_SITE_NONE
#define MR_ALLOC_SITE_UINT64 MR_ALLOC_SITE_NONE
#endif
extern void *MR_new_object_func(size_t num_bytes,
MR_AllocSiteInfoPtr alloc_id, const char *name);
extern void *MR_new_object_atomic_func(size_t num_bytes,
MR_AllocSiteInfoPtr alloc_id, const char *name);
////////////////////////////////////////////////////////////////////////////
// MR_copy_string makes a copy of the given string,
// using memory allocated with MR_malloc().
extern char *MR_copy_string(const char *s);
////////////////////////////////////////////////////////////////////////////
// `MR_unit' is the size of the minimum unit of memory we allocate (in bytes).
// `MR_page_size' is the size of a single page of memory.
extern size_t MR_unit;
extern size_t MR_page_size;
////////////////////////////////////////////////////////////////////////////
// Users need to call MR_add_root() for any global variable which contains
// pointers to the Mercury heap. This information is only used for agc grades.
#ifdef MR_NATIVE_GC
#define MR_add_root(root_ptr, type_info) \
MR_agc_add_root((root_ptr), (type_info))
#else
#define MR_add_root(root_ptr, type_info) // nothing
#endif
////////////////////////////////////////////////////////////////////////////
#endif // not MERCURY_MEMORY_H