mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-08 18:34:00 +00:00
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.
COPYING.LIB:
Add a special linking exception to the LGPL.
*:
Update references to COPYING.LIB.
Clean up some minor errors that have accumulated in copyright
messages.
402 lines
16 KiB
C
402 lines
16 KiB
C
// vim: ts=4 sw=4 expandtab ft=c
|
|
|
|
// Copyright (C) 1999-2006, 2011 The University of Melbourne.
|
|
// Copyright (C) 2014, 2015-2016, 2018 The Mercury team.
|
|
// This file is distributed under the terms specified in COPYING.LIB.
|
|
|
|
// mercury.h - This file defines the macros, types, etc. that
|
|
// are used when generating high-level C code.
|
|
// (For the low-level C code, see mercury_imp.h.)
|
|
|
|
#ifndef MERCURY_H
|
|
#define MERCURY_H
|
|
|
|
// Everything in this file is specific to the high-level-code back-end
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Header files to include.
|
|
|
|
#include "mercury_conf.h"
|
|
#include "mercury_types.h"
|
|
#include "mercury_float.h" // for the `MR_Float' type
|
|
#include "mercury_int.h"
|
|
#include "mercury_tags.h"
|
|
#include "mercury_grade.h"
|
|
#include "mercury_thread.h" // for the MR_*_GLOBAL_LOCK() macros
|
|
#include "mercury_std.h" // for the MR_CALL macro (and others)
|
|
#include "mercury_type_info.h"
|
|
#include "mercury_builtin_types.h"
|
|
#include "mercury_library_types.h" // for MercuryFilePtr, for files
|
|
// that use the type in io.m, whose
|
|
// foreign_type is MercuryFilePtr XXX
|
|
#include "mercury_ho_call.h" // for the `MR_Closure' type
|
|
#include "mercury_memory.h" // for memory allocation routines
|
|
#include "mercury_type_tables.h" // for MR_register_type_ctor_info
|
|
#include "mercury_misc.h" // for MR_fatal_error()
|
|
|
|
#ifdef MR_CONSERVATIVE_GC
|
|
#ifdef MR_BOEHM_GC
|
|
#include "gc.h"
|
|
#define GC_I_HIDE_POINTERS
|
|
#ifdef MR_INLINE_ALLOC
|
|
#include "gc_inline.h"
|
|
#endif
|
|
#endif
|
|
#else
|
|
#include "mercury_regs.h" // for MR_hp
|
|
#include "mercury_engine.h" // for MR_fake_reg (needed by MR_hp)
|
|
#include "mercury_overflow.h" // for MR_heap_overflow_check()
|
|
#ifdef MR_NATIVE_GC
|
|
#include "mercury_accurate_gc.h" // for MR_garbage_collect()
|
|
#include "mercury_layout_util.h" // for MR_materialize_closure...()
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(MR_MPROF_PROFILE_CALLS) || defined(MR_MPROF_PROFILE_TIME)
|
|
#include "mercury_prof.h" // for MR_prof_call_profile
|
|
// and MR_set_prof_current_proc
|
|
#endif
|
|
|
|
#ifdef MR_MPROF_PROFILE_MEMORY
|
|
#include "mercury_heap_profile.h" // for MR_record_allocation
|
|
#endif
|
|
|
|
#if defined(MR_MPROF_PROFILE_CALLS) || defined(MR_MPROF_PROFILE_MEMORY) || defined(MR_MPROF_PROFILE_TIME)
|
|
#include "mercury_goto.h" // for MR_init_entry
|
|
#endif
|
|
|
|
#include <setjmp.h> // for jmp_buf etc., which are used for commits
|
|
#include <string.h> // for strcmp(), which is used for =/2 on strings
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Type definitions.
|
|
|
|
// The jmp_buf type used by MR_builtin_setjmp()
|
|
// to save the stack context when implementing commits.
|
|
|
|
#ifdef MR_GNUC
|
|
// For GCC, we use `__builtin_setjmp' and `__builtin_longjmp'.
|
|
// These are documented (in gcc/builtins.c in the GCC source code)
|
|
// as taking for their parameter a pointer to an array of five words.
|
|
|
|
typedef void *MR_builtin_jmp_buf[5];
|
|
#else
|
|
// Otherwise we use the standard jmp_buf type.
|
|
typedef jmp_buf MR_builtin_jmp_buf;
|
|
#endif
|
|
|
|
// The chain of stack frames, used for accurate GC.
|
|
//
|
|
// Any changes to this struct may require changes to compiler/ml_elim_nested.m,
|
|
// which generates structs that whose initial members have to match the layout
|
|
// here, and which assumes that the `prev' is at offset zero.
|
|
|
|
struct MR_StackChain {
|
|
struct MR_StackChain *prev;
|
|
void (*trace)(void *this_frame);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Declarations of constants and variables.
|
|
|
|
#ifdef MR_NATIVE_GC
|
|
// This points to the start of the MR_StackChain frame list.
|
|
//
|
|
// XXX Using a global variable for this is not thread-safe.
|
|
// We could use a GNU C global register variable to hold it instead,
|
|
// but we don't have enough of those on x86s to allow us to spare one
|
|
// for this purpose.
|
|
|
|
#ifdef MR_THREAD_SAFE
|
|
#error "Sorry, not supported: --gc accurate --thread-safe"
|
|
#endif
|
|
extern void *mercury__private_builtin__stack_chain;
|
|
#endif
|
|
|
|
// Declare the TypeCtorInfos of the library types that are not already declared
|
|
// in mercury_builtin_types.h
|
|
|
|
MR_DECLARE_TYPE_CTOR_INFO_STRUCT(
|
|
mercury__array__array__type_ctor_info_array_1);
|
|
MR_DECLARE_TYPE_CTOR_INFO_STRUCT(
|
|
mercury__univ__univ__type_ctor_info_univ_0);
|
|
|
|
// When generating code which passes an io.state or a store.store to a
|
|
// polymorphic procedure, or which does a higher-order call that passes
|
|
// one of these, then we need to generate a reference to a dummy variable.
|
|
// We use this variable for that purpose.
|
|
|
|
extern MR_Word mercury__private_builtin__dummy_var;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Macros and inline function definitions.
|
|
|
|
// These macros expand to the either the standard setjmp()/longjmp()
|
|
// or to the GNU __builtin_setjmp() and __builtin_longjmp().
|
|
// The GNU versions are the same as the standard versions,
|
|
// except that they are more efficient, and that they have two restrictions:
|
|
//
|
|
// 1. The second argument to __builtin_longjmp() must always be `1'.
|
|
// 2. The call to __builtin_longjmp() must not be in the same
|
|
// function as the call to __builtin_setjmp().
|
|
|
|
#if (MR_GNUC > 2 || (MR_GNUC == 2 && __GNUC_MINOR__ >= 8))
|
|
#ifndef MR_DARWIN_SETJMP_WORKAROUND
|
|
#define MR_builtin_setjmp(buf) __builtin_setjmp((buf))
|
|
#define MR_builtin_longjmp(buf, val) __builtin_longjmp((buf), (val))
|
|
#endif
|
|
#endif
|
|
#ifndef MR_builtin_setjmp
|
|
#define MR_builtin_setjmp(buf) setjmp((buf))
|
|
#define MR_builtin_longjmp(buf, val) longjmp((buf), (val))
|
|
#endif
|
|
|
|
// MR_new_object():
|
|
// Allocates memory on the garbage-collected heap.
|
|
|
|
#ifdef MR_BOEHM_GC
|
|
#ifdef MR_INLINE_ALLOC
|
|
#ifndef MR_GNUC
|
|
#error "MR_INLINE_ALLOC requires GNU C"
|
|
#endif
|
|
// This must be a macro, not an inline function, because GNU C's
|
|
// `__builtin_constant_p' does not work inside inline functions.
|
|
|
|
#define MR_GC_MALLOC_INLINE(bytes) \
|
|
( __extension__ __builtin_constant_p(bytes) && \
|
|
(bytes) <= 16 * sizeof(MR_Word) \
|
|
? ({ \
|
|
void *temp; \
|
|
/* If size > 1 word, round up to multiple of 8 bytes. */ \
|
|
MR_Word rounded_bytes = \
|
|
( (bytes) <= sizeof(MR_Word) \
|
|
? sizeof(MR_Word) \
|
|
: 8 * (((bytes) + 7) / 8) \
|
|
); \
|
|
MR_Word num_words = rounded_bytes / sizeof(MR_Word); \
|
|
GC_MALLOC_WORDS(temp, num_words); \
|
|
/* return */ temp; \
|
|
}) \
|
|
: GC_MALLOC(bytes) \
|
|
)
|
|
#define MR_new_object(type, size, alloc_id, name) \
|
|
((type *) MR_GC_MALLOC_INLINE(size))
|
|
// Since the Boehm collector defined GC_MALLOC_WORDS but not
|
|
// GC_MALLOC_WORDS_ATOMIC, we can define MR_new_object_atomic here
|
|
// to call either MR_GC_MALLOC_ATOMIC or MR_GC_MALLOC_INLINE,
|
|
// depending on whether we value atomicity or inline expansion more.
|
|
// XXX The above is out-of-date: Boehm GC does now provide
|
|
// GC_MALLOC_ATOMIC_WORDS.
|
|
// XXX We don't provide MR_GC_MALLOC_ATOMIC.
|
|
|
|
#define MR_new_object_atomic(type, size, alloc_id, name) \
|
|
((type *) GC_MALLOC_ATOMIC(size))
|
|
#else // !MR_INLINE_ALLOC
|
|
|
|
#ifdef MR_MPROF_PROFILE_MEMORY_ATTRIBUTION
|
|
#define MR_new_object(type, size, alloc_id, name) \
|
|
((type *) MR_new_object_func(size, alloc_id, name))
|
|
#define MR_new_object_atomic(type, size, alloc_id, name) \
|
|
((type *) MR_new_object_atomic_func(size, alloc_id, name))
|
|
#else
|
|
#define MR_new_object(type, size, alloc_id, name) \
|
|
((type *) GC_MALLOC(size))
|
|
#define MR_new_object_atomic(type, size, alloc_id, name) \
|
|
((type *) GC_MALLOC_ATOMIC(size))
|
|
#endif
|
|
#endif // !MR_INLINE_ALLOC
|
|
|
|
#else // !MR_BOEHM_GC
|
|
|
|
#if !defined(MR_GNUC) && !defined(MR_CLANG)
|
|
// We need GNU C's `({...})' expressions.
|
|
// It's not worth worrying about compilers other than GCC or clang for
|
|
// this obscure combination of options.
|
|
|
|
#error "For C compilers other than GCC or clang, `--high-level-code' requires `--gc boehm'"
|
|
#endif
|
|
|
|
// XXX Note that currently we don't need to worry about alignment here,
|
|
// other than word alignment, because floating point fields will be boxed
|
|
// if they don't fit in a word. This would need to change if we ever start
|
|
// using unboxed fields whose alignment requirement is greater than one word.
|
|
|
|
#define MR_new_object(type, size, alloc_id, name) \
|
|
({ \
|
|
size_t MR_new_object_num_words; \
|
|
MR_Word MR_new_object_ptr; \
|
|
\
|
|
MR_new_object_num_words = MR_bytes_to_words(size); \
|
|
MR_incr_hp_msg(MR_new_object_ptr, MR_new_object_num_words, \
|
|
(alloc_id), (name)); \
|
|
/* return */ (type *) MR_new_object_ptr; \
|
|
})
|
|
#define MR_new_object_atomic(type, size, alloc_id, name) \
|
|
MR_new_object(type, size, alloc_id, name)
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Code to box/unbox floats in high-level C grades.
|
|
// The low-level C grades only use MR_float_to_word and MR_word_to_float.
|
|
//
|
|
// This code is not in mercury_float.h because the function definition
|
|
// requires the declaration of MR_new_object_atomic.
|
|
//
|
|
// When sizeof(MR_Float) <= sizeof(MR_Box), the names "box" and "unbox" should
|
|
// be interpreted as casts to and from MR_Box, as we do not truly box the
|
|
// floats then.
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
#ifdef MR_BOXED_FLOAT
|
|
|
|
#if defined(MR_GNUC)
|
|
#define MR_box_float(f) \
|
|
({ \
|
|
MR_Float *MR_box_float_ptr; \
|
|
\
|
|
MR_make_hp_float_aligned(); \
|
|
MR_box_float_ptr = (MR_Float *) MR_new_object_atomic(MR_Float,\
|
|
sizeof(MR_Float), MR_ALLOC_SITE_FLOAT, NULL); \
|
|
*MR_box_float_ptr = (f); \
|
|
/* return */ (MR_Box) MR_box_float_ptr; \
|
|
})
|
|
#else
|
|
// Note that this code is also duplicated in mercury.c.
|
|
MR_EXTERN_INLINE MR_Box MR_box_float(MR_Float f);
|
|
|
|
MR_EXTERN_INLINE MR_Box
|
|
MR_box_float(MR_Float f)
|
|
{
|
|
MR_Float *ptr;
|
|
|
|
MR_make_hp_float_aligned();
|
|
ptr = MR_new_object_atomic(MR_Float, sizeof(MR_Float),
|
|
MR_ALLOC_SITE_FLOAT, NULL);
|
|
*ptr = f;
|
|
return (MR_Box) ptr;
|
|
}
|
|
#endif
|
|
|
|
#define MR_unbox_float(ptr) (*(MR_Float *)ptr)
|
|
|
|
#else // ! MR_BOXED_FLOAT
|
|
|
|
#define MR_box_float(F) ((MR_Box) MR_float_to_word(F))
|
|
#define MR_unbox_float(B) MR_word_to_float((MR_Word)(B))
|
|
|
|
#endif // ! MR_BOXED_FLOAT
|
|
|
|
#endif // MR_HIGHLEVEL_CODE
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Code to box/unbox 64-bit integers in high-level C grades.
|
|
// The low-level C grades only use MR_{int64,uint64)_to_word and
|
|
// MR_word_to_{int64,uint64}.
|
|
//
|
|
// This code is not in mercury_int.h because the function definition
|
|
// requires the declaration of MR_new_object_atomic.
|
|
//
|
|
// When sizeof(int64_t) <= sizeof(MR_Box), the names "box" and "unbox" should
|
|
// be interpreted as casts to and from MR_Box, as we do not truly box the
|
|
// 64-bit integers then.
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
#if defined(MR_BOXED_INT64S)
|
|
|
|
#if defined(MR_GNUC)
|
|
#define MR_box_int64(i) \
|
|
({ \
|
|
int64_t *MR_box_int64_ptr; \
|
|
\
|
|
MR_make_hp_int64_aligned(); \
|
|
MR_box_int64_ptr = (int64_t *) MR_new_object_atomic(int64_t, \
|
|
sizeof(int64_t), MR_ALLOC_SITE_INT64, NULL); \
|
|
*MR_box_int64_ptr = (i); \
|
|
/* return */ (MR_Box) MR_box_int64_ptr; \
|
|
})
|
|
#define MR_box_uint64(i) \
|
|
({ \
|
|
uint64_t *MR_box_uint64_ptr; \
|
|
\
|
|
MR_make_hp_uint64_aligned(); \
|
|
MR_box_uint64_ptr = (uint64_t *) MR_new_object_atomic(uint64_t, \
|
|
sizeof(uint64_t), MR_ALLOC_SITE_UINT64, NULL); \
|
|
*MR_box_uint64_ptr = (i); \
|
|
/* return */ (MR_Box) MR_box_uint64_ptr; \
|
|
})
|
|
#else
|
|
// Note that this code is also duplicated in mercury.c.
|
|
MR_EXTERN_INLINE MR_Box MR_box_int64(int64_t i);
|
|
MR_EXTERN_INLINE MR_Box MR_box_uint64(uint64_t i);
|
|
|
|
MR_EXTERN_INLINE MR_Box
|
|
MR_box_int64(int64_t i)
|
|
{
|
|
int64_t *ptr;
|
|
|
|
MR_make_hp_int64_aligned();
|
|
ptr = MR_new_object_atomic(int64_t, sizeof(int64_t),
|
|
MR_ALLOC_SITE_INT64, NULL);
|
|
*ptr = i;
|
|
return (MR_Box) ptr;
|
|
}
|
|
|
|
MR_EXTERN_INLINE MR_Box
|
|
MR_box_uint64(uint64_t i)
|
|
{
|
|
uint64_t *ptr;
|
|
|
|
MR_make_hp_uint64_aligned();
|
|
ptr = MR_new_object_atomic(uint64_t, sizeof(uint64_t),
|
|
MR_ALLOC_SITE_UINT64, NULL);
|
|
*ptr = i;
|
|
return (MR_Box) ptr;
|
|
}
|
|
#endif
|
|
|
|
#define MR_unbox_int64(ptr) (*(int64_t *) ptr)
|
|
#define MR_unbox_uint64(ptr) (*(uint64_t *) ptr)
|
|
|
|
#else // not MR_BOXED_INT64S
|
|
|
|
#define MR_box_int64(I) ((MR_Box) MR_int64_to_word(I))
|
|
#define MR_unbox_int64(B) MR_word_to_int64((MR_Word) (B))
|
|
#define MR_box_uint64(I) ((MR_Box) MR_uint64_to_word(I))
|
|
#define MR_unbox_uint64(B) MR_word_to_uint64((MR_Word) (B))
|
|
|
|
#endif // not MR_BOXED_INT64S
|
|
#endif // MR_HIGHLEVEL_CODE
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// MR_GC_check():
|
|
// Check to see if we need to do a garbage collection, and if so, do it.
|
|
|
|
#define MR_GC_check() \
|
|
do { \
|
|
if ((char *) MR_hp >= \
|
|
MR_ENGINE(MR_eng_heap_zone)->MR_zone_gc_threshold) \
|
|
{ \
|
|
MR_save_registers(); \
|
|
MR_garbage_collect(); \
|
|
MR_restore_registers(); \
|
|
} \
|
|
} while (0)
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The #include of mercury_heap.h needs to come *after* the definition
|
|
// of MR_new_object(), because mercury_heap.h defines some inline
|
|
// functions that reference MR_new_object(). So does mercury_string.h.
|
|
// mercury_univ.h includes mercury_heap.h.
|
|
|
|
#include "mercury_heap.h" // for MR_MAYBE_(UN)BOX_FOREIGN_TYPE()
|
|
#include "mercury_univ.h"
|
|
#include "mercury_string.h" // for MR_nth_code_unit/MR_offset_streq()
|
|
|
|
#endif // MR_HIGHLEVEL_CODE
|
|
|
|
#endif // not MERCURY_H
|