Compare commits

...

10 Commits

Author SHA1 Message Date
Jef Roosens 32d7ae7835
Made publish curl's failable
ci/woodpecker/push/vc Pipeline was successful Details
ci/woodpecker/push/docker Pipeline was successful Details
ci/woodpecker/push/arch Pipeline was successful Details
2022-04-19 12:42:44 +02:00
yuyi 168531d4e0
examples: fix optional in string interpolation and format error (#14079) 2022-04-19 12:42:44 +02:00
yuyi 1660be910d
token: minor cleanup of token.v (#14083) 2022-04-19 12:42:44 +02:00
yuyi 33005becf1
checker: check fn return type mismatch (#14081) 2022-04-19 12:42:44 +02:00
Nick Treleaven f291e5fdd8
checker: Revert part of small_unsigned == signed (#13967) (#14075)
`gcc -W` doesn't error for e.g. u16 == i32, only for u32 == i16.
Any u16 value can fit in an i32.
2022-04-19 12:42:43 +02:00
yuyi 898167f986
checker: check error for fn decl with optional arguments (#14076) 2022-04-19 12:42:43 +02:00
yuyi 77593d6c68
cgen: minor cleanup of infix_expr.v (#14070) 2022-04-19 12:42:43 +02:00
Delyan Angelov cc3740fda6
ci: update windows-install-sqlite.bat to latest sqlite 2022-04-19 12:42:43 +02:00
yuyi 0d4d4ffc2d
ast, checker, cgen: fix aggregations type check (#14066) 2022-04-19 12:42:43 +02:00
spaceface 090a9755db
builtin: compile the gc statically by default (#14063) 2022-04-19 12:42:43 +02:00
42 changed files with 26621 additions and 22241 deletions

View File

@ -131,7 +131,7 @@ jobs:
run: |
./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv
./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`
run: |
./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv

View File

@ -1,12 +1,11 @@
@echo off
curl -L https://www.sqlite.org/2020/sqlite-amalgamation-3320300.zip -o sqlite-amalgamation-3320300.zip
curl -L https://www.sqlite.org/2022/sqlite-amalgamation-3380200.zip -o sqlite-amalgamation-3380200.zip
unzip sqlite-amalgamation-3320300.zip -d thirdparty\
unzip sqlite-amalgamation-3380200.zip -d thirdparty\
del thirdparty\sqlite-amalgamation-3320300\shell.c
del thirdparty\sqlite-amalgamation-3380200\shell.c
move /y thirdparty\sqlite-amalgamation-3320300 thirdparty\sqlite
move /y thirdparty\sqlite-amalgamation-3380200 thirdparty\sqlite
dir thirdparty\sqlite

View File

@ -29,4 +29,4 @@ pipeline:
- 'vieter_api_key'
commands:
# Publish the package
- 'for pkg in $(ls -1 *.pkg*); do curl -XPOST -T "$pkg" -H "X-API-KEY: $VIETER_API_KEY" https://arch.r8r.be/vieter/publish; done'
- 'for pkg in $(ls -1 *.pkg*); do curl -f -XPOST -T "$pkg" -H "X-API-KEY: $VIETER_API_KEY" https://arch.r8r.be/vieter/publish; done'

View File

@ -8,8 +8,8 @@ fn main() {
conn.close() or {}
}
println(' peer: $conn.peer_addr()')
println('local: $conn.addr()')
println(' peer: ${conn.peer_addr() ?}')
println('local: ${conn.addr() ?}')
// Simple http HEAD request for a file
conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n') ?

View File

@ -2,6 +2,6 @@ import rand
fn main() {
for _ in 0 .. 10 {
println('${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}')
println('${rand.intn(255) ?}.${rand.intn(255) ?}.${rand.intn(255) ?}.${rand.intn(255) ?}')
}
}

42957
thirdparty/libgc/gc.c vendored

File diff suppressed because it is too large Load Diff

1081
thirdparty/libgc/gc.h vendored

File diff suppressed because it is too large Load Diff

2
thirdparty/libgc/include/gc.h vendored 100644
View File

@ -0,0 +1,2 @@
/* This file is installed for backward compatibility. */
#include <gc/gc.h>

View File

@ -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 */

View File

@ -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

View File

@ -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 */

2172
thirdparty/libgc/include/gc/gc.h vendored 100644

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -161,7 +161,7 @@ fn test_bf_from_str() {
output := bitfield.from_str(input)
mut result := 1
for i in 0 .. len {
if input[i] != u8(output.get_bit(i)) + 48 {
if input[i] != output.get_bit(i) + 48 {
result = 0
}
}

View File

@ -1,65 +1,73 @@
module builtin
$if freebsd {
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
#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 dynamic_boehm ? {
$if windows {
$if tinyc {
#flag -I@VEXEROOT/thirdparty/libgc/include
#flag -L@VEXEROOT/thirdparty/libgc
#flag -L@VEXEROOT/thirdparty/tcc/lib
#flag -lgc
} $else $if msvc {
#flag -DGC_BUILTIN_ATOMIC=1
#flag -I@VEXEROOT/thirdparty/libgc/include
} $else {
#flag -DGC_WIN32_THREADS=1
#flag -DGC_BUILTIN_ATOMIC=1
#flag -I@VEXEROOT/thirdparty/libgc
#flag @VEXEROOT/thirdparty/libgc/gc.o
}
} $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 {
$if macos {
#pkgconfig bdw-gc
} $else $if openbsd || freebsd {
#flag -DGC_THREADS=1
#flag -DGC_BUILTIN_ATOMIC=1
$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 -L/usr/local/lib
}
$if windows {
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
#flag -lpthread
} $else $if windows {
$if tinyc {
#flag -I@VEXEROOT/thirdparty/libgc/include
#flag -L@VEXEROOT/thirdparty/libgc
#flag -L@VEXEROOT/thirdparty/tcc/lib
#flag -lgc
} $else $if msvc {
} $else {
#flag -DGC_NOT_DLL=1
#flag -DGC_WIN32_THREADS=1
#flag -DGC_BUILTIN_ATOMIC=1
#flag -I@VEXEROOT/thirdparty/libgc/include
} $else {
#flag -DGC_BUILTIN_ATOMIC=1
#flag -I@VEXEROOT/thirdparty/libgc
#flag @VEXEROOT/thirdparty/libgc/gc.o
}
} $else $if $pkgconfig('bdw-gc') {
#pkgconfig bdw-gc
} $else {
#flag -lgc
}
@ -85,7 +93,7 @@ fn C.GC_REALLOC(ptr voidptr, n usize) 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
fn C.GC_gcollect()

View File

@ -288,8 +288,8 @@ fn (mut ctx Context) parse_events() {
if !C.GetConsoleScreenBufferInfo(ctx.stdout_handle, &sb) {
panic('could not get screenbuffer info')
}
w := int(sb.srWindow.Right - sb.srWindow.Left + 1)
h := int(sb.srWindow.Bottom - sb.srWindow.Top + 1)
w := sb.srWindow.Right - sb.srWindow.Left + 1
h := sb.srWindow.Bottom - sb.srWindow.Top + 1
utf8 := '($ctx.window_width, $ctx.window_height) -> ($w, $h)'
if w != ctx.window_width || h != ctx.window_height {
ctx.window_width, ctx.window_height = w, h

View File

@ -209,7 +209,8 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
break
}
CallExpr {
if sub_expr.args.len != 0 || sub_expr.concrete_types.len != 0 {
if sub_expr.args.len != 0 || sub_expr.concrete_types.len != 0
|| sub_expr.or_block.kind == .propagate || sub_expr.or_block.stmts.len > 0 {
needs_braces = true
} else if sub_expr.left is CallExpr {
sub_expr = sub_expr.left

View File

@ -937,7 +937,8 @@ pub struct Aggregate {
mut:
fields []StructField // used for faster lookup inside the module
pub:
types []Type
sum_type Type
types []Type
}
pub struct Array {

View File

@ -117,7 +117,7 @@ pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) {
mut others := []string{}
mut libs := []string{}
for copt in copts_without_obj_files {
if copt.starts_with('-l') {
if copt.starts_with('-l') || copt.ends_with('.a') {
libs << copt
continue
}

View File

@ -639,15 +639,6 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
rt := c.table.sym(right_type).name
c.error('negative value cannot be compared with `$rt`', node.left.pos)
}
} else if is_left_type_signed != is_right_type_signed
&& left_type.flip_signedness() != right_type {
// prevent e.g. `u16(-1) == int(-1)` which is false in C
if (is_right_type_signed && left_type in ast.int_promoted_type_idxs)
|| (is_left_type_signed && right_type in ast.int_promoted_type_idxs) {
lt := c.table.sym(left_type).name
rt := c.table.sym(right_type).name
c.error('`$lt` cannot be compared with `$rt`', node.pos)
}
}
}
}
@ -1013,6 +1004,10 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
if typ_sym.kind == .placeholder {
c.error('$op: type `$typ_sym.name` does not exist', right_expr.pos())
}
if left_sym.kind == .aggregate {
parent_left_type := (left_sym.info as ast.Aggregate).sum_type
left_sym = c.table.sym(parent_left_type)
}
if left_sym.kind !in [.interface_, .sum_type] {
c.error('`$op` can only be used with interfaces and sum types', node.pos)
} else if mut left_sym.info is ast.SumType {

View File

@ -181,6 +181,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.error('invalid use of reserved type `$param.name` as a parameter name',
param.pos)
}
if param.typ.has_flag(.optional) {
c.error('optional type argument is not supported currently', param.type_pos)
}
if !param.typ.is_ptr() { // value parameter, i.e. on stack - check for `[heap]`
arg_typ_sym := c.table.sym(param.typ)
if arg_typ_sym.kind == .struct_ {

View File

@ -296,7 +296,10 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
if right_type != ast.Type(0) {
left_sym := c.table.sym(node.left_type)
right_sym := c.table.sym(right_type)
expr_type := c.unwrap_generic(c.expr(node.left))
mut expr_type := c.unwrap_generic(c.expr(node.left))
if left_sym.kind == .aggregate {
expr_type = (left_sym.info as ast.Aggregate).sum_type
}
if left_sym.kind == .interface_ {
if right_sym.kind != .interface_ {
c.type_implements(right_type, expr_type, node.pos)

View File

@ -282,6 +282,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
kind: .aggregate
mod: c.mod
info: ast.Aggregate{
sum_type: node.cond_type
types: expr_types.map(it.typ)
}
})

View File

@ -32,7 +32,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
}
}
mut got_types := []ast.Type{}
for expr in node.exprs {
mut expr_idxs := []int{}
for i, expr in node.exprs {
typ := c.expr(expr)
if typ == ast.void_type {
c.error('`$expr` used as value', node.pos)
@ -42,9 +43,11 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if sym.kind == .multi_return {
for t in sym.mr_info().types {
got_types << t
expr_idxs << i
}
} else {
got_types << typ
expr_idxs << i
}
}
node.types = got_types
@ -82,7 +85,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
got_typ := c.unwrap_generic(got_types[i])
if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional)
|| c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := node.exprs[i].pos()
pos := node.exprs[expr_idxs[i]].pos()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument',
pos)
}
@ -93,19 +96,19 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if c.type_implements(got_typ, exp_type, node.pos) {
if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_
&& !c.inside_unsafe {
c.mark_as_referenced(mut &node.exprs[i], true)
c.mark_as_referenced(mut &node.exprs[expr_idxs[i]], true)
}
}
continue
}
pos := node.exprs[i].pos()
pos := node.exprs[expr_idxs[i]].pos()
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
pos)
}
if (got_typ.is_ptr() || got_typ.is_pointer())
&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
pos := node.exprs[i].pos()
if node.exprs[i].is_auto_deref_var() {
pos := node.exprs[expr_idxs[i]].pos()
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
continue
}
c.error('fn `$c.table.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
@ -114,8 +117,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if (exp_type.is_ptr() || exp_type.is_pointer())
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
&& !c.pref.translated && !c.file.is_translated {
pos := node.exprs[i].pos()
if node.exprs[i].is_auto_deref_var() {
pos := node.exprs[expr_idxs[i]].pos()
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
continue
}
c.error('fn `$c.table.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',

View File

@ -17,24 +17,10 @@ vlib/v/checker/tests/compare_unsigned_signed.vv:10:16: error: `u8` cannot be com
10 | _ = u8(-1) == -1 // false!
| ~~
11 | _ = -1 == u16(-1) // false!
12 |
12 | }
vlib/v/checker/tests/compare_unsigned_signed.vv:11:6: error: negative value cannot be compared with `u16`
9 | // unsigned == literal
10 | _ = u8(-1) == -1 // false!
11 | _ = -1 == u16(-1) // false!
| ~~
12 |
13 | // unsigned == signed
vlib/v/checker/tests/compare_unsigned_signed.vv:14:14: error: `u16` cannot be compared with `int`
12 |
13 | // unsigned == signed
14 | _ = u16(-1) == int(-1)
| ~~
15 | _ = int(-1) != u8(-1)
16 | }
vlib/v/checker/tests/compare_unsigned_signed.vv:15:14: error: `int` cannot be compared with `u8`
13 | // unsigned == signed
14 | _ = u16(-1) == int(-1)
15 | _ = int(-1) != u8(-1)
| ~~
16 | }
12 | }

View File

@ -9,8 +9,4 @@ fn main() {
// unsigned == literal
_ = u8(-1) == -1 // false!
_ = -1 == u16(-1) // false!
// unsigned == signed
_ = u16(-1) == int(-1)
_ = int(-1) != u8(-1)
}

View File

@ -0,0 +1,5 @@
vlib/v/checker/tests/fn_arg_of_optional_err.vv:1:19: error: optional type argument is not supported currently
1 | fn optional_arg(x ?int) {
| ^
2 | println('int type: $x')
3 | }

View File

@ -0,0 +1,7 @@
fn optional_arg(x ?int) {
println('int type: $x')
}
fn main() {
optional_arg(1)
}

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/fn_return_type_mismatch.vv:6:9: error: cannot use `i64` as type `int` in return argument
4 |
5 | fn func2() (int, int) {
6 | return func1()
| ~~~~~~~
7 | }
8 |

View File

@ -0,0 +1,9 @@
fn func1() (i64, i64) {
return i64(1), i64(2)
}
fn func2() (int, int) {
return func1()
}
fn main() {}

View File

@ -495,23 +495,32 @@ fn (mut g Gen) infix_expr_in_optimization(left ast.Expr, right ast.ArrayInit) {
// infix_expr_is_op generates code for `is` and `!is`
fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
sym := g.table.sym(node.left_type)
mut left_sym := g.table.sym(node.left_type)
is_aggregate := left_sym.kind == .aggregate
if is_aggregate {
parent_left_type := (left_sym.info as ast.Aggregate).sum_type
left_sym = g.table.sym(parent_left_type)
}
right_sym := g.table.sym(node.right_type)
if sym.kind == .interface_ && right_sym.kind == .interface_ {
if left_sym.kind == .interface_ && right_sym.kind == .interface_ {
g.gen_interface_is_op(node)
return
}
cmp_op := if node.op == .key_is { '==' } else { '!=' }
g.write('(')
g.expr(node.left)
if is_aggregate {
g.write('$node.left')
} else {
g.expr(node.left)
}
g.write(')')
if node.left_type.is_ptr() {
g.write('->')
} else {
g.write('.')
}
if sym.kind == .interface_ {
if left_sym.kind == .interface_ {
g.write('_typ $cmp_op ')
// `_Animal_Dog_index`
sub_type := match node.right {
@ -526,9 +535,9 @@ fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
}
}
sub_sym := g.table.sym(sub_type)
g.write('_${sym.cname}_${sub_sym.cname}_index')
g.write('_${left_sym.cname}_${sub_sym.cname}_index')
return
} else if sym.kind == .sum_type {
} else if left_sym.kind == .sum_type {
g.write('_typ $cmp_op ')
}
g.expr(node.right)

View File

@ -0,0 +1,19 @@
type Abc = bool | int | string
fn test_aggregate_is_nodetype() {
x := Abc('test')
match x {
string, int {
if x is string {
println('it is a string')
assert true
} else {
assert false
}
}
else {
assert false
}
}
}

View File

@ -133,12 +133,6 @@ pub enum Kind {
_end_
}
pub const assign_tokens = [Kind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign,
.xor_assign, .mod_assign, .or_assign, .and_assign, .right_shift_assign, .left_shift_assign,
.unsigned_right_shift_assign]
const nr_tokens = int(Kind._end_)
// @FN => will be substituted with the name of the current V function
// @METHOD => will be substituted with ReceiverType.MethodName
// @MOD => will be substituted with the name of the current V module
@ -179,8 +173,20 @@ pub enum AtKind {
vexeroot_path
}
pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
'@VEXE', '@FILE', '@LINE', '@COLUMN', '@VHASH', '@VMOD_FILE']
pub const (
assign_tokens = [Kind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign,
.xor_assign, .mod_assign, .or_assign, .and_assign, .right_shift_assign, .left_shift_assign,
.unsigned_right_shift_assign]
valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
'@VEXE', '@FILE', '@LINE', '@COLUMN', '@VHASH', '@VMOD_FILE']
token_str = build_token_str()
keywords = build_keys()
matcher = new_keywords_matcher<Kind>(keywords)
)
// build_keys genereates a map with keywords' string values:
// Keywords['return'] == .key_return
@ -195,7 +201,7 @@ fn build_keys() map[string]Kind {
// TODO remove once we have `enum Kind { name('name') if('if') ... }`
fn build_token_str() []string {
mut s := []string{len: token.nr_tokens}
mut s := []string{len: int(Kind._end_)}
s[Kind.unknown] = 'unknown'
s[Kind.eof] = 'eof'
s[Kind.name] = 'name'
@ -323,12 +329,6 @@ fn build_token_str() []string {
return s
}
pub const token_str = build_token_str()
pub const keywords = build_keys()
pub const matcher = new_keywords_matcher<Kind>(keywords)
[inline]
pub fn is_key(key string) bool {
return int(token.keywords[key]) > 0
@ -620,122 +620,122 @@ pub fn kind_to_string(k Kind) string {
}
pub fn kind_from_string(s string) ?Kind {
match s {
'unknown' { return .unknown }
'eof' { return .eof }
'name' { return .name }
'number' { return .number }
'string' { return .string }
'str_inter' { return .str_inter }
'chartoken' { return .chartoken }
'plus' { return .plus }
'minus' { return .minus }
'mul' { return .mul }
'div' { return .div }
'mod' { return .mod }
'xor' { return .xor }
'pipe' { return .pipe }
'inc' { return .inc }
'dec' { return .dec }
'and' { return .and }
'logical_or' { return .logical_or }
'not' { return .not }
'bit_not' { return .bit_not }
'question' { return .question }
'comma' { return .comma }
'semicolon' { return .semicolon }
'colon' { return .colon }
'arrow' { return .arrow }
'amp' { return .amp }
'hash' { return .hash }
'dollar' { return .dollar }
'at' { return .at }
'str_dollar' { return .str_dollar }
'left_shift' { return .left_shift }
'right_shift' { return .right_shift }
'unsigned_right_shift' { return .unsigned_right_shift }
'not_in' { return .not_in }
'not_is' { return .not_is }
'assign' { return .assign }
'decl_assign' { return .decl_assign }
'plus_assign' { return .plus_assign }
'minus_assign' { return .minus_assign }
'div_assign' { return .div_assign }
'mult_assign' { return .mult_assign }
'xor_assign' { return .xor_assign }
'mod_assign' { return .mod_assign }
'or_assign' { return .or_assign }
'and_assign' { return .and_assign }
'right_shift_assign' { return .right_shift_assign }
'left_shift_assign' { return .left_shift_assign }
'unsigned_right_shift_assign' { return .unsigned_right_shift_assign }
'lcbr' { return .lcbr }
'rcbr' { return .rcbr }
'lpar' { return .lpar }
'rpar' { return .rpar }
'lsbr' { return .lsbr }
'nilsbr' { return .nilsbr }
'rsbr' { return .rsbr }
'eq' { return .eq }
'ne' { return .ne }
'gt' { return .gt }
'lt' { return .lt }
'ge' { return .ge }
'le' { return .le }
'comment' { return .comment }
'nl' { return .nl }
'dot' { return .dot }
'dotdot' { return .dotdot }
'ellipsis' { return .ellipsis }
'keyword_beg' { return .keyword_beg }
'key_as' { return .key_as }
'key_asm' { return .key_asm }
'key_assert' { return .key_assert }
'key_atomic' { return .key_atomic }
'key_break' { return .key_break }
'key_const' { return .key_const }
'key_continue' { return .key_continue }
'key_defer' { return .key_defer }
'key_else' { return .key_else }
'key_enum' { return .key_enum }
'key_false' { return .key_false }
'key_for' { return .key_for }
'key_fn' { return .key_fn }
'key_global' { return .key_global }
'key_go' { return .key_go }
'key_goto' { return .key_goto }
'key_if' { return .key_if }
'key_import' { return .key_import }
'key_in' { return .key_in }
'key_interface' { return .key_interface }
'key_is' { return .key_is }
'key_match' { return .key_match }
'key_module' { return .key_module }
'key_mut' { return .key_mut }
'key_shared' { return .key_shared }
'key_lock' { return .key_lock }
'key_rlock' { return .key_rlock }
'key_none' { return .key_none }
'key_return' { return .key_return }
'key_select' { return .key_select }
'key_sizeof' { return .key_sizeof }
'key_isreftype' { return .key_isreftype }
'key_likely' { return .key_likely }
'key_unlikely' { return .key_unlikely }
'key_offsetof' { return .key_offsetof }
'key_struct' { return .key_struct }
'key_true' { return .key_true }
'key_type' { return .key_type }
'key_typeof' { return .key_typeof }
'key_dump' { return .key_dump }
'key_orelse' { return .key_orelse }
'key_union' { return .key_union }
'key_pub' { return .key_pub }
'key_static' { return .key_static }
'key_volatile' { return .key_volatile }
'key_unsafe' { return .key_unsafe }
'keyword_end' { return .keyword_end }
'_end_' { return ._end_ }
else { return error('unknown') }
return match s {
'unknown' { .unknown }
'eof' { .eof }
'name' { .name }
'number' { .number }
'string' { .string }
'str_inter' { .str_inter }
'chartoken' { .chartoken }
'plus' { .plus }
'minus' { .minus }
'mul' { .mul }
'div' { .div }
'mod' { .mod }
'xor' { .xor }
'pipe' { .pipe }
'inc' { .inc }
'dec' { .dec }
'and' { .and }
'logical_or' { .logical_or }
'not' { .not }
'bit_not' { .bit_not }
'question' { .question }
'comma' { .comma }
'semicolon' { .semicolon }
'colon' { .colon }
'arrow' { .arrow }
'amp' { .amp }
'hash' { .hash }
'dollar' { .dollar }
'at' { .at }
'str_dollar' { .str_dollar }
'left_shift' { .left_shift }
'right_shift' { .right_shift }
'unsigned_right_shift' { .unsigned_right_shift }
'not_in' { .not_in }
'not_is' { .not_is }
'assign' { .assign }
'decl_assign' { .decl_assign }
'plus_assign' { .plus_assign }
'minus_assign' { .minus_assign }
'div_assign' { .div_assign }
'mult_assign' { .mult_assign }
'xor_assign' { .xor_assign }
'mod_assign' { .mod_assign }
'or_assign' { .or_assign }
'and_assign' { .and_assign }
'right_shift_assign' { .right_shift_assign }
'left_shift_assign' { .left_shift_assign }
'unsigned_right_shift_assign' { .unsigned_right_shift_assign }
'lcbr' { .lcbr }
'rcbr' { .rcbr }
'lpar' { .lpar }
'rpar' { .rpar }
'lsbr' { .lsbr }
'nilsbr' { .nilsbr }
'rsbr' { .rsbr }
'eq' { .eq }
'ne' { .ne }
'gt' { .gt }
'lt' { .lt }
'ge' { .ge }
'le' { .le }
'comment' { .comment }
'nl' { .nl }
'dot' { .dot }
'dotdot' { .dotdot }
'ellipsis' { .ellipsis }
'keyword_beg' { .keyword_beg }
'key_as' { .key_as }
'key_asm' { .key_asm }
'key_assert' { .key_assert }
'key_atomic' { .key_atomic }
'key_break' { .key_break }
'key_const' { .key_const }
'key_continue' { .key_continue }
'key_defer' { .key_defer }
'key_else' { .key_else }
'key_enum' { .key_enum }
'key_false' { .key_false }
'key_for' { .key_for }
'key_fn' { .key_fn }
'key_global' { .key_global }
'key_go' { .key_go }
'key_goto' { .key_goto }
'key_if' { .key_if }
'key_import' { .key_import }
'key_in' { .key_in }
'key_interface' { .key_interface }
'key_is' { .key_is }
'key_match' { .key_match }
'key_module' { .key_module }
'key_mut' { .key_mut }
'key_shared' { .key_shared }
'key_lock' { .key_lock }
'key_rlock' { .key_rlock }
'key_none' { .key_none }
'key_return' { .key_return }
'key_select' { .key_select }
'key_sizeof' { .key_sizeof }
'key_isreftype' { .key_isreftype }
'key_likely' { .key_likely }
'key_unlikely' { .key_unlikely }
'key_offsetof' { .key_offsetof }
'key_struct' { .key_struct }
'key_true' { .key_true }
'key_type' { .key_type }
'key_typeof' { .key_typeof }
'key_dump' { .key_dump }
'key_orelse' { .key_orelse }
'key_union' { .key_union }
'key_pub' { .key_pub }
'key_static' { .key_static }
'key_volatile' { .key_volatile }
'key_unsafe' { .key_unsafe }
'keyword_end' { .keyword_end }
'_end_' { ._end_ }
else { error('unknown') }
}
}

View File

@ -778,7 +778,7 @@ pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
}
}
if count == int(glyph.contour_ends[c]) {
if count == glyph.contour_ends[c] {
// dprintln("count == glyph.contour_ends[count]")
if s == 2 { // final point was off-curve. connect to start