Files
mercury/runtime/mercury_heap.h
Julien Fischer 8af00f7a2a Avoid using the __GNUC__ macro in the runtime as a test for the presence of
Branches: main, 11.07

Avoid using the __GNUC__ macro in the runtime as a test for the presence of
gcc, since clang also defines that macro.  Since clang doesn't support all
of the GNU C extensions, we can't actually use __GNUC__ without also checking
whether we are actually using clang.

runtime/mercury_conf_param.h:
	Add three new macros, MR_CLANG, MR_GNUC and MR_MSVC that are defined
	only when the C compiler is clang, gcc, or Visual C respectively.
	(In particular, MR_GNUC will _not_ be defined when the C compiler
	is clang.)

runtime/mercury.c:
runtime/mercury.h:
runtime/mercury_atomic_ops.c:
runtime/mercury_atomic_ops.h
runtime/mercury_bitmap.h:
runtime/mercury_float.h:
runtime/mercury_getopt.c:
runtime/mercury_goto.h:
runtime/mercury_heap.h:
runtime/mercury_std.h:
	Replace uses of the __GNUC__ and __clang__ macros with the above.

runtime/mercury_regs.h:
	As above, also #include mercury_conf_param.h directly since
	this file is #included by some of the tests in the configure
	script.
2011-08-01 07:06:21 +00:00

797 lines
39 KiB
C

/*
** vim: ts=4 sw=4 et
*/
/*
** Copyright (C) 1995-2006, 2010-2011 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.
*/
/*
** mercury_heap.h - definitions for manipulating the Mercury heap.
**
** This file defines several levels of macros for allocating space on
** the Mercury heap.
**
** It would be simpler if all these macros expanded out to statements. However,
** many cannot, since they must be usable inside expressions. The ultimate
** reason for this is MR_float_to_word, which is used not just as an operand
** in expressions, but also as an initializer in static cells generated
** by the compiler.
*/
#ifndef MERCURY_HEAP_H
#define MERCURY_HEAP_H
#include "mercury_conf.h" /* for MR_CONSERVATIVE_GC */
#include "mercury_conf_param.h" /* for MR_RECORD_TERM_SIZES */
#include "mercury_types.h" /* for `MR_Word' */
#include "mercury_context.h" /* for min_heap_reclamation_point() */
#include "mercury_heap_profile.h" /* for MR_record_allocation() */
#include "mercury_deep_profiling.h" /* for MR_current_call_site_dynamic */
#include "mercury_std.h" /* for MR_EXTERN_INLINE */
#include "mercury_reg_workarounds.h" /* for MR_memcpy */
#include "mercury_debug.h" /* for MR_debugtagoffsetincrhp* */
#ifdef MR_HIGHLEVEL_CODE
#include "mercury.h" /* for MR_new_object() */
#endif
#ifdef MR_CONSERVATIVE_GC
#ifdef MR_MPS_GC
#include "mercury_mps.h"
#endif
#ifdef MR_HGC
#include "mercury_hgc.h"
#endif
#ifdef MR_BOEHM_GC
#define GC_I_HIDE_POINTERS
#include "gc.h"
#include "gc_mark.h" /* for GC_least_plausible_heap_addr */
/* GC_greatest_plausible_heap_addr */
#endif
#endif
/***************************************************************************/
/*
** The first level of heap allocation macros. These are concerned with
** the raw business of allocating memory, taking and restoring snapshots
** of the state of the heap, and recording profiling information for the
** profdeep grade and complexity experiments.
*/
#ifdef MR_DEBUG_HEAP_ALLOC
#define MR_tag_offset_sanity_check(offset, count) \
( ((offset) >= (count)) \
? MR_fatal_error("MR_tag_offset_sanity_check failed") \
: ((void) 0) \
)
#else
#define MR_tag_offset_sanity_check(offset, count) \
((void) 0)
#endif
#ifdef MR_RECORD_TERM_SIZES
#define MR_maybe_increment_complexity_counters(count) \
( \
MR_complexity_word_counter += (count), \
MR_complexity_cell_counter += 1 \
)
#else
#define MR_maybe_increment_complexity_counters(count) \
((void) 0)
#endif
#if defined (MR_DEEP_PROFILING) && defined(MR_DEEP_PROFILING_MEMORY)
#define MR_profdeep_maybe_record_allocation(count) \
( \
MR_current_call_site_dynamic->MR_csd_own.MR_own_allocs += 1,\
MR_current_call_site_dynamic->MR_csd_own.MR_own_words \
+= (count) \
)
#else
#define MR_profdeep_maybe_record_allocation(count) \
((void) 0)
#endif
#ifdef MR_CONSERVATIVE_GC
#define MR_tag_offset_incr_hp_base(dest, tag, offset, count, alloc, \
is_atomic) \
( \
MR_tag_offset_sanity_check((offset), (count)), \
MR_maybe_increment_complexity_counters((count)), \
MR_profdeep_maybe_record_allocation((count)), \
(dest) = (MR_Word) MR_mkword((tag), (MR_Word) \
(((MR_Word *) alloc((count) * sizeof(MR_Word))) \
+ (offset))), \
MR_debug_tag_offset_incr_hp_base((dest), (tag), (offset), \
(count), (is_atomic)), \
((void) 0) \
)
#define MR_tag_offset_incr_hp_n(dest, tag, offset, count) \
MR_tag_offset_incr_hp_base(dest, tag, offset, count, \
GC_MALLOC, 0)
#define MR_tag_offset_incr_hp_atomic(dest, tag, offset, count) \
MR_tag_offset_incr_hp_base(dest, tag, offset, count, \
GC_MALLOC_ATOMIC, 1)
#ifdef MR_INLINE_ALLOC
/*
** The following stuff uses the macros in the `gc_inline.h' header file in
** the Boehm garbage collector. They improve performance a little for
** highly allocation-intensive programs (e.g. the `nrev' benchmark).
** You'll probably need to fool around with the `-I' options to get this
** to work. Also, you must make sure that you compile with the same
** setting for -DSILENT that the boehm_gc directory was compiled with.
**
** We only want to inline allocations if the allocation size is a
** compile-time constant. This should be true for almost all the code that
** we generate, but with GCC we can use the `__builtin_constant_p()'
** extension to find out.
**
** The inline allocation macros are used only for allocating amounts
** of less than 16 words, to avoid fragmenting memory by creating too
** many distinct free lists. The garbage collector also requires that
** if we're allocating more than one word, we round up to an even number
** of words.
*/
#ifndef MR_GNUC
/*
** Without the gcc extensions __builtin_constant_p() and ({...}),
** MR_INLINE_ALLOC would probably be a performance _loss_.
*/
#error "MR_INLINE_ALLOC requires the use of GCC"
#endif
#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION
#error "MR_INLINE_ALLOC and MR_MPROF_PROFILE_MEMORY_ATTRIBUTION both defined"
#endif
#include "gc_inline.h"
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
( __builtin_constant_p(count) && (count) < 16 \
? ({ \
void *temp; \
\
MR_tag_offset_sanity_check((offset), (count)), \
MR_maybe_increment_complexity_counters((count)), \
MR_profdeep_maybe_record_allocation((count)), \
/* if size > 1, round up to an even number of words */ \
MR_Word num_words = ((count) == 1 ? 1 : \
2 * (((count) + 1) / 2)); \
GC_MALLOC_WORDS(temp, num_words); \
temp = (void *) (((MR_Word *) temp) + (offset)); \
(dest) = (MR_Word) MR_mkword((tag), temp); \
}) \
: MR_tag_offset_incr_hp_n((dest), (tag), (offset), (count)) \
)
#else /* !MR_INLINE_ALLOC */
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
MR_tag_offset_incr_hp_n((dest), (tag), (offset), (count))
#endif /* MR_INLINE_ALLOC */
#define MR_mark_hp(dest) ((void) 0)
#define MR_restore_hp(src) ((void) 0)
#define MR_free_heap(ptr) \
do { \
MR_Word *tmp = (MR_Word *) (ptr); \
if (MR_in_heap_range(tmp)) { \
GC_FREE(tmp); \
} \
} while (0)
#else /* not MR_CONSERVATIVE_GC */
#define MR_tag_offset_incr_hp_base(dest, tag, offset, count, is_atomic) \
( \
MR_tag_offset_sanity_check((offset), (count)), \
MR_maybe_increment_complexity_counters((count)), \
MR_profdeep_maybe_record_allocation((count)), \
(dest) = (MR_Word) MR_mkword(tag, (MR_Word) \
(((MR_Word *) MR_hp) + (offset))), \
MR_debug_tag_offset_incr_hp_base((dest), (tag), (offset), \
(count), (is_atomic)), \
MR_hp_word = (MR_Word) (MR_hp + (count)), \
MR_heap_overflow_check(), \
(void) 0 \
)
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
MR_tag_offset_incr_hp_base((dest), (tag), (offset), (count), 0)
#define MR_tag_offset_incr_hp_atomic(dest, tag, offset, count) \
MR_tag_offset_incr_hp_base((dest), (tag), (offset), (count), 1)
#define MR_mark_hp(dest) ((dest) = MR_hp_word)
/*
** When restoring MR_hp, we must make sure that we don't truncate the heap
** further than it is safe to. We can only truncate it as far as
** min_heap_reclamation_point. See the comments in mercury_context.h next to
** the MR_set_min_heap_reclamation_point() macro.
*/
#define MR_restore_hp(src) \
( \
MR_hp_word = (MR_Word) (src), \
(void) 0 \
)
#if 0
#define MR_restore_hp(src) \
( \
MR_hp_word = (MR_Word) \
( (MR_Word) MR_min_hp_rec < (src) ? \
(src) : (MR_Word) MR_min_hp_rec ), \
(void) 0 \
)
#endif
#define MR_free_heap(ptr) ((void) 0)
#endif /* not MR_CONSERVATIVE_GC */
/***************************************************************************/
/*
** The second level of heap allocation macros. These are concerned with
** recording profiling information for memory profiling grades. Memory
** attribution profiling adds an extra word at the start of each object.
*/
#if defined(MR_MPROF_PROFILE_MEMORY)
#define MR_profmem_record_allocation(count, alloc_id, type) \
MR_record_allocation((count), (alloc_id), (type))
#else
#define MR_profmem_record_allocation(count, alloc_id, type) \
((void) 0)
#endif
#if defined(MR_MPROF_PROFILE_MEMORY_ATTRIBUTION)
#define MR_profmem_attrib_word (1)
#define MR_profmem_set_attrib(dest, tag, alloc_id) \
((MR_Word *) MR_strip_tag(dest))[-1] = (MR_Word) (alloc_id)
/*
** XXX This version causes gcc 4.4.4 on x86 to abort when
** compiling mercury_bitmap.c.
*/
/* MR_field((tag), (dest), 0) = (MR_Word) (alloc_id) */
/*
** Hand-written code must set the MR_asi_type field at runtime.
** When the type argument is NULL, as it is for generated code,
** the C compiler can optimise away the condition and assignment.
*/
#define MR_profmem_set_alloc_type(alloc_id, type) \
((alloc_id) != NULL && (type) != NULL && \
(((MR_AllocSiteInfo *) (alloc_id))->MR_asi_type = (type)))
#else
#define MR_profmem_attrib_word (0)
#define MR_profmem_set_attrib(dest, tag, alloc_id) \
((void) 0)
#define MR_profmem_set_alloc_type(alloc_id, type) \
((void) 0)
#endif
#define MR_tag_offset_incr_hp_msg(dest, tag, offset, count, \
alloc_id, type) \
( \
MR_tag_offset_incr_hp((dest), (tag), \
(offset) + MR_profmem_attrib_word, \
(count) + MR_profmem_attrib_word), \
MR_profmem_set_attrib((dest), (tag), (alloc_id)), \
MR_profmem_set_alloc_type((alloc_id), (type)), \
MR_profmem_record_allocation((count), (alloc_id), (type)) \
)
#define MR_tag_offset_incr_hp_atomic_msg(dest, tag, offset, count, \
alloc_id, type) \
( \
MR_tag_offset_incr_hp_atomic((dest), (tag), \
(offset) + MR_profmem_attrib_word, \
(count) + MR_profmem_attrib_word), \
MR_profmem_set_attrib((dest), (tag), (alloc_id)), \
MR_profmem_set_alloc_type((alloc_id), (type)), \
MR_profmem_record_allocation((count), (alloc_id), (type)) \
)
/***************************************************************************/
/*
** The third level of heap allocation macros. These are shorthands, supplying
** default values of some of the parameters of the previous macros.
*/
#define MR_tag_incr_hp(dest, tag, count) \
MR_tag_offset_incr_hp((dest), (tag), 0, (count))
#define MR_tag_incr_hp_atomic(dest, tag, count) \
MR_tag_offset_incr_hp_atomic((dest), (tag), 0, (count))
#define MR_tag_incr_hp_msg(dest, tag, count, alloc_id, type) \
MR_tag_offset_incr_hp_msg((dest), (tag), 0, (count), \
(alloc_id), (type))
#define MR_tag_incr_hp_atomic_msg(dest, tag, count, alloc_id, type) \
MR_tag_offset_incr_hp_atomic_msg((dest), (tag), 0, (count), \
(alloc_id), (type))
/*
** The MR_offset_incr_hp*() macros are defined in terms of the
** MR_tag_offset_incr_hp*() macros.
*/
#define MR_offset_incr_hp(dest, offset, count) \
MR_tag_offset_incr_hp((dest), MR_mktag(0), (offset), (count))
#define MR_offset_incr_hp_msg(dest, offset, count, alloc_id, type) \
MR_tag_offset_incr_hp_msg((dest), MR_mktag(0), \
(offset), (count), (alloc_id), (type))
#define MR_offset_incr_hp_atomic(dest, offset, count) \
MR_tag_offset_incr_hp_atomic((dest), MR_mktag(0), (offset), \
(count))
#define MR_offset_incr_hp_atomic_msg(dest, offset, count, alloc_id, \
type) \
MR_tag_offset_incr_hp_atomic_msg((dest), MR_mktag(0), (offset), \
(count), (alloc_id), (type))
#ifdef MR_CONSERVATIVE_GC
/* we use `MR_hp_word' as a convenient temporary here */
#define MR_hp_alloc(count) ( \
MR_offset_incr_hp(MR_hp_word, 0, (count)), \
MR_hp_word = (MR_Word) (MR_hp + (count)), \
(void) 0 \
)
#define MR_hp_alloc_atomic_msg(count, alloc_id, type) ( \
MR_offset_incr_hp_atomic_msg(MR_hp_word, 0, (count), \
(alloc_id), (type)), \
MR_hp_word = (MR_Word) (MR_hp + (count)), \
(void) 0 \
)
#else /* !MR_CONSERVATIVE_GC */
#define MR_hp_alloc(count) \
MR_offset_incr_hp(MR_hp_word, 0, (count))
#define MR_hp_alloc_atomic_msg(count, alloc_id, type) \
MR_offset_incr_hp_atomic_msg(MR_hp_word, 0, (count), \
(alloc_id), (type))
#endif /* MR_CONSERVATIVE_GC */
/***************************************************************************/
/*
** The fourth level of heap allocation macros. These implement the various
** cases of the incr_hp LLDS instruction, and look after recording term sizes.
*/
#ifndef MR_RECORD_TERM_SIZES
#define MR_incr_hp(dest, count) \
MR_offset_incr_hp((dest), 0, (count))
#define MR_incr_hp_msg(dest, count, alloc_id, type) \
MR_offset_incr_hp_msg((dest), 0, (count), (alloc_id), (type))
#define MR_incr_hp_atomic(dest, count) \
MR_offset_incr_hp_atomic((dest), 0, (count))
#define MR_incr_hp_atomic_msg(dest, count, alloc_id, type) \
MR_offset_incr_hp_atomic_msg((dest), 0, (count), (alloc_id), \
(type))
#endif
#define MR_incr_hp_type(dest, typename) \
do { \
MR_Word tmp; \
MR_tag_incr_hp(tmp, MR_mktag(0), \
(MR_bytes_to_words(sizeof(typename)))); \
(dest) = (typename *) tmp; \
} while (0)
#define MR_incr_hp_type_msg(dest, typename, alloc_id, type) \
do { \
MR_Word tmp; \
MR_tag_incr_hp_msg(tmp, MR_mktag(0), \
(MR_bytes_to_words(sizeof(typename))), \
(alloc_id), (type)); \
(dest) = (typename *) tmp; \
} while (0)
/*
** These are only used by the compiler in non-memory profiling grades,
** so do not have _msg equivalents. Avoid these in hand-written code.
*/
#define MR_alloc_heap(dest, count) \
MR_tag_offset_incr_hp((dest), MR_mktag(0), 0, (count))
#define MR_alloc_heap_atomic(dest, count) \
MR_tag_offset_incr_hp_atomic((dest), MR_mktag(0), 0, (count))
#define MR_tag_alloc_heap(dest, tag, count) \
MR_tag_offset_incr_hp((dest), MR_mktag(tag), 0, (count))
#define MR_tag_alloc_heap_atomic(dest, tag, count) \
MR_tag_offset_incr_hp_atomic((dest), MR_mktag(tag), 0, (count))
#ifdef MR_HIGHLEVEL_CODE
/* term size profiling is not supported with MR_HIGHLEVEL_CODE */
#define MR_SIZE_SLOT_SIZE 0
#define MR_cell_size(arity) 0
#define MR_define_size_slot(ptag, new, size) 0
#define MR_copy_size_slot(nptag, new, optag, old) 0
#else /* ! MR_HIGHLEVEL_CODE */
#ifdef MR_RECORD_TERM_SIZES
#define MR_SIZE_SLOT_SIZE 1
#ifdef MR_RECORD_TERM_SIZES_AS_CELLS
#define MR_cell_size(arity) 1
#else
#define MR_cell_size(arity) arity
#endif
#define MR_define_size_slot(ptag, new, size) \
do { \
MR_field(ptag, new, -1) = size; \
} while(0)
#define MR_copy_size_slot(nptag, new, optag, old) \
do { \
MR_field(nptag, new, -1) = MR_field(optag, old, -1); \
} while(0)
#else
#define MR_SIZE_SLOT_SIZE 0
#define MR_cell_size(arity) 0
#define MR_define_size_slot(ptag, new, size) 0
#define MR_copy_size_slot(nptag, new, optag, old) 0
#endif
#endif /* ! MR_HIGHLEVEL_CODE */
/***************************************************************************/
/*
** Macros to implement structure reuse, conditional on whether the structure
** to reuse is really dynamically allocated. If not, fall back to allocating
** a new object on the heap.
*/
#define MR_reuse_or_alloc_heap(dest, reuse, fallback_alloc) \
MR_tag_reuse_or_alloc_heap((dest), 0, (reuse), (fallback_alloc))
#define MR_reuse_or_alloc_heap_flag(dest, flag, reuse, fallback_alloc) \
MR_tag_reuse_or_alloc_heap((dest), 0, (flag), (reuse), \
(fallback_alloc))
#define MR_tag_reuse_or_alloc_heap(dest, tag, reuse, fallback_alloc) \
do { \
MR_bool dummy; \
MR_tag_reuse_or_alloc_heap_flag((dest), (tag), dummy, \
(reuse), (fallback_alloc)); \
(void) dummy; \
} while (0)
#if defined(MR_BOEHM_GC) && !defined(MR_UNCONDITIONAL_STRUCTURE_REUSE)
#define MR_in_heap_range(addr) \
((void *) (addr) >= GC_least_plausible_heap_addr && \
(void *) (addr) < GC_greatest_plausible_heap_addr) \
#else /* ! MR_BOEHM_GC || MR_UNCONDITIONAL_STRUCTURE_REUSE */
/*
** We don't have any way to check whether `addr' is dynamically allocated,
** so just assume that it is. For this to be safe `--static-ground-terms'
** needs to be disabled.
*/
#define MR_in_heap_range(addr) (MR_TRUE)
#endif /* ! MR_BOEHM_GC || MR_UNCONDITIONAL_STRUCTURE_REUSE */
#define MR_tag_reuse_or_alloc_heap_flag(dest, tag, flag, reuse_addr, \
fallback_alloc) \
do { \
MR_Word tmp = (reuse_addr); \
if (MR_in_heap_range(tmp)) { \
(dest) = (MR_Word) MR_mkword((tag), tmp); \
(flag) = MR_TRUE; \
} else { \
(fallback_alloc); \
(flag) = MR_FALSE; \
} \
} while (0)
#define MR_assign_if_in_heap(dest, addr) \
do { \
MR_Word tmp = (addr); \
(dest) = MR_in_heap_range(tmp) ? tmp : (MR_Word) NULL; \
} while (0)
/***************************************************************************/
/*
** Macros to box/unbox types declared with `pragma foreign_type'.
*/
/*
** void MR_MAYBE_BOX_FOREIGN_TYPE(type T, const T &value, MR_Box &box):
** Copy a value of type T from `value' to `box', boxing it if necessary
** (i.e. if type T won't fit in type MR_Box).
*/
#define MR_MAYBE_BOX_FOREIGN_TYPE(T, value, box) \
do { \
MR_CHECK_EXPR_TYPE((value), T); \
MR_CHECK_EXPR_TYPE((box), MR_Box); \
if (sizeof(T) == sizeof(MR_Box)) { \
(box) = * (MR_Box *) &(value); \
} else if (sizeof(T) > sizeof(MR_Box)) { \
MR_Word box_word; \
size_t size_in_words = \
(sizeof(T) + sizeof(MR_Word) - 1) / sizeof(MR_Word); \
/* XXX this assumes that nothing requires */ \
/* stricter alignment than MR_Float */ \
MR_make_hp_float_aligned(); \
/* \
** This assumes that we don't keep term sizes \
** in grades that use boxes. \
*/ \
MR_offset_incr_hp_msg(box_word, 0, size_in_words, \
MR_ALLOC_SITE_FOREIGN, NULL); \
box = (MR_Box) box_word; \
MR_assign_structure(*(T *)(box), (value)); \
MR_profmem_record_allocation(size_in_words, NULL, \
"foreign type: " MR_STRINGIFY(T)); \
} else { \
/* We can't take the address of `box' here, */ \
/* since it might be a global register. */ \
/* Hence we need to use a temporary copy. */ \
MR_Box box_copy; \
if (sizeof(T) < sizeof(MR_Box)) { \
/* make sure we don't leave any */ \
/* part of it uninitialized */ \
box_copy = 0; \
} \
MR_memcpy(&box_copy, &(value), sizeof(T)); \
(box) = box_copy; \
} \
} while (0)
/*
** void MR_MAYBE_UNBOX_FOREIGN_TYPE(type T, MR_Box box, T &value):
** Copy a value of type T from `box' to `value', unboxing it if necessary.
*/
#define MR_MAYBE_UNBOX_FOREIGN_TYPE(T, box, value) \
do { \
MR_CHECK_EXPR_TYPE((value), T); \
MR_CHECK_EXPR_TYPE((box), MR_Box); \
if (sizeof(T) > sizeof(MR_Word)) { \
MR_assign_structure((value), * (T *) (box)); \
} else { \
/* We can't take the address of `box' here, */ \
/* since it might be a global register. */ \
/* Hence we need to use a temporary copy. */ \
MR_Box box_copy = (box); \
if (sizeof(T) == sizeof(MR_Box)) { \
(value) = * (T *) &box_copy; \
} else { \
MR_memcpy(&(value), &box_copy, sizeof(T)); \
} \
} \
} while (0)
/***************************************************************************/
/*
** The rest of this file defines macros designed to help hand-written C code
** create cells on the heap. These macros can be used directly, or indirectly
** via macros built on top of them. mercury_string.h and mercury_tags.h define
** some such macros.
*/
#ifdef MR_HIGHLEVEL_CODE
/*
** Note that this code is also duplicated in mercury.c.
*/
MR_EXTERN_INLINE MR_Word MR_create1_func(MR_Word w1);
MR_EXTERN_INLINE MR_Word MR_create2_func(MR_Word w1, MR_Word w2);
MR_EXTERN_INLINE MR_Word MR_create3_func(MR_Word w1, MR_Word w2, MR_Word w3);
MR_EXTERN_INLINE MR_Word
MR_create1_func(MR_Word w1)
{
MR_Word *p;
p = (MR_Word *) MR_new_object(MR_Word, 1 * sizeof(MR_Word),
NULL, "create1");
p[0] = w1;
return (MR_Word) p;
}
MR_EXTERN_INLINE MR_Word
MR_create2_func(MR_Word w1, MR_Word w2)
{
MR_Word *p;
p = (MR_Word *) MR_new_object(MR_Word, 2 * sizeof(MR_Word),
NULL, "create2");
p[0] = w1;
p[1] = w2;
return (MR_Word) p;
}
MR_EXTERN_INLINE MR_Word
MR_create3_func(MR_Word w1, MR_Word w2, MR_Word w3)
{
MR_Word *p;
p = (MR_Word *) MR_new_object(MR_Word, 3 * sizeof(MR_Word),
NULL, "create3");
p[0] = w1;
p[1] = w2;
p[2] = w3;
return (MR_Word) p;
}
#define MR_create1(ti1, w1) \
MR_create1_func((w1))
#define MR_create2(ti1, w1, ti2, w2) \
MR_create2_func((w1), (w2))
#define MR_create3(ti1, w1, ti2, w2, ti3, w3) \
MR_create3_func((w1), (w2), (w3))
#define MR_create1_msg(ti1, w1, alloc_id, type) \
MR_create1((ti1), (w1))
#define MR_create2_msg(ti1, w1, ti2, w2, alloc_id, type) \
MR_create2((ti1), (w1), (ti2), (w2))
#define MR_create3_msg(ti1, w1, ti2, w2, ti3, w3, alloc_id, type) \
MR_create3((ti1), (w1), (ti2), (w2), (ti3), (w3))
#else /* ! MR_HIGHLEVEL_CODE */
#ifdef MR_RECORD_TERM_SIZES
#define MR_fill_create1_size(hp, ti1, w1) \
( \
hp[-2] = MR_term_size(ti1, w1) + MR_cell_size(1) \
)
#define MR_fill_create2_size(hp, ti1, w1, ti2, w2) \
( \
hp[-3] = MR_term_size(ti1, w1) + MR_term_size(ti2, w2) \
+ MR_cell_size(2) \
)
#define MR_fill_create3_size(hp, ti1, w1, ti2, w2, ti3, w3) \
( \
hp[-4] = MR_term_size(ti1, w1) + MR_term_size(ti2, w2) \
+ MR_term_size(ti3, w3) + MR_cell_size(3) \
)
#else
#define MR_fill_create1_size(hp, ti1, w1) 0
#define MR_fill_create2_size(hp, ti1, w1, ti2, w2) 0
#define MR_fill_create3_size(hp, ti1, w1, ti2, w2, ti3, w3) 0
#endif
#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION
#define MR_fill_create1_origin(hp, alloc_id) \
(hp[-2] = (MR_Word) (alloc_id))
#define MR_fill_create2_origin(hp, alloc_id) \
(hp[-3] = (MR_Word) (alloc_id))
#define MR_fill_create3_origin(hp, alloc_id) \
(hp[-4] = (MR_Word) (alloc_id))
#else
#define MR_fill_create1_origin(hp, alloc_id) ((void) 0)
#define MR_fill_create2_origin(hp, alloc_id) ((void) 0)
#define MR_fill_create3_origin(hp, alloc_id) ((void) 0)
#endif
/*
** Note that gcc optimizes `hp += 2; return hp - 2;'
** to `tmp = hp; hp += 2; return tmp;', so we don't need to use
** gcc's expression statements in the code below.
*/
/* used only by hand-written code not by the automatically generated code */
#define MR_create1(ti1, w1) \
( \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 1), \
MR_hp[-1] = (MR_Word) (w1), \
MR_fill_create1_size(MR_hp, ti1, w1), \
MR_debugcr1(MR_hp), \
/* return */ (MR_Word) (MR_hp - 1) \
)
/* used only by hand-written code not by the automatically generated code */
#define MR_create2(ti1, w1, ti2, w2) \
( \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 2), \
MR_hp[-2] = (MR_Word) (w1), \
MR_hp[-1] = (MR_Word) (w2), \
MR_fill_create2_size(MR_hp, ti1, w1, ti2, w2), \
MR_debugcr2(MR_hp), \
/* return */ (MR_Word) (MR_hp - 2) \
)
/* used only by hand-written code not by the automatically generated code */
#define MR_create3(ti1, w1, ti2, w2, ti3, w3) \
( \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 3), \
MR_hp[-3] = (MR_Word) (w1), \
MR_hp[-2] = (MR_Word) (w2), \
MR_hp[-1] = (MR_Word) (w3), \
MR_fill_create3_size(MR_hp, ti1, w1, ti2, w2, ti3, w3), \
MR_debugcr3(MR_hp), \
/* return */ (MR_Word) (MR_hp - 3) \
)
/* used only by hand-written code not by the automatically generated code */
#define MR_create1_msg(ti1, w1, alloc_id, type) \
( \
MR_profmem_record_allocation(MR_SIZE_SLOT_SIZE + 1, \
(alloc_id), (type)), \
MR_profmem_set_alloc_type((alloc_id), (type)), \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 1 + MR_profmem_attrib_word),\
MR_hp[-1] = (MR_Word) (w1), \
MR_fill_create1_size(MR_hp, ti1, w1), \
MR_fill_create1_origin(MR_hp, (alloc_id)), \
MR_debugcr1(MR_hp), \
/* return */ (MR_Word) (MR_hp - 1) \
)
/* used only by hand-written code not by the automatically generated code */
#define MR_create2_msg(ti1, w1, ti2, w2, alloc_id, type) \
( \
MR_profmem_record_allocation(MR_SIZE_SLOT_SIZE + 2, \
(alloc_id), (type)), \
MR_profmem_set_alloc_type((alloc_id), (type)), \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 2 + MR_profmem_attrib_word),\
MR_hp[-2] = (MR_Word) (w1), \
MR_hp[-1] = (MR_Word) (w2), \
MR_fill_create2_size(MR_hp, ti1, w1, ti2, w2), \
MR_fill_create2_origin(MR_hp, (alloc_id)), \
MR_debugcr2(MR_hp), \
/* return */ (MR_Word) (MR_hp - 2) \
)
/* used only by hand-written code not by the automatically generated code */
#define MR_create3_msg(ti1, w1, ti2, w2, ti3, w3, alloc_id, type) \
( \
MR_profmem_record_allocation(MR_SIZE_SLOT_SIZE + 3, \
(alloc_id), (type)), \
MR_profmem_set_alloc_type((alloc_id), (type)), \
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 3 + MR_profmem_attrib_word),\
MR_hp[-3] = (MR_Word) (w1), \
MR_hp[-2] = (MR_Word) (w2), \
MR_hp[-1] = (MR_Word) (w3), \
MR_fill_create3_size(MR_hp, ti1, w1, ti2, w2, ti3, w3), \
MR_fill_create3_origin(MR_hp, (alloc_id)), \
MR_debugcr3(MR_hp), \
/* return */ (MR_Word) (MR_hp - 3) \
)
#endif /* ! MR_HIGHLEVEL_CODE */
/*
** Indended for use in handwritten C code where the Mercury registers
** may have been clobbered due to C function calls (eg, on the SPARC due
** to sliding register windows).
** Remember to MR_save_transient_hp() before calls to such code, and
** MR_restore_transient_hp() after.
**
** There are intentionally no versions that do not specify an offset;
** this is to force anyone who wants to allocate cells on the saved heap
** to think about the implications of their code for term size profiling.
*/
#define MR_offset_incr_saved_hp(dest, offset, count, alloc_id, type) \
do { \
MR_restore_transient_hp(); \
MR_offset_incr_hp_msg((dest), (offset), (count), \
(alloc_id), (type)); \
MR_save_transient_hp(); \
} while (0)
#define MR_offset_incr_saved_hp_atomic(dest, offset, count, alloc_id, type) \
do { \
MR_restore_transient_hp(); \
MR_offset_incr_hp_atomic_msg((dest), (offset), (count), \
(alloc_id), (type)); \
MR_save_transient_hp(); \
} while (0)
#endif /* not MERCURY_HEAP_H */