builtin: compile the gc statically by default (#14063)
parent
56a3539ea9
commit
775c4c34b5
|
@ -131,7 +131,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv
|
./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||||
./testcase_leak 2>leaks.txt
|
./testcase_leak 2>leaks.txt
|
||||||
grep "Found 1 leaked object" leaks.txt && grep ", sz=1000," leaks.txt
|
grep "Found 1 leaked object" leaks.txt && grep -P ", sz=\s?1000," leaks.txt
|
||||||
- name: Test leak detector not being active for `-gc boehm`
|
- name: Test leak detector not being active for `-gc boehm`
|
||||||
run: |
|
run: |
|
||||||
./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv
|
./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
||||||
|
/* This file is installed for backward compatibility. */
|
||||||
|
#include <gc/gc.h>
|
|
@ -0,0 +1,377 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cords are immutable character strings. A number of operations
|
||||||
|
* on long cords are much more efficient than their strings.h counterpart.
|
||||||
|
* In particular, concatenation takes constant time independent of the length
|
||||||
|
* of the arguments. (Cords are represented as trees, with internal
|
||||||
|
* nodes representing concatenation and leaves consisting of either C
|
||||||
|
* strings or a functional description of the string.)
|
||||||
|
*
|
||||||
|
* The following are reasonable applications of cords. They would perform
|
||||||
|
* unacceptably if C strings were used:
|
||||||
|
* - A compiler that produces assembly language output by repeatedly
|
||||||
|
* concatenating instructions onto a cord representing the output file.
|
||||||
|
* - A text editor that converts the input file to a cord, and then
|
||||||
|
* performs editing operations by producing a new cord representing
|
||||||
|
* the file after each character change (and keeping the old ones in an
|
||||||
|
* edit history)
|
||||||
|
*
|
||||||
|
* For optimal performance, cords should be built by
|
||||||
|
* concatenating short sections.
|
||||||
|
* This interface is designed for maximum compatibility with C strings.
|
||||||
|
* ASCII NUL characters may be embedded in cords using CORD_from_fn.
|
||||||
|
* This is handled correctly, but CORD_to_char_star will produce a string
|
||||||
|
* with embedded NULs when given such a cord.
|
||||||
|
*
|
||||||
|
* This interface is fairly big, largely for performance reasons.
|
||||||
|
* The most basic constants and functions:
|
||||||
|
*
|
||||||
|
* CORD - the type of a cord;
|
||||||
|
* CORD_EMPTY - empty cord;
|
||||||
|
* CORD_len(cord) - length of a cord;
|
||||||
|
* CORD_cat(cord1,cord2) - concatenation of two cords;
|
||||||
|
* CORD_substr(cord, start, len) - substring (or subcord);
|
||||||
|
* CORD_pos i; CORD_FOR(i, cord) { ... CORD_pos_fetch(i) ... } -
|
||||||
|
* examine each character in a cord. CORD_pos_fetch(i) is the char.
|
||||||
|
* CORD_fetch(int i) - Retrieve i'th character (slowly).
|
||||||
|
* CORD_cmp(cord1, cord2) - compare two cords.
|
||||||
|
* CORD_from_file(FILE * f) - turn a read-only file into a cord.
|
||||||
|
* CORD_to_char_star(cord) - convert to C string.
|
||||||
|
* (Non-NULL C constant strings are cords.)
|
||||||
|
* CORD_printf (etc.) - cord version of printf. Use %r for cords.
|
||||||
|
*/
|
||||||
|
#ifndef CORD_H
|
||||||
|
#define CORD_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_DLL) && !defined(CORD_NOT_DLL)
|
||||||
|
/* Same as for GC_API in gc_config_macros.h. */
|
||||||
|
# ifdef CORD_BUILD
|
||||||
|
# if defined(__MINGW32__) || defined(__CEGCC__)
|
||||||
|
# define CORD_API __declspec(dllexport)
|
||||||
|
# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
|
||||||
|
|| defined(__CYGWIN__) || defined(__WATCOMC__)
|
||||||
|
# define CORD_API extern __declspec(dllexport)
|
||||||
|
# elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \
|
||||||
|
&& (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
|
||||||
|
/* Only matters if used in conjunction with -fvisibility=hidden option. */
|
||||||
|
# define CORD_API extern __attribute__((__visibility__("default")))
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if defined(__MINGW32__) || defined(__CEGCC__) || defined(_MSC_VER) \
|
||||||
|
|| defined(__DMC__) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||||
|
# define CORD_API __declspec(dllimport)
|
||||||
|
# elif defined(__WATCOMC__)
|
||||||
|
# define CORD_API extern __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
# endif /* !CORD_BUILD */
|
||||||
|
#endif /* GC_DLL */
|
||||||
|
|
||||||
|
#ifndef CORD_API
|
||||||
|
# define CORD_API extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cords have type const char *. This is cheating quite a bit, and not */
|
||||||
|
/* 100% portable. But it means that nonempty character string */
|
||||||
|
/* constants may be used as cords directly, provided the string is */
|
||||||
|
/* never modified in place. The empty cord is represented by, and */
|
||||||
|
/* can be written as, 0. */
|
||||||
|
|
||||||
|
typedef const char * CORD;
|
||||||
|
|
||||||
|
/* An empty cord is always represented as nil */
|
||||||
|
#define CORD_EMPTY 0
|
||||||
|
|
||||||
|
/* Is a nonempty cord represented as a C string? */
|
||||||
|
#define CORD_IS_STRING(s) (*(s) != '\0')
|
||||||
|
|
||||||
|
/* Concatenate two cords. If the arguments are C strings, they may */
|
||||||
|
/* not be subsequently altered. */
|
||||||
|
CORD_API CORD CORD_cat(CORD x, CORD y);
|
||||||
|
|
||||||
|
/* Concatenate a cord and a C string with known length. Except for the */
|
||||||
|
/* empty string case, this is a special case of CORD_cat. Since the */
|
||||||
|
/* length is known, it can be faster. */
|
||||||
|
/* The string y is shared with the resulting CORD. Hence it should */
|
||||||
|
/* not be altered by the caller. */
|
||||||
|
CORD_API CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
|
||||||
|
|
||||||
|
/* Compute the length of a cord */
|
||||||
|
CORD_API size_t CORD_len(CORD x);
|
||||||
|
|
||||||
|
/* Cords may be represented by functions defining the ith character */
|
||||||
|
typedef char (* CORD_fn)(size_t i, void * client_data);
|
||||||
|
|
||||||
|
/* Turn a functional description into a cord. */
|
||||||
|
CORD_API CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
|
||||||
|
|
||||||
|
/* Return the substring (subcord really) of x with length at most n, */
|
||||||
|
/* starting at position i. (The initial character has position 0.) */
|
||||||
|
CORD_API CORD CORD_substr(CORD x, size_t i, size_t n);
|
||||||
|
|
||||||
|
/* Return the argument, but rebalanced to allow more efficient */
|
||||||
|
/* character retrieval, substring operations, and comparisons. */
|
||||||
|
/* This is useful only for cords that were built using repeated */
|
||||||
|
/* concatenation. Guarantees log time access to the result, unless */
|
||||||
|
/* x was obtained through a large number of repeated substring ops */
|
||||||
|
/* or the embedded functional descriptions take longer to evaluate. */
|
||||||
|
/* May reallocate significant parts of the cord. The argument is not */
|
||||||
|
/* modified; only the result is balanced. */
|
||||||
|
CORD_API CORD CORD_balance(CORD x);
|
||||||
|
|
||||||
|
/* The following traverse a cord by applying a function to each */
|
||||||
|
/* character. This is occasionally appropriate, especially where */
|
||||||
|
/* speed is crucial. But, since C doesn't have nested functions, */
|
||||||
|
/* clients of this sort of traversal are clumsy to write. Consider */
|
||||||
|
/* the functions that operate on cord positions instead. */
|
||||||
|
|
||||||
|
/* Function to iteratively apply to individual characters in cord. */
|
||||||
|
typedef int (* CORD_iter_fn)(char c, void * client_data);
|
||||||
|
|
||||||
|
/* Function to apply to substrings of a cord. Each substring is a */
|
||||||
|
/* a C character string, not a general cord. */
|
||||||
|
typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
|
||||||
|
#define CORD_NO_FN ((CORD_batched_iter_fn)0)
|
||||||
|
|
||||||
|
/* Apply f1 to each character in the cord, in ascending order, */
|
||||||
|
/* starting at position i. If */
|
||||||
|
/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by */
|
||||||
|
/* a single call to f2. The parameter f2 is provided only to allow */
|
||||||
|
/* some optimization by the client. This terminates when the right */
|
||||||
|
/* end of this string is reached, or when f1 or f2 return != 0. In the */
|
||||||
|
/* latter case CORD_iter returns != 0. Otherwise it returns 0. */
|
||||||
|
/* The specified value of i must be < CORD_len(x). */
|
||||||
|
CORD_API int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
|
||||||
|
CORD_batched_iter_fn f2, void * client_data);
|
||||||
|
|
||||||
|
/* A simpler version that starts at 0, and without f2: */
|
||||||
|
CORD_API int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
|
||||||
|
#define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
|
||||||
|
|
||||||
|
/* Similar to CORD_iter5, but end-to-beginning. No provisions for */
|
||||||
|
/* CORD_batched_iter_fn. */
|
||||||
|
CORD_API int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
|
||||||
|
|
||||||
|
/* A simpler version that starts at the end: */
|
||||||
|
CORD_API int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Functions that operate on cord positions. The easy way to traverse */
|
||||||
|
/* cords. A cord position is logically a pair consisting of a cord */
|
||||||
|
/* and an index into that cord. But it is much faster to retrieve a */
|
||||||
|
/* character based on a position than on an index. Unfortunately, */
|
||||||
|
/* positions are big (order of a few 100 bytes), so allocate them with */
|
||||||
|
/* caution. */
|
||||||
|
/* Things in cord_pos.h should be treated as opaque, except as */
|
||||||
|
/* described below. Also note that */
|
||||||
|
/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function */
|
||||||
|
/* definitions. The former may evaluate their argument more than once. */
|
||||||
|
#include "cord_pos.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Visible definitions from above:
|
||||||
|
|
||||||
|
typedef <OPAQUE but fairly big> CORD_pos[1];
|
||||||
|
|
||||||
|
* Extract the cord from a position:
|
||||||
|
CORD CORD_pos_to_cord(CORD_pos p);
|
||||||
|
|
||||||
|
* Extract the current index from a position:
|
||||||
|
size_t CORD_pos_to_index(CORD_pos p);
|
||||||
|
|
||||||
|
* Fetch the character located at the given position:
|
||||||
|
char CORD_pos_fetch(CORD_pos p);
|
||||||
|
|
||||||
|
* Initialize the position to refer to the given cord and index.
|
||||||
|
* Note that this is the most expensive function on positions:
|
||||||
|
void CORD_set_pos(CORD_pos p, CORD x, size_t i);
|
||||||
|
|
||||||
|
* Advance the position to the next character.
|
||||||
|
* P must be initialized and valid.
|
||||||
|
* Invalidates p if past end:
|
||||||
|
void CORD_next(CORD_pos p);
|
||||||
|
|
||||||
|
* Move the position to the preceding character.
|
||||||
|
* P must be initialized and valid.
|
||||||
|
* Invalidates p if past beginning:
|
||||||
|
void CORD_prev(CORD_pos p);
|
||||||
|
|
||||||
|
* Is the position valid, i.e. inside the cord?
|
||||||
|
int CORD_pos_valid(CORD_pos p);
|
||||||
|
*/
|
||||||
|
#define CORD_FOR(pos, cord) \
|
||||||
|
for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
|
||||||
|
|
||||||
|
|
||||||
|
/* An out of memory handler to call. May be supplied by client. */
|
||||||
|
/* Must not return. */
|
||||||
|
extern void (* CORD_oom_fn)(void);
|
||||||
|
|
||||||
|
/* Dump the representation of x to stdout in an implementation defined */
|
||||||
|
/* manner. Intended for debugging only. */
|
||||||
|
CORD_API void CORD_dump(CORD x);
|
||||||
|
|
||||||
|
/* The following could easily be implemented by the client. They are */
|
||||||
|
/* provided in cordxtra.c for convenience. */
|
||||||
|
|
||||||
|
/* Concatenate a character to the end of a cord. */
|
||||||
|
CORD_API CORD CORD_cat_char(CORD x, char c);
|
||||||
|
|
||||||
|
/* Concatenate n cords. */
|
||||||
|
CORD_API CORD CORD_catn(int n, /* CORD */ ...);
|
||||||
|
|
||||||
|
/* Return the character in CORD_substr(x, i, 1) */
|
||||||
|
CORD_API char CORD_fetch(CORD x, size_t i);
|
||||||
|
|
||||||
|
/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y */
|
||||||
|
CORD_API int CORD_cmp(CORD x, CORD y);
|
||||||
|
|
||||||
|
/* A generalization that takes both starting positions for the */
|
||||||
|
/* comparison, and a limit on the number of characters to be compared. */
|
||||||
|
CORD_API int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
/* Find the first occurrence of s in x at position start or later. */
|
||||||
|
/* Return the position of the first character of s in x, or */
|
||||||
|
/* CORD_NOT_FOUND if there is none. */
|
||||||
|
CORD_API size_t CORD_str(CORD x, size_t start, CORD s);
|
||||||
|
|
||||||
|
/* Return a cord consisting of i copies of (possibly NUL) c. Dangerous */
|
||||||
|
/* in conjunction with CORD_to_char_star. */
|
||||||
|
/* The resulting representation takes constant space, independent of i. */
|
||||||
|
CORD_API CORD CORD_chars(char c, size_t i);
|
||||||
|
#define CORD_nul(i) CORD_chars('\0', (i))
|
||||||
|
|
||||||
|
/* Turn a file into cord. The file must be seekable. Its contents */
|
||||||
|
/* must remain constant. The file may be accessed as an immediate */
|
||||||
|
/* result of this call and/or as a result of subsequent accesses to */
|
||||||
|
/* the cord. Short files are likely to be immediately read, but */
|
||||||
|
/* long files are likely to be read on demand, possibly relying on */
|
||||||
|
/* stdio for buffering. */
|
||||||
|
/* We must have exclusive access to the descriptor f, i.e. we may */
|
||||||
|
/* read it at any time, and expect the file pointer to be */
|
||||||
|
/* where we left it. Normally this should be invoked as */
|
||||||
|
/* CORD_from_file(fopen(...)) */
|
||||||
|
/* CORD_from_file arranges to close the file descriptor when it is no */
|
||||||
|
/* longer needed (e.g. when the result becomes inaccessible). */
|
||||||
|
/* The file f must be such that ftell reflects the actual character */
|
||||||
|
/* position in the file, i.e. the number of characters that can be */
|
||||||
|
/* or were read with fread. On UNIX systems this is always true. On */
|
||||||
|
/* MS Windows systems, f must be opened in binary mode. */
|
||||||
|
CORD_API CORD CORD_from_file(FILE * f);
|
||||||
|
|
||||||
|
/* Equivalent to the above, except that the entire file will be read */
|
||||||
|
/* and the file pointer will be closed immediately. */
|
||||||
|
/* The binary mode restriction from above does not apply. */
|
||||||
|
CORD_API CORD CORD_from_file_eager(FILE * f);
|
||||||
|
|
||||||
|
/* Equivalent to the above, except that the file will be read on demand.*/
|
||||||
|
/* The binary mode restriction applies. */
|
||||||
|
CORD_API CORD CORD_from_file_lazy(FILE * f);
|
||||||
|
|
||||||
|
/* Turn a cord into a C string. The result shares no structure with */
|
||||||
|
/* x, and is thus modifiable. */
|
||||||
|
CORD_API char * CORD_to_char_star(CORD x);
|
||||||
|
|
||||||
|
/* Turn a C string into a CORD. The C string is copied, and so may */
|
||||||
|
/* subsequently be modified. */
|
||||||
|
CORD_API CORD CORD_from_char_star(const char *s);
|
||||||
|
|
||||||
|
/* Identical to the above, but the result may share structure with */
|
||||||
|
/* the argument and is thus not modifiable. */
|
||||||
|
CORD_API const char * CORD_to_const_char_star(CORD x);
|
||||||
|
|
||||||
|
/* Write a cord to a file, starting at the current position. No */
|
||||||
|
/* trailing NULs are newlines are added. */
|
||||||
|
/* Returns EOF if a write error occurs, 1 otherwise. */
|
||||||
|
CORD_API int CORD_put(CORD x, FILE * f);
|
||||||
|
|
||||||
|
/* "Not found" result for the following two functions. */
|
||||||
|
#define CORD_NOT_FOUND ((size_t)(-1))
|
||||||
|
|
||||||
|
/* A vague analog of strchr. Returns the position (an integer, not */
|
||||||
|
/* a pointer) of the first occurrence of (char) c inside x at position */
|
||||||
|
/* i or later. The value i must be < CORD_len(x). */
|
||||||
|
CORD_API size_t CORD_chr(CORD x, size_t i, int c);
|
||||||
|
|
||||||
|
/* A vague analog of strrchr. Returns index of the last occurrence */
|
||||||
|
/* of (char) c inside x at position i or earlier. The value i */
|
||||||
|
/* must be < CORD_len(x). */
|
||||||
|
CORD_API size_t CORD_rchr(CORD x, size_t i, int c);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The following are also not primitive, but are implemented in */
|
||||||
|
/* cordprnt.c. They provide functionality similar to the ANSI C */
|
||||||
|
/* functions with corresponding names, but with the following */
|
||||||
|
/* additions and changes: */
|
||||||
|
/* 1. A %r conversion specification specifies a CORD argument. Field */
|
||||||
|
/* width, precision, etc. have the same semantics as for %s. */
|
||||||
|
/* (Note that %c, %C, and %S were already taken.) */
|
||||||
|
/* 2. The format string is represented as a CORD. */
|
||||||
|
/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */
|
||||||
|
/* argument. Unlike their ANSI C versions, there is no need to guess */
|
||||||
|
/* the correct buffer size. */
|
||||||
|
/* 4. Most of the conversions are implement through the native */
|
||||||
|
/* vsprintf. Hence they are usually no faster, and */
|
||||||
|
/* idiosyncrasies of the native printf are preserved. However, */
|
||||||
|
/* CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */
|
||||||
|
/* the result shares the original structure. This may make them */
|
||||||
|
/* very efficient in some unusual applications. */
|
||||||
|
/* The format string is copied. */
|
||||||
|
/* All functions return the number of characters generated or -1 on */
|
||||||
|
/* error. This complies with the ANSI standard, but is inconsistent */
|
||||||
|
/* with some older implementations of sprintf. */
|
||||||
|
|
||||||
|
/* The implementation of these is probably less portable than the rest */
|
||||||
|
/* of this package. */
|
||||||
|
|
||||||
|
#ifndef CORD_NO_IO
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
CORD_API int CORD_sprintf(CORD * out, CORD format, ...);
|
||||||
|
CORD_API int CORD_vsprintf(CORD * out, CORD format, va_list args);
|
||||||
|
CORD_API int CORD_fprintf(FILE * f, CORD format, ...);
|
||||||
|
CORD_API int CORD_vfprintf(FILE * f, CORD format, va_list args);
|
||||||
|
CORD_API int CORD_printf(CORD format, ...);
|
||||||
|
CORD_API int CORD_vprintf(CORD format, va_list args);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif /* CORD_NO_IO */
|
||||||
|
|
||||||
|
#endif /* CORD_H */
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This should never be included directly; included only from cord.h. */
|
||||||
|
#if !defined(CORD_POSITION_H) && defined(CORD_H)
|
||||||
|
#define CORD_POSITION_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The representation of CORD_position. This is private to the */
|
||||||
|
/* implementation, but the size is known to clients. Also */
|
||||||
|
/* the implementation of some exported macros relies on it. */
|
||||||
|
/* Don't use anything defined here and not in cord.h. */
|
||||||
|
|
||||||
|
# define MAX_DEPTH 48
|
||||||
|
/* The maximum depth of a balanced cord + 1. */
|
||||||
|
/* We don't let cords get deeper than MAX_DEPTH. */
|
||||||
|
|
||||||
|
struct CORD_pe {
|
||||||
|
CORD pe_cord;
|
||||||
|
size_t pe_start_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A structure describing an entry on the path from the root */
|
||||||
|
/* to current position. */
|
||||||
|
typedef struct CORD_Pos {
|
||||||
|
size_t cur_pos;
|
||||||
|
int path_len;
|
||||||
|
# define CORD_POS_INVALID (0x55555555)
|
||||||
|
/* path_len == INVALID <==> position invalid */
|
||||||
|
const char *cur_leaf; /* Current leaf, if it is a string. */
|
||||||
|
/* If the current leaf is a function, */
|
||||||
|
/* then this may point to function_buf */
|
||||||
|
/* containing the next few characters. */
|
||||||
|
/* Always points to a valid string */
|
||||||
|
/* containing the current character */
|
||||||
|
/* unless cur_end is 0. */
|
||||||
|
size_t cur_start; /* Start position of cur_leaf */
|
||||||
|
size_t cur_end; /* Ending position of cur_leaf */
|
||||||
|
/* 0 if cur_leaf is invalid. */
|
||||||
|
struct CORD_pe path[MAX_DEPTH + 1];
|
||||||
|
/* path[path_len] is the leaf corresponding to cur_pos */
|
||||||
|
/* path[0].pe_cord is the cord we point to. */
|
||||||
|
# define FUNCTION_BUF_SZ 8
|
||||||
|
char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */
|
||||||
|
/* from function node. */
|
||||||
|
} CORD_pos[1];
|
||||||
|
|
||||||
|
/* Extract the cord from a position: */
|
||||||
|
CORD_API CORD CORD_pos_to_cord(CORD_pos p);
|
||||||
|
|
||||||
|
/* Extract the current index from a position: */
|
||||||
|
CORD_API size_t CORD_pos_to_index(CORD_pos p);
|
||||||
|
|
||||||
|
/* Fetch the character located at the given position: */
|
||||||
|
CORD_API char CORD_pos_fetch(CORD_pos p);
|
||||||
|
|
||||||
|
/* Initialize the position to refer to the give cord and index. */
|
||||||
|
/* Note that this is the most expensive function on positions: */
|
||||||
|
CORD_API void CORD_set_pos(CORD_pos p, CORD x, size_t i);
|
||||||
|
|
||||||
|
/* Advance the position to the next character. */
|
||||||
|
/* P must be initialized and valid. */
|
||||||
|
/* Invalidates p if past end: */
|
||||||
|
CORD_API void CORD_next(CORD_pos p);
|
||||||
|
|
||||||
|
/* Move the position to the preceding character. */
|
||||||
|
/* P must be initialized and valid. */
|
||||||
|
/* Invalidates p if past beginning: */
|
||||||
|
CORD_API void CORD_prev(CORD_pos p);
|
||||||
|
|
||||||
|
/* Is the position valid, i.e. inside the cord? */
|
||||||
|
CORD_API int CORD_pos_valid(CORD_pos p);
|
||||||
|
|
||||||
|
CORD_API char CORD__pos_fetch(CORD_pos);
|
||||||
|
CORD_API void CORD__next(CORD_pos);
|
||||||
|
CORD_API void CORD__prev(CORD_pos);
|
||||||
|
|
||||||
|
#define CORD_pos_fetch(p) \
|
||||||
|
(((p)[0].cur_end != 0)? \
|
||||||
|
(p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
|
||||||
|
: CORD__pos_fetch(p))
|
||||||
|
|
||||||
|
#define CORD_next(p) \
|
||||||
|
(((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
|
||||||
|
(p)[0].cur_pos++ \
|
||||||
|
: (CORD__next(p), 0))
|
||||||
|
|
||||||
|
#define CORD_prev(p) \
|
||||||
|
(((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
|
||||||
|
(p)[0].cur_pos-- \
|
||||||
|
: (CORD__prev(p), 0))
|
||||||
|
|
||||||
|
#define CORD_pos_to_index(p) ((p)[0].cur_pos)
|
||||||
|
|
||||||
|
#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
|
||||||
|
|
||||||
|
#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
|
||||||
|
|
||||||
|
/* Some grubby stuff for performance-critical friends: */
|
||||||
|
#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
|
||||||
|
/* Number of characters in cache. <= 0 ==> none */
|
||||||
|
|
||||||
|
#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
|
||||||
|
/* Advance position by n characters */
|
||||||
|
/* 0 < n < CORD_pos_chars_left(p) */
|
||||||
|
|
||||||
|
#define CORD_pos_cur_char_addr(p) \
|
||||||
|
(p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
|
||||||
|
/* address of current character in cache. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EC_H
|
||||||
|
#define EC_H
|
||||||
|
|
||||||
|
# ifndef CORD_H
|
||||||
|
# include "cord.h"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Extensible cords are strings that may be destructively appended to. */
|
||||||
|
/* They allow fast construction of cords from characters that are */
|
||||||
|
/* being read from a stream. */
|
||||||
|
/*
|
||||||
|
* A client might look like:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* CORD_ec x;
|
||||||
|
* CORD result;
|
||||||
|
* char c;
|
||||||
|
* FILE *f;
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
* CORD_ec_init(x);
|
||||||
|
* while(...) {
|
||||||
|
* c = getc(f);
|
||||||
|
* ...
|
||||||
|
* CORD_ec_append(x, c);
|
||||||
|
* }
|
||||||
|
* result = CORD_balance(CORD_ec_to_cord(x));
|
||||||
|
*
|
||||||
|
* If a C string is desired as the final result, the call to CORD_balance
|
||||||
|
* may be replaced by a call to CORD_to_char_star.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# ifndef CORD_BUFSZ
|
||||||
|
# define CORD_BUFSZ 128
|
||||||
|
# endif
|
||||||
|
|
||||||
|
typedef struct CORD_ec_struct {
|
||||||
|
CORD ec_cord;
|
||||||
|
char * ec_bufptr;
|
||||||
|
char ec_buf[CORD_BUFSZ+1];
|
||||||
|
} CORD_ec[1];
|
||||||
|
|
||||||
|
/* This structure represents the concatenation of ec_cord with */
|
||||||
|
/* ec_buf[0 ... (ec_bufptr-ec_buf-1)] */
|
||||||
|
|
||||||
|
/* Flush the buffer part of the extended cord into ec_cord. */
|
||||||
|
/* Note that this is almost the only real function, and it is */
|
||||||
|
/* implemented in 6 lines in cordxtra.c */
|
||||||
|
void CORD_ec_flush_buf(CORD_ec x);
|
||||||
|
|
||||||
|
/* Convert an extensible cord to a cord. */
|
||||||
|
# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord)
|
||||||
|
|
||||||
|
/* Initialize an extensible cord. */
|
||||||
|
#define CORD_ec_init(x) \
|
||||||
|
((x)[0].ec_cord = 0, (void)((x)[0].ec_bufptr = (x)[0].ec_buf))
|
||||||
|
|
||||||
|
/* Append a character to an extensible cord. */
|
||||||
|
#define CORD_ec_append(x, c) \
|
||||||
|
((void)((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ \
|
||||||
|
? (CORD_ec_flush_buf(x), 0) : 0), \
|
||||||
|
(void)(*(x)[0].ec_bufptr++ = (c)))
|
||||||
|
|
||||||
|
/* Append a cord to an extensible cord. Structure remains shared with */
|
||||||
|
/* original. */
|
||||||
|
void CORD_ec_append_cord(CORD_ec x, CORD s);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EC_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||||
|
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||||
|
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a simple API to implement pointer back tracing, i.e.
|
||||||
|
* to answer questions such as "who is pointing to this" or
|
||||||
|
* "why is this object being retained by the collector"
|
||||||
|
*
|
||||||
|
* Most of these calls yield useful information on only after
|
||||||
|
* a garbage collection. Usually the client will first force
|
||||||
|
* a full collection and then gather information, preferably
|
||||||
|
* before much intervening allocation.
|
||||||
|
*
|
||||||
|
* The implementation of the interface is only about 99.9999%
|
||||||
|
* correct. It is intended to be good enough for profiling,
|
||||||
|
* but is not intended to be used with production code.
|
||||||
|
*
|
||||||
|
* Results are likely to be much more useful if all allocation is
|
||||||
|
* accomplished through the debugging allocators.
|
||||||
|
*
|
||||||
|
* The implementation idea is due to A. Demers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GC_BACKPTR_H
|
||||||
|
#define GC_BACKPTR_H
|
||||||
|
|
||||||
|
#ifndef GC_H
|
||||||
|
# include "gc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store information about the object referencing dest in *base_p */
|
||||||
|
/* and *offset_p. */
|
||||||
|
/* If multiple objects or roots point to dest, the one reported */
|
||||||
|
/* will be the last on used by the garbage collector to trace the */
|
||||||
|
/* object. */
|
||||||
|
/* source is root ==> *base_p = address, *offset_p = 0 */
|
||||||
|
/* source is heap object ==> *base_p != 0, *offset_p = offset */
|
||||||
|
/* Returns 1 on success, 0 if source couldn't be determined. */
|
||||||
|
/* Dest can be any address within a heap object. */
|
||||||
|
typedef enum {
|
||||||
|
GC_UNREFERENCED, /* No reference info available. */
|
||||||
|
GC_NO_SPACE, /* Dest not allocated with debug alloc. */
|
||||||
|
GC_REFD_FROM_ROOT, /* Referenced directly by root *base_p. */
|
||||||
|
GC_REFD_FROM_REG, /* Referenced from a register, i.e. */
|
||||||
|
/* a root without an address. */
|
||||||
|
GC_REFD_FROM_HEAP, /* Referenced from another heap obj. */
|
||||||
|
GC_FINALIZER_REFD /* Finalizable and hence accessible. */
|
||||||
|
} GC_ref_kind;
|
||||||
|
|
||||||
|
GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void * /* dest */,
|
||||||
|
void ** /* base_p */, size_t * /* offset_p */)
|
||||||
|
GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
/* Generate a random heap address. */
|
||||||
|
/* The resulting address is in the heap, but */
|
||||||
|
/* not necessarily inside a valid object. */
|
||||||
|
GC_API void * GC_CALL GC_generate_random_heap_address(void);
|
||||||
|
|
||||||
|
/* Generate a random address inside a valid marked heap object. */
|
||||||
|
GC_API void * GC_CALL GC_generate_random_valid_address(void);
|
||||||
|
|
||||||
|
/* Force a garbage collection and generate a backtrace from a */
|
||||||
|
/* random heap address. */
|
||||||
|
/* This uses the GC logging mechanism (GC_printf) to produce */
|
||||||
|
/* output. It can often be called from a debugger. The */
|
||||||
|
/* source in dbg_mlc.c also serves as a sample client. */
|
||||||
|
GC_API void GC_CALL GC_generate_random_backtrace(void);
|
||||||
|
|
||||||
|
/* Print a backtrace from a specific address. Used by the */
|
||||||
|
/* above. The client should call GC_gcollect() immediately */
|
||||||
|
/* before invocation. */
|
||||||
|
GC_API void GC_CALL GC_print_backtrace(void *) GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GC_BACKPTR_H */
|
|
@ -0,0 +1,457 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||||
|
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||||
|
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
|
||||||
|
* All rights reserved.
|
||||||
|
* Copyright (c) 2008-2020 Ivan Maidanski
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This should never be included directly; it is included only from gc.h. */
|
||||||
|
/* We separate it only to make gc.h more suitable as documentation. */
|
||||||
|
#if defined(GC_H)
|
||||||
|
|
||||||
|
/* Convenient internal macro to test version of GCC. */
|
||||||
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||||
|
# define GC_GNUC_PREREQ(major, minor) \
|
||||||
|
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((major) << 16) + (minor))
|
||||||
|
#else
|
||||||
|
# define GC_GNUC_PREREQ(major, minor) 0 /* FALSE */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Some tests for old macros. These violate our namespace rules and */
|
||||||
|
/* will disappear shortly. Use the GC_ names. */
|
||||||
|
#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
|
||||||
|
|| defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS)
|
||||||
|
/* We no longer support old style Solaris threads. */
|
||||||
|
/* GC_SOLARIS_THREADS now means pthreads. */
|
||||||
|
# ifndef GC_SOLARIS_THREADS
|
||||||
|
# define GC_SOLARIS_THREADS
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if defined(IRIX_THREADS)
|
||||||
|
# define GC_IRIX_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(DGUX_THREADS) && !defined(GC_DGUX386_THREADS)
|
||||||
|
# define GC_DGUX386_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(AIX_THREADS)
|
||||||
|
# define GC_AIX_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(HPUX_THREADS)
|
||||||
|
# define GC_HPUX_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(OSF1_THREADS)
|
||||||
|
# define GC_OSF1_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(LINUX_THREADS)
|
||||||
|
# define GC_LINUX_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(WIN32_THREADS)
|
||||||
|
# define GC_WIN32_THREADS
|
||||||
|
#endif
|
||||||
|
#if defined(RTEMS_THREADS)
|
||||||
|
# define GC_RTEMS_PTHREADS
|
||||||
|
#endif
|
||||||
|
#if defined(USE_LD_WRAP)
|
||||||
|
# define GC_USE_LD_WRAP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_WIN32_PTHREADS) && !defined(GC_WIN32_THREADS)
|
||||||
|
/* Using pthreads-win32 library (or other Win32 implementation). */
|
||||||
|
# define GC_WIN32_THREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
|
||||||
|
|| defined(GC_DGUX386_THREADS) || defined(GC_FREEBSD_THREADS) \
|
||||||
|
|| defined(GC_HPUX_THREADS) \
|
||||||
|
|| defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) \
|
||||||
|
|| defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS) \
|
||||||
|
|| defined(GC_OSF1_THREADS) || defined(GC_SOLARIS_THREADS) \
|
||||||
|
|| defined(GC_WIN32_THREADS) || defined(GC_RTEMS_PTHREADS)
|
||||||
|
# ifndef GC_THREADS
|
||||||
|
# define GC_THREADS
|
||||||
|
# endif
|
||||||
|
#elif defined(GC_THREADS)
|
||||||
|
# if defined(__linux__)
|
||||||
|
# define GC_LINUX_THREADS
|
||||||
|
# elif defined(__OpenBSD__)
|
||||||
|
# define GC_OPENBSD_THREADS
|
||||||
|
# elif defined(_PA_RISC1_1) || defined(_PA_RISC2_0) || defined(hppa) \
|
||||||
|
|| defined(__HPPA) || (defined(__ia64) && defined(_HPUX_SOURCE))
|
||||||
|
# define GC_HPUX_THREADS
|
||||||
|
# elif defined(__HAIKU__)
|
||||||
|
# define GC_HAIKU_THREADS
|
||||||
|
# elif (defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
|
||||||
|
|| defined(__FreeBSD__)) && !defined(GC_NO_FREEBSD)
|
||||||
|
# define GC_FREEBSD_THREADS
|
||||||
|
# elif defined(__NetBSD__)
|
||||||
|
# define GC_NETBSD_THREADS
|
||||||
|
# elif defined(__alpha) || defined(__alpha__) /* && !Linux && !xBSD */
|
||||||
|
# define GC_OSF1_THREADS
|
||||||
|
# elif (defined(mips) || defined(__mips) || defined(_mips)) \
|
||||||
|
&& !(defined(nec_ews) || defined(_nec_ews) \
|
||||||
|
|| defined(ultrix) || defined(__ultrix))
|
||||||
|
# define GC_IRIX_THREADS
|
||||||
|
# elif defined(__sparc) /* && !Linux */ \
|
||||||
|
|| ((defined(sun) || defined(__sun)) \
|
||||||
|
&& (defined(i386) || defined(__i386__) \
|
||||||
|
|| defined(__amd64) || defined(__amd64__)))
|
||||||
|
# define GC_SOLARIS_THREADS
|
||||||
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define GC_DARWIN_THREADS
|
||||||
|
# endif
|
||||||
|
# if defined(DGUX) && (defined(i386) || defined(__i386__))
|
||||||
|
# define GC_DGUX386_THREADS
|
||||||
|
# endif
|
||||||
|
# if defined(_AIX)
|
||||||
|
# define GC_AIX_THREADS
|
||||||
|
# endif
|
||||||
|
# if (defined(_WIN32) || defined(_MSC_VER) || defined(__BORLANDC__) \
|
||||||
|
|| defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__CEGCC__) \
|
||||||
|
|| defined(_WIN32_WCE) || defined(__MINGW32__)) \
|
||||||
|
&& !defined(GC_WIN32_THREADS)
|
||||||
|
/* Either posix or native Win32 threads. */
|
||||||
|
# define GC_WIN32_THREADS
|
||||||
|
# endif
|
||||||
|
# if defined(__rtems__) && (defined(i386) || defined(__i386__))
|
||||||
|
# define GC_RTEMS_PTHREADS
|
||||||
|
# endif
|
||||||
|
#endif /* GC_THREADS */
|
||||||
|
|
||||||
|
#undef GC_PTHREADS
|
||||||
|
#if (!defined(GC_WIN32_THREADS) || defined(GC_WIN32_PTHREADS) \
|
||||||
|
|| defined(__CYGWIN32__) || defined(__CYGWIN__)) && defined(GC_THREADS) \
|
||||||
|
&& !defined(NN_PLATFORM_CTR) && !defined(NN_BUILD_TARGET_PLATFORM_NX)
|
||||||
|
/* Posix threads. */
|
||||||
|
# define GC_PTHREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
|
||||||
|
# define _PTHREADS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
|
||||||
|
# define _POSIX4A_DRAFT10_SOURCE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
|
||||||
|
/* Better late than never. This fails if system headers that depend */
|
||||||
|
/* on this were previously included. */
|
||||||
|
# define _REENTRANT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __GC
|
||||||
|
#if !defined(_WIN32_WCE) || defined(__GNUC__)
|
||||||
|
# include <stddef.h>
|
||||||
|
# if defined(__MINGW32__) && !defined(_WIN32_WCE)
|
||||||
|
# include <stdint.h>
|
||||||
|
/* We mention uintptr_t. */
|
||||||
|
/* Perhaps this should be included in pure msft environments */
|
||||||
|
/* as well? */
|
||||||
|
# endif
|
||||||
|
#else /* _WIN32_WCE */
|
||||||
|
/* Yet more kludges for WinCE. */
|
||||||
|
# include <stdlib.h> /* size_t is defined here */
|
||||||
|
# ifndef _PTRDIFF_T_DEFINED
|
||||||
|
/* ptrdiff_t is not defined */
|
||||||
|
# define _PTRDIFF_T_DEFINED
|
||||||
|
typedef long ptrdiff_t;
|
||||||
|
# endif
|
||||||
|
#endif /* _WIN32_WCE */
|
||||||
|
|
||||||
|
#if !defined(GC_NOT_DLL) && !defined(GC_DLL) \
|
||||||
|
&& ((defined(_DLL) && !defined(__GNUC__)) \
|
||||||
|
|| (defined(DLL_EXPORT) && defined(GC_BUILD)))
|
||||||
|
# define GC_DLL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_DLL) && !defined(GC_API)
|
||||||
|
|
||||||
|
# if defined(__CEGCC__)
|
||||||
|
# if defined(GC_BUILD)
|
||||||
|
# define GC_API __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define GC_API __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(__MINGW32__)
|
||||||
|
# if defined(__cplusplus) && defined(GC_BUILD)
|
||||||
|
# define GC_API extern __declspec(dllexport)
|
||||||
|
# elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
|
||||||
|
# define GC_API __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define GC_API extern __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
|
||||||
|
|| defined(__CYGWIN__)
|
||||||
|
# ifdef GC_BUILD
|
||||||
|
# define GC_API extern __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define GC_API __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(__WATCOMC__)
|
||||||
|
# ifdef GC_BUILD
|
||||||
|
# define GC_API extern __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define GC_API extern __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(__SYMBIAN32__)
|
||||||
|
# ifdef GC_BUILD
|
||||||
|
# define GC_API extern EXPORT_C
|
||||||
|
# else
|
||||||
|
# define GC_API extern IMPORT_C
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
/* Only matters if used in conjunction with -fvisibility=hidden option. */
|
||||||
|
# if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
|
||||||
|
&& (GC_GNUC_PREREQ(4, 0) || defined(GC_VISIBILITY_HIDDEN_SET))
|
||||||
|
# define GC_API extern __attribute__((__visibility__("default")))
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif /* GC_DLL */
|
||||||
|
|
||||||
|
#ifndef GC_API
|
||||||
|
# define GC_API extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_CALL
|
||||||
|
# define GC_CALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_CALLBACK
|
||||||
|
# define GC_CALLBACK GC_CALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_MALLOC
|
||||||
|
/* 'malloc' attribute should be used for all malloc-like functions */
|
||||||
|
/* (to tell the compiler that a function may be treated as if any */
|
||||||
|
/* non-NULL pointer it returns cannot alias any other pointer valid */
|
||||||
|
/* when the function returns). If the client code violates this rule */
|
||||||
|
/* by using custom GC_oom_func then define GC_OOM_FUNC_RETURNS_ALIAS. */
|
||||||
|
# ifdef GC_OOM_FUNC_RETURNS_ALIAS
|
||||||
|
# define GC_ATTR_MALLOC /* empty */
|
||||||
|
# elif GC_GNUC_PREREQ(3, 1)
|
||||||
|
# define GC_ATTR_MALLOC __attribute__((__malloc__))
|
||||||
|
# elif defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(__EDG__)
|
||||||
|
# define GC_ATTR_MALLOC \
|
||||||
|
__declspec(allocator) __declspec(noalias) __declspec(restrict)
|
||||||
|
# elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
# define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_MALLOC
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_ALLOC_SIZE
|
||||||
|
/* 'alloc_size' attribute improves __builtin_object_size correctness. */
|
||||||
|
# undef GC_ATTR_CALLOC_SIZE
|
||||||
|
# ifdef __clang__
|
||||||
|
# if __has_attribute(__alloc_size__)
|
||||||
|
# define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
|
||||||
|
# define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_ALLOC_SIZE(argnum) /* empty */
|
||||||
|
# endif
|
||||||
|
# elif GC_GNUC_PREREQ(4, 3) && !defined(__ICC)
|
||||||
|
# define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
|
||||||
|
# define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_ALLOC_SIZE(argnum) /* empty */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_CALLOC_SIZE
|
||||||
|
# define GC_ATTR_CALLOC_SIZE(n, s) /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_NONNULL
|
||||||
|
# if GC_GNUC_PREREQ(4, 0)
|
||||||
|
# define GC_ATTR_NONNULL(argnum) __attribute__((__nonnull__(argnum)))
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_NONNULL(argnum) /* empty */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_CONST
|
||||||
|
# if GC_GNUC_PREREQ(4, 0)
|
||||||
|
# define GC_ATTR_CONST __attribute__((__const__))
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_CONST /* empty */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_DEPRECATED
|
||||||
|
# ifdef GC_BUILD
|
||||||
|
# undef GC_ATTR_DEPRECATED
|
||||||
|
# define GC_ATTR_DEPRECATED /* empty */
|
||||||
|
# elif GC_GNUC_PREREQ(4, 0)
|
||||||
|
# define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
|
||||||
|
# elif defined(_MSC_VER) && _MSC_VER >= 1200
|
||||||
|
# define GC_ATTR_DEPRECATED __declspec(deprecated)
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_DEPRECATED /* empty */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
|
||||||
|
# define GC_ADD_CALLER
|
||||||
|
# define GC_RETURN_ADDR (GC_word)__return_address
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__GLIBC__)
|
||||||
|
# if !defined(__native_client__)
|
||||||
|
# include <features.h>
|
||||||
|
# endif
|
||||||
|
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
|
||||||
|
&& !defined(__ia64__) \
|
||||||
|
&& !defined(GC_MISSING_EXECINFO_H) \
|
||||||
|
&& !defined(GC_HAVE_BUILTIN_BACKTRACE)
|
||||||
|
# define GC_HAVE_BUILTIN_BACKTRACE
|
||||||
|
# endif
|
||||||
|
# if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
|
||||||
|
# define GC_CAN_SAVE_CALL_STACKS
|
||||||
|
# endif
|
||||||
|
#endif /* GLIBC */
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1200 /* version 12.0+ (MSVC 6.0+) */ \
|
||||||
|
&& !defined(_AMD64_) && !defined(_M_X64) && !defined(_WIN32_WCE) \
|
||||||
|
&& !defined(GC_HAVE_NO_BUILTIN_BACKTRACE) \
|
||||||
|
&& !defined(GC_HAVE_BUILTIN_BACKTRACE)
|
||||||
|
# define GC_HAVE_BUILTIN_BACKTRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
|
||||||
|
# define GC_CAN_SAVE_CALL_STACKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__sparc__)
|
||||||
|
# define GC_CAN_SAVE_CALL_STACKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we're on a platform on which we can't save call stacks, but */
|
||||||
|
/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */
|
||||||
|
/* We make this decision independent of whether gcc is actually being */
|
||||||
|
/* used, in order to keep the interface consistent, and allow mixing */
|
||||||
|
/* of compilers. */
|
||||||
|
/* This may also be desirable if it is possible but expensive to */
|
||||||
|
/* retrieve the call chain. */
|
||||||
|
#if (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||||
|
|| defined(__FreeBSD_kernel__) || defined(__HAIKU__) \
|
||||||
|
|| defined(__NetBSD__) || defined(__OpenBSD__) \
|
||||||
|
|| defined(HOST_ANDROID) || defined(__ANDROID__)) \
|
||||||
|
&& !defined(GC_CAN_SAVE_CALL_STACKS)
|
||||||
|
# define GC_ADD_CALLER
|
||||||
|
# if GC_GNUC_PREREQ(2, 95)
|
||||||
|
/* gcc knows how to retrieve return address, but we don't know */
|
||||||
|
/* how to generate call stacks. */
|
||||||
|
# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
|
||||||
|
# if GC_GNUC_PREREQ(4, 0) && (defined(__i386__) || defined(__amd64__) \
|
||||||
|
|| defined(__x86_64__) /* and probably others... */) \
|
||||||
|
&& !defined(GC_NO_RETURN_ADDR_PARENT)
|
||||||
|
# define GC_HAVE_RETURN_ADDR_PARENT
|
||||||
|
# define GC_RETURN_ADDR_PARENT \
|
||||||
|
(GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
|
||||||
|
/* Note: a compiler might complain that calling */
|
||||||
|
/* __builtin_return_address with a nonzero argument is unsafe. */
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
/* Just pass 0 for gcc compatibility. */
|
||||||
|
# define GC_RETURN_ADDR 0
|
||||||
|
# endif
|
||||||
|
#endif /* !GC_CAN_SAVE_CALL_STACKS */
|
||||||
|
|
||||||
|
#ifdef GC_PTHREADS
|
||||||
|
|
||||||
|
# if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
|
||||||
|
|| defined(__native_client__) || defined(GC_RTEMS_PTHREADS)) \
|
||||||
|
&& !defined(GC_NO_DLOPEN)
|
||||||
|
/* Either there is no dlopen() or we do not need to intercept it. */
|
||||||
|
# define GC_NO_DLOPEN
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
|
||||||
|
|| defined(GC_OPENBSD_THREADS) || defined(__native_client__)) \
|
||||||
|
&& !defined(GC_NO_PTHREAD_SIGMASK)
|
||||||
|
/* Either there is no pthread_sigmask() or no need to intercept it. */
|
||||||
|
# define GC_NO_PTHREAD_SIGMASK
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__native_client__)
|
||||||
|
/* At present, NaCl pthread_create() prototype does not have */
|
||||||
|
/* "const" for its "attr" argument; also, NaCl pthread_exit() one */
|
||||||
|
/* does not have "noreturn" attribute. */
|
||||||
|
# ifndef GC_PTHREAD_CREATE_CONST
|
||||||
|
# define GC_PTHREAD_CREATE_CONST /* empty */
|
||||||
|
# endif
|
||||||
|
# ifndef GC_HAVE_PTHREAD_EXIT
|
||||||
|
# define GC_HAVE_PTHREAD_EXIT
|
||||||
|
# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(GC_HAVE_PTHREAD_EXIT) \
|
||||||
|
&& !defined(HOST_ANDROID) && !defined(__ANDROID__) \
|
||||||
|
&& (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
|
||||||
|
# define GC_HAVE_PTHREAD_EXIT
|
||||||
|
/* Intercept pthread_exit on Linux and Solaris. */
|
||||||
|
# if GC_GNUC_PREREQ(2, 7)
|
||||||
|
# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
|
||||||
|
# elif defined(__NORETURN) /* used in Solaris */
|
||||||
|
# define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN
|
||||||
|
# else
|
||||||
|
# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if (!defined(GC_HAVE_PTHREAD_EXIT) || defined(__native_client__)) \
|
||||||
|
&& !defined(GC_NO_PTHREAD_CANCEL)
|
||||||
|
/* Either there is no pthread_cancel() or no need to intercept it. */
|
||||||
|
# define GC_NO_PTHREAD_CANCEL
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif /* GC_PTHREADS */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#ifndef GC_ATTR_EXPLICIT
|
||||||
|
# if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \
|
||||||
|
|| defined(CPPCHECK)
|
||||||
|
# define GC_ATTR_EXPLICIT explicit
|
||||||
|
# else
|
||||||
|
# define GC_ATTR_EXPLICIT /* empty */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_NOEXCEPT
|
||||||
|
# if defined(__DMC__) || (defined(__BORLANDC__) \
|
||||||
|
&& (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
|
||||||
|
|| (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
|
||||||
|
|| (defined(__WATCOMC__) && !defined(_CPPUNWIND))
|
||||||
|
# define GC_NOEXCEPT /* empty */
|
||||||
|
# ifndef GC_NEW_ABORTS_ON_OOM
|
||||||
|
# define GC_NEW_ABORTS_ON_OOM
|
||||||
|
# endif
|
||||||
|
# elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L
|
||||||
|
# define GC_NOEXCEPT noexcept
|
||||||
|
# else
|
||||||
|
# define GC_NOEXCEPT throw()
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||||
|
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GC_INLINE_H
|
||||||
|
#define GC_INLINE_H
|
||||||
|
|
||||||
|
/* WARNING: */
|
||||||
|
/* Note that for these routines, it is the clients responsibility to */
|
||||||
|
/* add the extra byte at the end to deal with one-past-the-end pointers.*/
|
||||||
|
/* In the standard collector configuration, the collector assumes that */
|
||||||
|
/* such a byte has been added, and hence does not trace the last word */
|
||||||
|
/* in the resulting object. */
|
||||||
|
/* This is not an issue if the collector is compiled with */
|
||||||
|
/* DONT_ADD_BYTE_AT_END, or if GC_all_interior_pointers is not set. */
|
||||||
|
/* This interface is most useful for compilers that generate C. */
|
||||||
|
/* It is also used internally for thread-local allocation. */
|
||||||
|
/* Manual use is hereby discouraged. */
|
||||||
|
|
||||||
|
#include "gc.h"
|
||||||
|
#include "gc_tiny_fl.h"
|
||||||
|
|
||||||
|
#if GC_GNUC_PREREQ(3, 0)
|
||||||
|
# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
|
||||||
|
/* Equivalent to (expr), but predict that usually (expr)==outcome. */
|
||||||
|
#else
|
||||||
|
# define GC_EXPECT(expr, outcome) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_ASSERT
|
||||||
|
# ifdef NDEBUG
|
||||||
|
# define GC_ASSERT(expr) /* empty */
|
||||||
|
# else
|
||||||
|
# include <assert.h>
|
||||||
|
# define GC_ASSERT(expr) assert(expr)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GC_PREFETCH_FOR_WRITE
|
||||||
|
# if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
|
||||||
|
# define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
|
||||||
|
# else
|
||||||
|
# define GC_PREFETCH_FOR_WRITE(x) (void)0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Object kinds; must match PTRFREE, NORMAL in gc_priv.h. */
|
||||||
|
#define GC_I_PTRFREE 0
|
||||||
|
#define GC_I_NORMAL 1
|
||||||
|
|
||||||
|
/* Store a pointer to a list of newly allocated objects of kind k and */
|
||||||
|
/* size lb in *result. The caller must make sure that *result is */
|
||||||
|
/* traced even if objects are ptrfree. */
|
||||||
|
GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
||||||
|
void ** /* result */);
|
||||||
|
|
||||||
|
/* Generalized version of GC_malloc and GC_malloc_atomic. */
|
||||||
|
/* Uses appropriately the thread-local (if available) or the global */
|
||||||
|
/* free-list of the specified kind. */
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_malloc_kind(size_t /* lb */, int /* k */);
|
||||||
|
|
||||||
|
#ifdef GC_THREADS
|
||||||
|
/* Same as above but uses only the global free-list. */
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_malloc_kind_global(size_t /* lb */, int /* k */);
|
||||||
|
#else
|
||||||
|
# define GC_malloc_kind_global GC_malloc_kind
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* An internal macro to update the free list pointer atomically (if */
|
||||||
|
/* the AO primitives are available) to avoid race with the marker. */
|
||||||
|
#if defined(GC_THREADS) && defined(AO_HAVE_store)
|
||||||
|
# define GC_FAST_M_AO_STORE(my_fl, next) \
|
||||||
|
AO_store((volatile AO_t *)(my_fl), (AO_t)(next))
|
||||||
|
#else
|
||||||
|
# define GC_FAST_M_AO_STORE(my_fl, next) (void)(*(my_fl) = (next))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The ultimately general inline allocation macro. Allocate an object */
|
||||||
|
/* of size granules, putting the resulting pointer in result. Tiny_fl */
|
||||||
|
/* is a "tiny" free list array, which will be used first, if the size */
|
||||||
|
/* is appropriate. If granules is too large, we allocate with */
|
||||||
|
/* default_expr instead. If we need to refill the free list, we use */
|
||||||
|
/* GC_generic_malloc_many with the indicated kind. */
|
||||||
|
/* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers. */
|
||||||
|
/* If num_direct is nonzero, and the individual free list pointers */
|
||||||
|
/* are initialized to (void *)1, then we allocate num_direct granules */
|
||||||
|
/* directly using generic_malloc before putting multiple objects into */
|
||||||
|
/* the tiny_fl entry. If num_direct is zero, then the free lists may */
|
||||||
|
/* also be initialized to (void *)0. */
|
||||||
|
/* Note that we use the zeroth free list to hold objects 1 granule in */
|
||||||
|
/* size that are used to satisfy size 0 allocation requests. */
|
||||||
|
/* We rely on much of this hopefully getting optimized away in the */
|
||||||
|
/* num_direct = 0 case. */
|
||||||
|
/* Particularly if granules is constant, this should generate a small */
|
||||||
|
/* amount of code. */
|
||||||
|
# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct, \
|
||||||
|
kind,default_expr,init) \
|
||||||
|
do { \
|
||||||
|
if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
|
||||||
|
result = (default_expr); \
|
||||||
|
} else { \
|
||||||
|
void **my_fl = (tiny_fl) + (granules); \
|
||||||
|
void *my_entry=*my_fl; \
|
||||||
|
void *next; \
|
||||||
|
\
|
||||||
|
for (;;) { \
|
||||||
|
if (GC_EXPECT((GC_word)my_entry \
|
||||||
|
> (num_direct) + GC_TINY_FREELISTS + 1, 1)) { \
|
||||||
|
next = *(void **)(my_entry); \
|
||||||
|
result = (void *)my_entry; \
|
||||||
|
GC_FAST_M_AO_STORE(my_fl, next); \
|
||||||
|
init; \
|
||||||
|
GC_PREFETCH_FOR_WRITE(next); \
|
||||||
|
if ((kind) != GC_I_PTRFREE) { \
|
||||||
|
GC_end_stubborn_change(my_fl); \
|
||||||
|
GC_reachable_here(next); \
|
||||||
|
} \
|
||||||
|
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
|
||||||
|
GC_ASSERT((kind) == GC_I_PTRFREE \
|
||||||
|
|| ((GC_word *)result)[1] == 0); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
/* Entry contains counter or NULL */ \
|
||||||
|
if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct) <= 0 \
|
||||||
|
/* (GC_word)my_entry <= (num_direct) */ \
|
||||||
|
&& my_entry != 0 /* NULL */) { \
|
||||||
|
/* Small counter value, not NULL */ \
|
||||||
|
GC_FAST_M_AO_STORE(my_fl, (char *)my_entry \
|
||||||
|
+ (granules) + 1); \
|
||||||
|
result = (default_expr); \
|
||||||
|
break; \
|
||||||
|
} else { \
|
||||||
|
/* Large counter or NULL */ \
|
||||||
|
GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
|
||||||
|
GC_RAW_BYTES_FROM_INDEX(granules)), \
|
||||||
|
kind, my_fl); \
|
||||||
|
my_entry = *my_fl; \
|
||||||
|
if (my_entry == 0) { \
|
||||||
|
result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
# define GC_WORDS_TO_WHOLE_GRANULES(n) \
|
||||||
|
GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
|
||||||
|
|
||||||
|
/* Allocate n words (NOT BYTES). X is made to point to the result. */
|
||||||
|
/* This should really only be used if GC_all_interior_pointers is */
|
||||||
|
/* not set, or DONT_ADD_BYTE_AT_END is set. See above. */
|
||||||
|
/* Does not acquire lock. The caller is responsible for supplying */
|
||||||
|
/* a cleared tiny_fl free list array. For single-threaded */
|
||||||
|
/* applications, this may be a global array. */
|
||||||
|
# define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,kind,init) \
|
||||||
|
do { \
|
||||||
|
size_t granules = GC_WORDS_TO_WHOLE_GRANULES(n); \
|
||||||
|
GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, 0, kind, \
|
||||||
|
GC_malloc_kind(granules*GC_GRANULE_BYTES, kind), \
|
||||||
|
init); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
# define GC_MALLOC_WORDS(result,n,tiny_fl) \
|
||||||
|
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_NORMAL, \
|
||||||
|
*(void **)(result) = 0)
|
||||||
|
|
||||||
|
# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
|
||||||
|
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_PTRFREE, (void)0)
|
||||||
|
|
||||||
|
/* And once more for two word initialized objects: */
|
||||||
|
# define GC_CONS(result, first, second, tiny_fl) \
|
||||||
|
do { \
|
||||||
|
void *l = (void *)(first); \
|
||||||
|
void *r = (void *)(second); \
|
||||||
|
GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \
|
||||||
|
if ((result) != 0 /* NULL */) { \
|
||||||
|
*(void **)(result) = l; \
|
||||||
|
GC_PTR_STORE_AND_DIRTY((void **)(result) + 1, r); \
|
||||||
|
GC_reachable_here(l); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
GC_API void GC_CALL GC_print_free_list(int /* kind */,
|
||||||
|
size_t /* sz_in_granules */);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !GC_INLINE_H */
|
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This contains interfaces to the GC marker that are likely to be useful to
|
||||||
|
* clients that provide detailed heap layout information to the collector.
|
||||||
|
* This interface should not be used by normal C or C++ clients.
|
||||||
|
* It will be useful to runtimes for other languages.
|
||||||
|
*
|
||||||
|
* This is an experts-only interface! There are many ways to break the
|
||||||
|
* collector in subtle ways by using this functionality.
|
||||||
|
*/
|
||||||
|
#ifndef GC_MARK_H
|
||||||
|
#define GC_MARK_H
|
||||||
|
|
||||||
|
#ifndef GC_H
|
||||||
|
# include "gc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A client supplied mark procedure. Returns new mark stack pointer. */
|
||||||
|
/* Primary effect should be to push new entries on the mark stack. */
|
||||||
|
/* Mark stack pointer values are passed and returned explicitly. */
|
||||||
|
/* Global variables describing mark stack are not necessarily valid. */
|
||||||
|
/* (This usually saves a few cycles by keeping things in registers.) */
|
||||||
|
/* Assumed to scan about GC_PROC_BYTES on average. If it needs to do */
|
||||||
|
/* much more work than that, it should do it in smaller pieces by */
|
||||||
|
/* pushing itself back on the mark stack. */
|
||||||
|
/* Note that it should always do some work (defined as marking some */
|
||||||
|
/* objects) before pushing more than one entry on the mark stack. */
|
||||||
|
/* This is required to ensure termination in the event of mark stack */
|
||||||
|
/* overflows. */
|
||||||
|
/* This procedure is always called with at least one empty entry on the */
|
||||||
|
/* mark stack. */
|
||||||
|
/* Currently we require that mark procedures look for pointers in a */
|
||||||
|
/* subset of the places the conservative marker would. It must be safe */
|
||||||
|
/* to invoke the normal mark procedure instead. */
|
||||||
|
/* WARNING: Such a mark procedure may be invoked on an unused object */
|
||||||
|
/* residing on a free list. Such objects are cleared, except for a */
|
||||||
|
/* free list link field in the first word. Thus mark procedures may */
|
||||||
|
/* not count on the presence of a type descriptor, and must handle this */
|
||||||
|
/* case correctly somehow. */
|
||||||
|
#define GC_PROC_BYTES 100
|
||||||
|
|
||||||
|
#if defined(GC_BUILD) || defined(NOT_GCBUILD)
|
||||||
|
struct GC_ms_entry;
|
||||||
|
#else
|
||||||
|
struct GC_ms_entry { void *opaque; };
|
||||||
|
#endif
|
||||||
|
typedef struct GC_ms_entry * (*GC_mark_proc)(GC_word * /* addr */,
|
||||||
|
struct GC_ms_entry * /* mark_stack_ptr */,
|
||||||
|
struct GC_ms_entry * /* mark_stack_limit */,
|
||||||
|
GC_word /* env */);
|
||||||
|
|
||||||
|
#define GC_LOG_MAX_MARK_PROCS 6
|
||||||
|
#define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS)
|
||||||
|
|
||||||
|
/* In a few cases it's necessary to assign statically known indices to */
|
||||||
|
/* certain mark procs. Thus we reserve a few for well known clients. */
|
||||||
|
/* (This is necessary if mark descriptors are compiler generated.) */
|
||||||
|
#define GC_RESERVED_MARK_PROCS 8
|
||||||
|
#define GC_GCJ_RESERVED_MARK_PROC_INDEX 0
|
||||||
|
|
||||||
|
/* Object descriptors on mark stack or in objects. Low order two */
|
||||||
|
/* bits are tags distinguishing among the following 4 possibilities */
|
||||||
|
/* for the high order 30 bits. */
|
||||||
|
#define GC_DS_TAG_BITS 2
|
||||||
|
#define GC_DS_TAGS ((1 << GC_DS_TAG_BITS) - 1)
|
||||||
|
#define GC_DS_LENGTH 0 /* The entire word is a length in bytes that */
|
||||||
|
/* must be a multiple of 4. */
|
||||||
|
#define GC_DS_BITMAP 1 /* 30 (62) bits are a bitmap describing pointer */
|
||||||
|
/* fields. The msb is 1 if the first word */
|
||||||
|
/* is a pointer. */
|
||||||
|
/* (This unconventional ordering sometimes */
|
||||||
|
/* makes the marker slightly faster.) */
|
||||||
|
/* Zeroes indicate definite nonpointers. Ones */
|
||||||
|
/* indicate possible pointers. */
|
||||||
|
/* Only usable if pointers are word aligned. */
|
||||||
|
#define GC_DS_PROC 2
|
||||||
|
/* The objects referenced by this object can be */
|
||||||
|
/* pushed on the mark stack by invoking */
|
||||||
|
/* PROC(descr). ENV(descr) is passed as the */
|
||||||
|
/* last argument. */
|
||||||
|
#define GC_MAKE_PROC(proc_index, env) \
|
||||||
|
(((((env) << GC_LOG_MAX_MARK_PROCS) \
|
||||||
|
| (proc_index)) << GC_DS_TAG_BITS) | GC_DS_PROC)
|
||||||
|
#define GC_DS_PER_OBJECT 3 /* The real descriptor is at the */
|
||||||
|
/* byte displacement from the beginning of the */
|
||||||
|
/* object given by descr & ~GC_DS_TAGS. */
|
||||||
|
/* If the descriptor is negative, the real */
|
||||||
|
/* descriptor is at (*<object_start>) - */
|
||||||
|
/* (descr&~GC_DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
|
||||||
|
/* The latter alternative can be used if each */
|
||||||
|
/* object contains a type descriptor in the */
|
||||||
|
/* first word. */
|
||||||
|
/* Note that in the multi-threaded environments */
|
||||||
|
/* per-object descriptors must be located in */
|
||||||
|
/* either the first two or last two words of */
|
||||||
|
/* the object, since only those are guaranteed */
|
||||||
|
/* to be cleared while the allocation lock is */
|
||||||
|
/* held. */
|
||||||
|
#define GC_INDIR_PER_OBJ_BIAS 0x10
|
||||||
|
|
||||||
|
GC_API void * GC_least_plausible_heap_addr;
|
||||||
|
GC_API void * GC_greatest_plausible_heap_addr;
|
||||||
|
/* Bounds on the heap. Guaranteed valid */
|
||||||
|
/* Likely to include future heap expansion. */
|
||||||
|
/* Hence usually includes not-yet-mapped */
|
||||||
|
/* memory. */
|
||||||
|
|
||||||
|
/* Handle nested references in a custom mark procedure. */
|
||||||
|
/* Check if obj is a valid object. If so, ensure that it is marked. */
|
||||||
|
/* If it was not previously marked, push its contents onto the mark */
|
||||||
|
/* stack for future scanning. The object will then be scanned using */
|
||||||
|
/* its mark descriptor. */
|
||||||
|
/* Returns the new mark stack pointer. */
|
||||||
|
/* Handles mark stack overflows correctly. */
|
||||||
|
/* Since this marks first, it makes progress even if there are mark */
|
||||||
|
/* stack overflows. */
|
||||||
|
/* Src is the address of the pointer to obj, which is used only */
|
||||||
|
/* for back pointer-based heap debugging. */
|
||||||
|
/* It is strongly recommended that most objects be handled without mark */
|
||||||
|
/* procedures, e.g. with bitmap descriptors, and that mark procedures */
|
||||||
|
/* be reserved for exceptional cases. That will ensure that */
|
||||||
|
/* performance of this call is not extremely performance critical. */
|
||||||
|
/* (Otherwise we would need to inline GC_mark_and_push completely, */
|
||||||
|
/* which would tie the client code to a fixed collector version.) */
|
||||||
|
/* Note that mark procedures should explicitly call FIXUP_POINTER() */
|
||||||
|
/* if required. */
|
||||||
|
GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void * /* obj */,
|
||||||
|
struct GC_ms_entry * /* mark_stack_ptr */,
|
||||||
|
struct GC_ms_entry * /* mark_stack_limit */,
|
||||||
|
void ** /* src */);
|
||||||
|
|
||||||
|
#define GC_MARK_AND_PUSH(obj, msp, lim, src) \
|
||||||
|
((GC_word)(obj) >= (GC_word)GC_least_plausible_heap_addr && \
|
||||||
|
(GC_word)(obj) <= (GC_word)GC_greatest_plausible_heap_addr ? \
|
||||||
|
GC_mark_and_push(obj, msp, lim, src) : (msp))
|
||||||
|
|
||||||
|
/* The size of the header added to objects allocated through the */
|
||||||
|
/* GC_debug routines. Defined as a function so that client mark */
|
||||||
|
/* procedures do not need to be recompiled for the collector library */
|
||||||
|
/* version changes. */
|
||||||
|
GC_API GC_ATTR_CONST size_t GC_CALL GC_get_debug_header_size(void);
|
||||||
|
#define GC_USR_PTR_FROM_BASE(p) \
|
||||||
|
((void *)((char *)(p) + GC_get_debug_header_size()))
|
||||||
|
|
||||||
|
/* The same but defined as a variable. Exists only for the backward */
|
||||||
|
/* compatibility. Some compilers do not accept "const" together with */
|
||||||
|
/* deprecated or dllimport attributes, so the symbol is exported as */
|
||||||
|
/* a non-constant one. */
|
||||||
|
GC_API GC_ATTR_DEPRECATED
|
||||||
|
# ifdef GC_BUILD
|
||||||
|
const
|
||||||
|
# endif
|
||||||
|
size_t GC_debug_header_size;
|
||||||
|
|
||||||
|
/* And some routines to support creation of new "kinds", e.g. with */
|
||||||
|
/* custom mark procedures, by language runtimes. */
|
||||||
|
/* The _inner versions assume the caller holds the allocation lock. */
|
||||||
|
|
||||||
|
/* Return a new free list array. */
|
||||||
|
GC_API void ** GC_CALL GC_new_free_list(void);
|
||||||
|
GC_API void ** GC_CALL GC_new_free_list_inner(void);
|
||||||
|
|
||||||
|
/* Return a new kind, as specified. */
|
||||||
|
GC_API unsigned GC_CALL GC_new_kind(void ** /* free_list */,
|
||||||
|
GC_word /* mark_descriptor_template */,
|
||||||
|
int /* add_size_to_descriptor */,
|
||||||
|
int /* clear_new_objects */) GC_ATTR_NONNULL(1);
|
||||||
|
/* The last two parameters must be zero or one. */
|
||||||
|
GC_API unsigned GC_CALL GC_new_kind_inner(void ** /* free_list */,
|
||||||
|
GC_word /* mark_descriptor_template */,
|
||||||
|
int /* add_size_to_descriptor */,
|
||||||
|
int /* clear_new_objects */) GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
/* Return a new mark procedure identifier, suitable for use as */
|
||||||
|
/* the first argument in GC_MAKE_PROC. */
|
||||||
|
GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc);
|
||||||
|
GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc);
|
||||||
|
|
||||||
|
/* Allocate an object of a given kind. By default, there are only */
|
||||||
|
/* a few kinds: composite (pointerful), atomic, uncollectible, etc. */
|
||||||
|
/* We claim it is possible for clever client code that understands the */
|
||||||
|
/* GC internals to add more, e.g. to communicate object layout */
|
||||||
|
/* information to the collector. Note that in the multi-threaded */
|
||||||
|
/* contexts, this is usually unsafe for kinds that have the descriptor */
|
||||||
|
/* in the object itself, since there is otherwise a window in which */
|
||||||
|
/* the descriptor is not correct. Even in the single-threaded case, */
|
||||||
|
/* we need to be sure that cleared objects on a free list don't */
|
||||||
|
/* cause a GC crash if they are accidentally traced. */
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL GC_generic_malloc(
|
||||||
|
size_t /* lb */,
|
||||||
|
int /* knd */);
|
||||||
|
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_generic_malloc_ignore_off_page(
|
||||||
|
size_t /* lb */, int /* knd */);
|
||||||
|
/* As above, but pointers to past the */
|
||||||
|
/* first page of the resulting object */
|
||||||
|
/* are ignored. */
|
||||||
|
|
||||||
|
/* Generalized version of GC_malloc_[atomic_]uncollectable. */
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_generic_malloc_uncollectable(
|
||||||
|
size_t /* lb */, int /* knd */);
|
||||||
|
|
||||||
|
/* Same as above but primary for allocating an object of the same kind */
|
||||||
|
/* as an existing one (kind obtained by GC_get_kind_and_size). */
|
||||||
|
/* Not suitable for GCJ and typed-malloc kinds. */
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_generic_or_special_malloc(
|
||||||
|
size_t /* size */, int /* knd */);
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_debug_generic_or_special_malloc(
|
||||||
|
size_t /* size */, int /* knd */,
|
||||||
|
GC_EXTRA_PARAMS);
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
# define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
|
||||||
|
GC_debug_generic_or_special_malloc(sz, knd, GC_EXTRAS)
|
||||||
|
#else
|
||||||
|
# define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
|
||||||
|
GC_generic_or_special_malloc(sz, knd)
|
||||||
|
#endif /* !GC_DEBUG */
|
||||||
|
|
||||||
|
/* Similar to GC_size but returns object kind. Size is returned too */
|
||||||
|
/* if psize is not NULL. */
|
||||||
|
GC_API int GC_CALL GC_get_kind_and_size(const void *, size_t * /* psize */)
|
||||||
|
GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
typedef void (GC_CALLBACK * GC_describe_type_fn)(void * /* p */,
|
||||||
|
char * /* out_buf */);
|
||||||
|
/* A procedure which */
|
||||||
|
/* produces a human-readable */
|
||||||
|
/* description of the "type" of object */
|
||||||
|
/* p into the buffer out_buf of length */
|
||||||
|
/* GC_TYPE_DESCR_LEN. This is used by */
|
||||||
|
/* the debug support when printing */
|
||||||
|
/* objects. */
|
||||||
|
/* These functions should be as robust */
|
||||||
|
/* as possible, though we do avoid */
|
||||||
|
/* invoking them on objects on the */
|
||||||
|
/* global free list. */
|
||||||
|
#define GC_TYPE_DESCR_LEN 40
|
||||||
|
|
||||||
|
GC_API void GC_CALL GC_register_describe_type_fn(int /* kind */,
|
||||||
|
GC_describe_type_fn);
|
||||||
|
/* Register a describe_type function */
|
||||||
|
/* to be used when printing objects */
|
||||||
|
/* of a particular kind. */
|
||||||
|
|
||||||
|
/* Clear some of the inaccessible part of the stack. Returns its */
|
||||||
|
/* argument, so it can be used in a tail call position, hence clearing */
|
||||||
|
/* another frame. Argument may be NULL. */
|
||||||
|
GC_API void * GC_CALL GC_clear_stack(void *);
|
||||||
|
|
||||||
|
/* Set and get the client notifier on collections. The client function */
|
||||||
|
/* is called at the start of every full GC (called with the allocation */
|
||||||
|
/* lock held). May be 0. This is a really tricky interface to use */
|
||||||
|
/* correctly. Unless you really understand the collector internals, */
|
||||||
|
/* the callback should not, directly or indirectly, make any GC_ or */
|
||||||
|
/* potentially blocking calls. In particular, it is not safe to */
|
||||||
|
/* allocate memory using the garbage collector from within the callback */
|
||||||
|
/* function. Both the setter and getter acquire the GC lock. */
|
||||||
|
typedef void (GC_CALLBACK * GC_start_callback_proc)(void);
|
||||||
|
GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc);
|
||||||
|
GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void);
|
||||||
|
|
||||||
|
/* Slow/general mark bit manipulation. The caller must hold the */
|
||||||
|
/* allocation lock. GC_is_marked returns 1 (TRUE) or 0. */
|
||||||
|
GC_API int GC_CALL GC_is_marked(const void *) GC_ATTR_NONNULL(1);
|
||||||
|
GC_API void GC_CALL GC_clear_mark_bit(const void *) GC_ATTR_NONNULL(1);
|
||||||
|
GC_API void GC_CALL GC_set_mark_bit(const void *) GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
/* Push everything in the given range onto the mark stack. */
|
||||||
|
/* (GC_push_conditional pushes either all or only dirty pages depending */
|
||||||
|
/* on the third argument.) GC_push_all_eager also ensures that stack */
|
||||||
|
/* is scanned immediately, not just scheduled for scanning. */
|
||||||
|
GC_API void GC_CALL GC_push_all(void * /* bottom */, void * /* top */);
|
||||||
|
GC_API void GC_CALL GC_push_all_eager(void * /* bottom */, void * /* top */);
|
||||||
|
GC_API void GC_CALL GC_push_conditional(void * /* bottom */, void * /* top */,
|
||||||
|
int /* bool all */);
|
||||||
|
GC_API void GC_CALL GC_push_finalizer_structures(void);
|
||||||
|
|
||||||
|
/* Set and get the client push-other-roots procedure. A client */
|
||||||
|
/* supplied procedure should also call the original procedure. */
|
||||||
|
/* Note that both the setter and getter require some external */
|
||||||
|
/* synchronization to avoid data race. */
|
||||||
|
typedef void (GC_CALLBACK * GC_push_other_roots_proc)(void);
|
||||||
|
GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
|
||||||
|
GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
|
||||||
|
|
||||||
|
/* Walk the GC heap visiting all reachable objects. Assume the caller */
|
||||||
|
/* holds the allocation lock. Object base pointer, object size and */
|
||||||
|
/* client custom data are passed to the callback (holding the lock). */
|
||||||
|
typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */,
|
||||||
|
size_t /* bytes */,
|
||||||
|
void * /* client_data */);
|
||||||
|
GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
|
||||||
|
GC_reachable_object_proc,
|
||||||
|
void * /* client_data */) GC_ATTR_NONNULL(1);
|
||||||
|
|
||||||
|
GC_API int GC_CALL GC_is_tmp_root(void *);
|
||||||
|
|
||||||
|
GC_API void GC_CALL GC_print_trace(GC_word /* gc_no */);
|
||||||
|
GC_API void GC_CALL GC_print_trace_inner(GC_word /* gc_no */);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GC_MARK_H */
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||||
|
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||||
|
* Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Our pthread support normally needs to intercept a number of thread */
|
||||||
|
/* calls. We arrange to do that here, if appropriate. */
|
||||||
|
|
||||||
|
#ifndef GC_PTHREAD_REDIRECTS_H
|
||||||
|
#define GC_PTHREAD_REDIRECTS_H
|
||||||
|
|
||||||
|
/* Included from gc.h only. Included only if GC_PTHREADS. */
|
||||||
|
#if defined(GC_H) && defined(GC_PTHREADS)
|
||||||
|
|
||||||
|
/* We need to intercept calls to many of the threads primitives, so */
|
||||||
|
/* that we can locate thread stacks and stop the world. */
|
||||||
|
/* Note also that the collector cannot always see thread specific data. */
|
||||||
|
/* Thread specific data should generally consist of pointers to */
|
||||||
|
/* uncollectible objects (allocated with GC_malloc_uncollectable, */
|
||||||
|
/* not the system malloc), which are deallocated using the destructor */
|
||||||
|
/* facility in thr_keycreate. Alternatively, keep a redundant pointer */
|
||||||
|
/* to thread specific data on the thread stack. */
|
||||||
|
|
||||||
|
#ifndef GC_PTHREAD_REDIRECTS_ONLY
|
||||||
|
|
||||||
|
# include <pthread.h>
|
||||||
|
# ifndef GC_NO_DLOPEN
|
||||||
|
# include <dlfcn.h>
|
||||||
|
# endif
|
||||||
|
# ifndef GC_NO_PTHREAD_SIGMASK
|
||||||
|
# include <signal.h> /* needed anyway for proper redirection */
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef GC_SUSPEND_THREAD_ID
|
||||||
|
# define GC_SUSPEND_THREAD_ID pthread_t
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef GC_NO_DLOPEN
|
||||||
|
GC_API void *GC_dlopen(const char * /* path */, int /* mode */);
|
||||||
|
# endif /* !GC_NO_DLOPEN */
|
||||||
|
|
||||||
|
# ifndef GC_NO_PTHREAD_SIGMASK
|
||||||
|
# if defined(GC_PTHREAD_SIGMASK_NEEDED) \
|
||||||
|
|| defined(_BSD_SOURCE) || defined(_GNU_SOURCE) \
|
||||||
|
|| (_POSIX_C_SOURCE >= 199506L) || (_XOPEN_SOURCE >= 500)
|
||||||
|
GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
|
||||||
|
sigset_t * /* oset */);
|
||||||
|
# endif
|
||||||
|
# endif /* !GC_NO_PTHREAD_SIGMASK */
|
||||||
|
|
||||||
|
# ifndef GC_PTHREAD_CREATE_CONST
|
||||||
|
/* This is used for pthread_create() only. */
|
||||||
|
# define GC_PTHREAD_CREATE_CONST const
|
||||||
|
# endif
|
||||||
|
|
||||||
|
GC_API int GC_pthread_create(pthread_t *,
|
||||||
|
GC_PTHREAD_CREATE_CONST pthread_attr_t *,
|
||||||
|
void *(*)(void *), void * /* arg */);
|
||||||
|
GC_API int GC_pthread_join(pthread_t, void ** /* retval */);
|
||||||
|
GC_API int GC_pthread_detach(pthread_t);
|
||||||
|
|
||||||
|
# ifndef GC_NO_PTHREAD_CANCEL
|
||||||
|
GC_API int GC_pthread_cancel(pthread_t);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(GC_HAVE_PTHREAD_EXIT) && !defined(GC_PTHREAD_EXIT_DECLARED)
|
||||||
|
# define GC_PTHREAD_EXIT_DECLARED
|
||||||
|
GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif /* !GC_PTHREAD_REDIRECTS_ONLY */
|
||||||
|
|
||||||
|
#if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
|
||||||
|
/* Unless the compiler supports #pragma extern_prefix, the Tru64 */
|
||||||
|
/* UNIX <pthread.h> redefines some POSIX thread functions to use */
|
||||||
|
/* mangled names. Anyway, it's safe to undef them before redefining. */
|
||||||
|
# undef pthread_create
|
||||||
|
# undef pthread_join
|
||||||
|
# undef pthread_detach
|
||||||
|
# define pthread_create GC_pthread_create
|
||||||
|
# define pthread_join GC_pthread_join
|
||||||
|
# define pthread_detach GC_pthread_detach
|
||||||
|
|
||||||
|
# ifndef GC_NO_PTHREAD_SIGMASK
|
||||||
|
# undef pthread_sigmask
|
||||||
|
# define pthread_sigmask GC_pthread_sigmask
|
||||||
|
# endif
|
||||||
|
# ifndef GC_NO_DLOPEN
|
||||||
|
# undef dlopen
|
||||||
|
# define dlopen GC_dlopen
|
||||||
|
# endif
|
||||||
|
# ifndef GC_NO_PTHREAD_CANCEL
|
||||||
|
# undef pthread_cancel
|
||||||
|
# define pthread_cancel GC_pthread_cancel
|
||||||
|
# endif
|
||||||
|
# ifdef GC_HAVE_PTHREAD_EXIT
|
||||||
|
# undef pthread_exit
|
||||||
|
# define pthread_exit GC_pthread_exit
|
||||||
|
# endif
|
||||||
|
#endif /* !GC_NO_THREAD_REDIRECTS */
|
||||||
|
|
||||||
|
#endif /* GC_PTHREADS */
|
||||||
|
|
||||||
|
#endif /* GC_PTHREAD_REDIRECTS_H */
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GC_TINY_FL_H
|
||||||
|
#define GC_TINY_FL_H
|
||||||
|
/*
|
||||||
|
* Constants and data structures for "tiny" free lists.
|
||||||
|
* These are used for thread-local allocation or in-lined allocators.
|
||||||
|
* Each global free list also essentially starts with one of these.
|
||||||
|
* However, global free lists are known to the GC. "Tiny" free lists
|
||||||
|
* are basically private to the client. Their contents are viewed as
|
||||||
|
* "in use" and marked accordingly by the core of the GC.
|
||||||
|
*
|
||||||
|
* Note that inlined code might know about the layout of these and the constants
|
||||||
|
* involved. Thus any change here may invalidate clients, and such changes should
|
||||||
|
* be avoided. Hence we keep this as simple as possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always set GC_GRANULE_BYTES to twice the length of a pointer.
|
||||||
|
* This means that all allocation requests are rounded up to the next
|
||||||
|
* multiple of 16 on 64-bit architectures or 8 on 32-bit architectures.
|
||||||
|
* This appears to be a reasonable compromise between fragmentation overhead
|
||||||
|
* and space usage for mark bits (usually mark bytes).
|
||||||
|
* On many 64-bit architectures some memory references require 16-byte
|
||||||
|
* alignment, making this necessary anyway.
|
||||||
|
* For a few 32-bit architecture (e.g. x86), we may also need 16-byte alignment
|
||||||
|
* for certain memory references. But currently that does not seem to be the
|
||||||
|
* default for all conventional malloc implementations, so we ignore that
|
||||||
|
* problem.
|
||||||
|
* It would always be safe, and often useful, to be able to allocate very
|
||||||
|
* small objects with smaller alignment. But that would cost us mark bit
|
||||||
|
* space, so we no longer do so.
|
||||||
|
*/
|
||||||
|
#ifndef GC_GRANULE_BYTES
|
||||||
|
/* GC_GRANULE_BYTES should not be overridden in any instances of the GC */
|
||||||
|
/* library that may be shared between applications, since it affects */
|
||||||
|
/* the binary interface to the library. */
|
||||||
|
# if defined(__LP64__) || defined (_LP64) || defined(_WIN64) \
|
||||||
|
|| defined(__s390x__) \
|
||||||
|
|| (defined(__x86_64__) && !defined(__ILP32__)) \
|
||||||
|
|| defined(__alpha__) || defined(__powerpc64__) \
|
||||||
|
|| defined(__arch64__)
|
||||||
|
# define GC_GRANULE_BYTES 16
|
||||||
|
# define GC_GRANULE_WORDS 2
|
||||||
|
# else
|
||||||
|
# define GC_GRANULE_BYTES 8
|
||||||
|
# define GC_GRANULE_WORDS 2
|
||||||
|
# endif
|
||||||
|
#endif /* !GC_GRANULE_BYTES */
|
||||||
|
|
||||||
|
#if GC_GRANULE_WORDS == 2
|
||||||
|
# define GC_WORDS_TO_GRANULES(n) ((n)>>1)
|
||||||
|
#else
|
||||||
|
# define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GC_GRANULE_BYTES)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A "tiny" free list header contains TINY_FREELISTS pointers to */
|
||||||
|
/* singly linked lists of objects of different sizes, the ith one */
|
||||||
|
/* containing objects i granules in size. Note that there is a list */
|
||||||
|
/* of size zero objects. */
|
||||||
|
#ifndef GC_TINY_FREELISTS
|
||||||
|
# if GC_GRANULE_BYTES == 16
|
||||||
|
# define GC_TINY_FREELISTS 25
|
||||||
|
# else
|
||||||
|
# define GC_TINY_FREELISTS 33 /* Up to and including 256 bytes */
|
||||||
|
# endif
|
||||||
|
#endif /* !GC_TINY_FREELISTS */
|
||||||
|
|
||||||
|
/* The ith free list corresponds to size i*GC_GRANULE_BYTES */
|
||||||
|
/* Internally to the collector, the index can be computed with */
|
||||||
|
/* ROUNDED_UP_GRANULES. Externally, we don't know whether */
|
||||||
|
/* DONT_ADD_BYTE_AT_END is set, but the client should know. */
|
||||||
|
|
||||||
|
/* Convert a free list index to the actual size of objects */
|
||||||
|
/* on that list, including extra space we added. Not an */
|
||||||
|
/* inverse of the above. */
|
||||||
|
#define GC_RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES)
|
||||||
|
|
||||||
|
#endif /* GC_TINY_FL_H */
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||||
|
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright 1996 Silicon Graphics. All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some simple primitives for allocation with explicit type information.
|
||||||
|
* Facilities for dynamic type inference may be added later.
|
||||||
|
* Should be used only for extremely performance critical applications,
|
||||||
|
* or if conservative collector leakage is otherwise a problem (unlikely).
|
||||||
|
* Note that this is implemented completely separately from the rest
|
||||||
|
* of the collector, and is not linked in unless referenced.
|
||||||
|
* This does not currently support GC_DEBUG in any interesting way.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GC_TYPED_H
|
||||||
|
#define GC_TYPED_H
|
||||||
|
|
||||||
|
#ifndef GC_H
|
||||||
|
# include "gc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef GC_word * GC_bitmap;
|
||||||
|
/* The least significant bit of the first word is one if */
|
||||||
|
/* the first word in the object may be a pointer. */
|
||||||
|
|
||||||
|
#define GC_WORDSZ (8 * sizeof(GC_word))
|
||||||
|
#define GC_get_bit(bm, index) \
|
||||||
|
(((bm)[(index) / GC_WORDSZ] >> ((index) % GC_WORDSZ)) & 1)
|
||||||
|
#define GC_set_bit(bm, index) \
|
||||||
|
((bm)[(index) / GC_WORDSZ] |= (GC_word)1 << ((index) % GC_WORDSZ))
|
||||||
|
#define GC_WORD_OFFSET(t, f) (offsetof(t,f) / sizeof(GC_word))
|
||||||
|
#define GC_WORD_LEN(t) (sizeof(t) / sizeof(GC_word))
|
||||||
|
#define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ - 1) / GC_WORDSZ)
|
||||||
|
|
||||||
|
typedef GC_word GC_descr;
|
||||||
|
|
||||||
|
GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * /* GC_bitmap bm */,
|
||||||
|
size_t /* len (number_of_bits_in_bitmap) */);
|
||||||
|
/* Return a type descriptor for the object whose layout */
|
||||||
|
/* is described by the argument. */
|
||||||
|
/* The least significant bit of the first word is one */
|
||||||
|
/* if the first word in the object may be a pointer. */
|
||||||
|
/* The second argument specifies the number of */
|
||||||
|
/* meaningful bits in the bitmap. The actual object */
|
||||||
|
/* may be larger (but not smaller). Any additional */
|
||||||
|
/* words in the object are assumed not to contain */
|
||||||
|
/* pointers. */
|
||||||
|
/* Returns a conservative approximation in the */
|
||||||
|
/* (unlikely) case of insufficient memory to build */
|
||||||
|
/* the descriptor. Calls to GC_make_descriptor */
|
||||||
|
/* may consume some amount of a finite resource. This */
|
||||||
|
/* is intended to be called once per type, not once */
|
||||||
|
/* per allocation. */
|
||||||
|
|
||||||
|
/* It is possible to generate a descriptor for a C type T with */
|
||||||
|
/* word aligned pointer fields f1, f2, ... as follows: */
|
||||||
|
/* */
|
||||||
|
/* GC_descr T_descr; */
|
||||||
|
/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
|
||||||
|
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
|
||||||
|
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
|
||||||
|
/* ... */
|
||||||
|
/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */
|
||||||
|
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_malloc_explicitly_typed(size_t /* size_in_bytes */,
|
||||||
|
GC_descr /* d */);
|
||||||
|
/* Allocate an object whose layout is described by d. */
|
||||||
|
/* The size may NOT be less than the number of */
|
||||||
|
/* meaningful bits in the bitmap of d multiplied by */
|
||||||
|
/* sizeof GC_word. The returned object is cleared. */
|
||||||
|
/* The returned object may NOT be passed to GC_realloc. */
|
||||||
|
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||||
|
GC_malloc_explicitly_typed_ignore_off_page(size_t /* size_in_bytes */,
|
||||||
|
GC_descr /* d */);
|
||||||
|
|
||||||
|
GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL
|
||||||
|
GC_calloc_explicitly_typed(size_t /* nelements */,
|
||||||
|
size_t /* element_size_in_bytes */,
|
||||||
|
GC_descr /* d */);
|
||||||
|
/* Allocate an array of nelements elements, each of the */
|
||||||
|
/* given size, and with the given descriptor. */
|
||||||
|
/* The element size must be a multiple of the byte */
|
||||||
|
/* alignment required for pointers. E.g. on a 32-bit */
|
||||||
|
/* machine with 16-bit aligned pointers, size_in_bytes */
|
||||||
|
/* must be a multiple of 2. The element size may NOT */
|
||||||
|
/* be less than the number of meaningful bits in the */
|
||||||
|
/* bitmap of d multiplied by sizeof GC_word. */
|
||||||
|
/* Returned object is cleared. */
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes))
|
||||||
|
# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
|
||||||
|
((void)(d), GC_MALLOC((n) * (bytes)))
|
||||||
|
#else
|
||||||
|
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
|
||||||
|
GC_malloc_explicitly_typed(bytes, d)
|
||||||
|
# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
|
||||||
|
GC_calloc_explicitly_typed(n, bytes, d)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GC_TYPED_H */
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||||
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||||
|
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||||
|
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This should never be included directly; it is included only from gc.h. */
|
||||||
|
#if defined(GC_H)
|
||||||
|
|
||||||
|
/* The policy regarding version numbers: development code has odd */
|
||||||
|
/* "minor" number (and "micro" part is 0); when development is finished */
|
||||||
|
/* and a release is prepared, "minor" number is incremented (keeping */
|
||||||
|
/* "micro" number still zero), whenever a defect is fixed a new release */
|
||||||
|
/* is prepared incrementing "micro" part to odd value (the most stable */
|
||||||
|
/* release has the biggest "micro" number). */
|
||||||
|
|
||||||
|
/* The version here should match that in configure/configure.ac */
|
||||||
|
/* Eventually this one may become unnecessary. For now we need */
|
||||||
|
/* it to keep the old-style build process working. */
|
||||||
|
#define GC_TMP_VERSION_MAJOR 8
|
||||||
|
#define GC_TMP_VERSION_MINOR 2
|
||||||
|
#define GC_TMP_VERSION_MICRO 0 /* 8.2.0 */
|
||||||
|
|
||||||
|
#ifdef GC_VERSION_MAJOR
|
||||||
|
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \
|
||||||
|
|| GC_TMP_VERSION_MINOR != GC_VERSION_MINOR \
|
||||||
|
|| GC_TMP_VERSION_MICRO != GC_VERSION_MICRO
|
||||||
|
# error Inconsistent version info. Check README.md, include/gc_version.h and configure.ac.
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
|
||||||
|
# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
|
||||||
|
# define GC_VERSION_MICRO GC_TMP_VERSION_MICRO
|
||||||
|
#endif /* !GC_VERSION_MAJOR */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted to use or copy this program
|
||||||
|
* for any purpose, provided the above notices are retained on all copies.
|
||||||
|
* Permission to modify the code and to distribute modified code is granted,
|
||||||
|
* provided the above notices are retained, and a notice that the code was
|
||||||
|
* modified is included with the above copyright notice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GC_LEAK_DETECTOR_H
|
||||||
|
#define GC_LEAK_DETECTOR_H
|
||||||
|
|
||||||
|
/* Include leak_detector.h (e.g., via GCC --include directive) */
|
||||||
|
/* to turn BoehmGC into a Leak Detector. */
|
||||||
|
|
||||||
|
#ifndef GC_DEBUG
|
||||||
|
# define GC_DEBUG
|
||||||
|
#endif
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
|
#ifndef GC_DONT_INCLUDE_STDLIB
|
||||||
|
/* We ensure stdlib.h and string.h are included before */
|
||||||
|
/* redirecting malloc() and the accompanying functions. */
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef malloc
|
||||||
|
#define malloc(n) GC_MALLOC(n)
|
||||||
|
#undef calloc
|
||||||
|
#define calloc(m,n) GC_MALLOC((m)*(n))
|
||||||
|
#undef free
|
||||||
|
#define free(p) GC_FREE(p)
|
||||||
|
#undef realloc
|
||||||
|
#define realloc(p,n) GC_REALLOC(p,n)
|
||||||
|
|
||||||
|
#undef strdup
|
||||||
|
#define strdup(s) GC_STRDUP(s)
|
||||||
|
#undef strndup
|
||||||
|
#define strndup(s,n) GC_STRNDUP(s,n)
|
||||||
|
|
||||||
|
#ifdef GC_REQUIRE_WCSDUP
|
||||||
|
/* The collector should be built with GC_REQUIRE_WCSDUP */
|
||||||
|
/* defined as well to redirect wcsdup(). */
|
||||||
|
# include <wchar.h>
|
||||||
|
# undef wcsdup
|
||||||
|
# define wcsdup(s) GC_WCSDUP(s)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef memalign
|
||||||
|
#define memalign(a,n) GC_memalign(a,n)
|
||||||
|
#undef posix_memalign
|
||||||
|
#define posix_memalign(p,a,n) GC_posix_memalign(p,a,n)
|
||||||
|
|
||||||
|
#ifndef CHECK_LEAKS
|
||||||
|
# define CHECK_LEAKS() GC_gcollect()
|
||||||
|
/* Note 1: CHECK_LEAKS does not have GC prefix (preserved for */
|
||||||
|
/* backward compatibility). */
|
||||||
|
/* Note 2: GC_gcollect() is also called automatically in the */
|
||||||
|
/* leak-finding mode at program exit. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GC_LEAK_DETECTOR_H */
|
|
@ -1,65 +1,73 @@
|
||||||
module builtin
|
module builtin
|
||||||
|
|
||||||
$if freebsd {
|
$if dynamic_boehm ? {
|
||||||
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
|
$if windows {
|
||||||
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
|
||||||
$if !tinyc {
|
|
||||||
#flag -DGC_THREADS=1
|
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
|
||||||
#flag -lpthread
|
|
||||||
}
|
|
||||||
} $else {
|
|
||||||
#flag -DGC_THREADS=1
|
|
||||||
}
|
|
||||||
|
|
||||||
$if static_boehm ? {
|
|
||||||
$if macos {
|
|
||||||
#flag -I$first_existing("/opt/homebrew/include", "/usr/local/include")
|
|
||||||
#flag $first_existing("/opt/homebrew/lib/libgc.a", "/usr/local/lib/libgc.a")
|
|
||||||
} $else $if linux {
|
|
||||||
#flag -l:libgc.a
|
|
||||||
} $else $if openbsd {
|
|
||||||
#flag -I/usr/local/include
|
|
||||||
#flag /usr/local/lib/libgc.a
|
|
||||||
#flag -lpthread
|
|
||||||
} $else $if windows {
|
|
||||||
#flag -DGC_NOT_DLL=1
|
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -L@VEXEROOT/thirdparty/libgc
|
#flag -L@VEXEROOT/thirdparty/tcc/lib
|
||||||
#flag -lgc
|
#flag -lgc
|
||||||
} $else $if msvc {
|
} $else $if msvc {
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
} $else {
|
} $else {
|
||||||
|
#flag -DGC_WIN32_THREADS=1
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc
|
#flag -I@VEXEROOT/thirdparty/libgc
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
#flag -lgc
|
$if $pkgconfig('bdw-gc') {
|
||||||
|
#pkgconfig bdw-gc
|
||||||
|
} $else {
|
||||||
|
$if openbsd || freebsd {
|
||||||
|
#flag -I/usr/local/include
|
||||||
|
#flag -L/usr/local/lib
|
||||||
|
}
|
||||||
|
#flag -lgc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
$if macos {
|
#flag -DGC_THREADS=1
|
||||||
#pkgconfig bdw-gc
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
} $else $if openbsd || freebsd {
|
$if macos || linux {
|
||||||
|
#flag -DGC_PTHREADS=1
|
||||||
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
|
#flag -lpthread -ldl
|
||||||
|
$if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) {
|
||||||
|
// TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
|
||||||
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
|
} $else {
|
||||||
|
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
|
||||||
|
}
|
||||||
|
} $else $if freebsd {
|
||||||
|
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
|
||||||
|
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
||||||
|
#flag -DGC_PTHREADS=1
|
||||||
|
$if !tinyc {
|
||||||
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
|
} $else {
|
||||||
|
#flag -I/usr/local/include
|
||||||
|
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
||||||
|
}
|
||||||
|
#flag -lpthread
|
||||||
|
} $else $if openbsd {
|
||||||
#flag -I/usr/local/include
|
#flag -I/usr/local/include
|
||||||
#flag -L/usr/local/lib
|
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
||||||
}
|
#flag -lpthread
|
||||||
$if windows {
|
} $else $if windows {
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -L@VEXEROOT/thirdparty/libgc
|
#flag -L@VEXEROOT/thirdparty/tcc/lib
|
||||||
#flag -lgc
|
#flag -lgc
|
||||||
} $else $if msvc {
|
} $else {
|
||||||
|
#flag -DGC_NOT_DLL=1
|
||||||
|
#flag -DGC_WIN32_THREADS=1
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
} $else {
|
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc
|
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
}
|
}
|
||||||
|
} $else $if $pkgconfig('bdw-gc') {
|
||||||
|
#pkgconfig bdw-gc
|
||||||
} $else {
|
} $else {
|
||||||
#flag -lgc
|
#flag -lgc
|
||||||
}
|
}
|
||||||
|
@ -85,7 +93,7 @@ fn C.GC_REALLOC(ptr voidptr, n usize) voidptr
|
||||||
|
|
||||||
fn C.GC_FREE(ptr voidptr)
|
fn C.GC_FREE(ptr voidptr)
|
||||||
|
|
||||||
// explicitely perform garbage collection now! Garbage collections
|
// explicitly perform garbage collection now! Garbage collections
|
||||||
// are done automatically when needed, so this function is hardly needed
|
// are done automatically when needed, so this function is hardly needed
|
||||||
fn C.GC_gcollect()
|
fn C.GC_gcollect()
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) {
|
||||||
mut others := []string{}
|
mut others := []string{}
|
||||||
mut libs := []string{}
|
mut libs := []string{}
|
||||||
for copt in copts_without_obj_files {
|
for copt in copts_without_obj_files {
|
||||||
if copt.starts_with('-l') {
|
if copt.starts_with('-l') || copt.ends_with('.a') {
|
||||||
libs << copt
|
libs << copt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue