diff options
Diffstat (limited to 'internal')
50 files changed, 4408 insertions, 0 deletions
diff --git a/internal/array.h b/internal/array.h new file mode 100644 index 0000000000..60f66f31bf --- /dev/null +++ b/internal/array.h @@ -0,0 +1,113 @@ +#ifndef INTERNAL_ARRAY_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ARRAY_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Array. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for RARRAY_LEN */ + +#ifndef ARRAY_DEBUG +# define ARRAY_DEBUG (0+RUBY_DEBUG) +#endif + +#define RARRAY_PTR_IN_USE_FLAG FL_USER14 + +/* array.c */ +VALUE rb_ary_last(int, const VALUE *, VALUE); +void rb_ary_set_len(VALUE, long); +void rb_ary_delete_same(VALUE, VALUE); +VALUE rb_ary_tmp_new_fill(long capa); +VALUE rb_ary_at(VALUE, VALUE); +size_t rb_ary_memsize(VALUE); +VALUE rb_to_array_type(VALUE obj); +VALUE rb_to_array(VALUE obj); +void rb_ary_cancel_sharing(VALUE ary); + +static inline VALUE rb_ary_entry_internal(VALUE ary, long offset); +static inline bool ARY_PTR_USING_P(VALUE ary); +static inline void RARY_TRANSIENT_SET(VALUE ary); +static inline void RARY_TRANSIENT_UNSET(VALUE ary); + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *); +VALUE rb_check_to_array(VALUE ary); +VALUE rb_ary_behead(VALUE, long); +VALUE rb_ary_aref1(VALUE ary, VALUE i); + +struct rb_execution_context_struct; +VALUE rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts); +MJIT_SYMBOL_EXPORT_END + +// YJIT needs this function to never allocate and never raise +static inline VALUE +rb_ary_entry_internal(VALUE ary, long offset) +{ + long len = RARRAY_LEN(ary); + const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + if (len == 0) return Qnil; + if (offset < 0) { + offset += len; + if (offset < 0) return Qnil; + } + else if (len <= offset) { + return Qnil; + } + return ptr[offset]; +} + +static inline bool +ARY_PTR_USING_P(VALUE ary) +{ + return FL_TEST_RAW(ary, RARRAY_PTR_IN_USE_FLAG); +} + +static inline void +RARY_TRANSIENT_SET(VALUE ary) +{ +#if USE_TRANSIENT_HEAP + FL_SET_RAW(ary, RARRAY_TRANSIENT_FLAG); +#endif +} + +static inline void +RARY_TRANSIENT_UNSET(VALUE ary) +{ +#if USE_TRANSIENT_HEAP + FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG); +#endif +} + +#undef rb_ary_new_from_args +#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments") +# /* Skip it; clang -pedantic doesn't like the following */ +#elif defined(__GNUC__) && defined(HAVE_VA_ARGS_MACRO) +#define rb_ary_new_from_args(n, ...) \ + __extension__ ({ \ + const VALUE args_to_new_ary[] = {__VA_ARGS__}; \ + if (__builtin_constant_p(n)) { \ + STATIC_ASSERT(rb_ary_new_from_args, numberof(args_to_new_ary) == (n)); \ + } \ + rb_ary_new_from_values(numberof(args_to_new_ary), args_to_new_ary); \ + }) +#endif + +#undef RARRAY_AREF +RBIMPL_ATTR_PURE_UNLESS_DEBUG() +RBIMPL_ATTR_ARTIFICIAL() +static inline VALUE +RARRAY_AREF(VALUE ary, long i) +{ + RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); + + return RARRAY_CONST_PTR_TRANSIENT(ary)[i]; +} + +#endif /* INTERNAL_ARRAY_H */ diff --git a/internal/bignum.h b/internal/bignum.h new file mode 100644 index 0000000000..5cd35ede8a --- /dev/null +++ b/internal/bignum.h @@ -0,0 +1,246 @@ +#ifndef INTERNAL_BIGNUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BIGNUM_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Bignums. + */ +#include "ruby/internal/config.h" /* for HAVE_LIBGMP */ +#include <stddef.h> /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> /* for ssize_t (note: on Windows ssize_t is */ +#endif /* `#define`d in ruby/config.h) */ + +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for struct RBasic */ + +#ifndef BDIGIT +# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG +# define BDIGIT unsigned int +# define SIZEOF_BDIGIT SIZEOF_INT +# define BDIGIT_DBL unsigned LONG_LONG +# define BDIGIT_DBL_SIGNED LONG_LONG +# define PRI_BDIGIT_PREFIX "" +# define PRI_BDIGIT_DBL_PREFIX PRI_LL_PREFIX +# elif SIZEOF_INT*2 <= SIZEOF_LONG +# define BDIGIT unsigned int +# define SIZEOF_BDIGIT SIZEOF_INT +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "" +# define PRI_BDIGIT_DBL_PREFIX "l" +# elif SIZEOF_SHORT*2 <= SIZEOF_LONG +# define BDIGIT unsigned short +# define SIZEOF_BDIGIT SIZEOF_SHORT +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "h" +# define PRI_BDIGIT_DBL_PREFIX "l" +# else +# define BDIGIT unsigned short +# define SIZEOF_BDIGIT (SIZEOF_LONG/2) +# define SIZEOF_ACTUAL_BDIGIT SIZEOF_LONG +# define BDIGIT_DBL unsigned long +# define BDIGIT_DBL_SIGNED long +# define PRI_BDIGIT_PREFIX "h" +# define PRI_BDIGIT_DBL_PREFIX "l" +# endif +#endif + +#ifndef SIZEOF_ACTUAL_BDIGIT +# define SIZEOF_ACTUAL_BDIGIT SIZEOF_BDIGIT +#endif + +#ifdef PRI_BDIGIT_PREFIX +# define PRIdBDIGIT PRI_BDIGIT_PREFIX"d" +# define PRIiBDIGIT PRI_BDIGIT_PREFIX"i" +# define PRIoBDIGIT PRI_BDIGIT_PREFIX"o" +# define PRIuBDIGIT PRI_BDIGIT_PREFIX"u" +# define PRIxBDIGIT PRI_BDIGIT_PREFIX"x" +# define PRIXBDIGIT PRI_BDIGIT_PREFIX"X" +#endif + +#ifdef PRI_BDIGIT_DBL_PREFIX +# define PRIdBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"d" +# define PRIiBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"i" +# define PRIoBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"o" +# define PRIuBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"u" +# define PRIxBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"x" +# define PRIXBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"X" +#endif + +#define RBIGNUM(obj) ((struct RBignum *)(obj)) +#define BIGNUM_SIGN_BIT FL_USER1 +#define BIGNUM_EMBED_FLAG ((VALUE)FL_USER2) +#define BIGNUM_EMBED_LEN_NUMBITS 3 +#define BIGNUM_EMBED_LEN_MASK \ + (~(~(VALUE)0U << BIGNUM_EMBED_LEN_NUMBITS) << BIGNUM_EMBED_LEN_SHIFT) +#define BIGNUM_EMBED_LEN_SHIFT \ + (FL_USHIFT+3) /* bit offset of BIGNUM_EMBED_LEN_MASK */ +#ifndef BIGNUM_EMBED_LEN_MAX +# if (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) < (1 << BIGNUM_EMBED_LEN_NUMBITS)-1 +# define BIGNUM_EMBED_LEN_MAX (SIZEOF_VALUE*RBIMPL_RVALUE_EMBED_LEN_MAX/SIZEOF_ACTUAL_BDIGIT) +# else +# define BIGNUM_EMBED_LEN_MAX ((1 << BIGNUM_EMBED_LEN_NUMBITS)-1) +# endif +#endif + +enum rb_int_parse_flags { + RB_INT_PARSE_SIGN = 0x01, + RB_INT_PARSE_UNDERSCORE = 0x02, + RB_INT_PARSE_PREFIX = 0x04, + RB_INT_PARSE_ALL = 0x07, + RB_INT_PARSE_DEFAULT = 0x07, +}; + +struct RBignum { + struct RBasic basic; + union { + struct { + size_t len; + BDIGIT *digits; + } heap; + BDIGIT ary[BIGNUM_EMBED_LEN_MAX]; + } as; +}; + +/* bignum.c */ +extern const char ruby_digitmap[]; +double rb_big_fdiv_double(VALUE x, VALUE y); +VALUE rb_big_uminus(VALUE x); +VALUE rb_big_hash(VALUE); +VALUE rb_big_odd_p(VALUE); +VALUE rb_big_even_p(VALUE); +size_t rb_big_size(VALUE); +VALUE rb_integer_float_cmp(VALUE x, VALUE y); +VALUE rb_integer_float_eq(VALUE x, VALUE y); +VALUE rb_str_convert_to_inum(VALUE str, int base, int badcheck, int raise_exception); +VALUE rb_big_comp(VALUE x); +VALUE rb_big_aref(VALUE x, VALUE y); +VALUE rb_big_abs(VALUE x); +VALUE rb_big_size_m(VALUE big); +VALUE rb_big_bit_length(VALUE big); +VALUE rb_big_remainder(VALUE x, VALUE y); +VALUE rb_big_gt(VALUE x, VALUE y); +VALUE rb_big_ge(VALUE x, VALUE y); +VALUE rb_big_lt(VALUE x, VALUE y); +VALUE rb_big_le(VALUE x, VALUE y); +VALUE rb_int_powm(int const argc, VALUE * const argv, VALUE const num); +VALUE rb_big_isqrt(VALUE n); +static inline bool BIGNUM_SIGN(VALUE b); +static inline bool BIGNUM_POSITIVE_P(VALUE b); +static inline bool BIGNUM_NEGATIVE_P(VALUE b); +static inline void BIGNUM_SET_SIGN(VALUE b, bool sign); +static inline void BIGNUM_NEGATE(VALUE b); +static inline size_t BIGNUM_LEN(VALUE b); +static inline BDIGIT *BIGNUM_DIGITS(VALUE b); +static inline int BIGNUM_LENINT(VALUE b); +static inline bool BIGNUM_EMBED_P(VALUE b); + +RUBY_SYMBOL_EXPORT_BEGIN +/* bignum.c (export) */ +VALUE rb_big_mul_normal(VALUE x, VALUE y); +VALUE rb_big_mul_balance(VALUE x, VALUE y); +VALUE rb_big_mul_karatsuba(VALUE x, VALUE y); +VALUE rb_big_mul_toom3(VALUE x, VALUE y); +VALUE rb_big_sq_fast(VALUE x); +VALUE rb_big_divrem_normal(VALUE x, VALUE y); +VALUE rb_big2str_poweroftwo(VALUE x, int base); +VALUE rb_big2str_generic(VALUE x, int base); +VALUE rb_str2big_poweroftwo(VALUE arg, int base, int badcheck); +VALUE rb_str2big_normal(VALUE arg, int base, int badcheck); +VALUE rb_str2big_karatsuba(VALUE arg, int base, int badcheck); +#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H) +VALUE rb_big_mul_gmp(VALUE x, VALUE y); +VALUE rb_big_divrem_gmp(VALUE x, VALUE y); +VALUE rb_big2str_gmp(VALUE x, int base); +VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck); +#endif +VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +#if defined(HAVE_INT128_T) +VALUE rb_int128t2big(int128_t n); +#endif +MJIT_SYMBOL_EXPORT_END + +/* sign: positive:1, negative:0 */ +static inline bool +BIGNUM_SIGN(VALUE b) +{ + return FL_TEST_RAW(b, BIGNUM_SIGN_BIT); +} + +static inline bool +BIGNUM_POSITIVE_P(VALUE b) +{ + return BIGNUM_SIGN(b); +} + +static inline bool +BIGNUM_NEGATIVE_P(VALUE b) +{ + return ! BIGNUM_POSITIVE_P(b); +} + +static inline void +BIGNUM_SET_SIGN(VALUE b, bool sign) +{ + if (sign) { + FL_SET_RAW(b, BIGNUM_SIGN_BIT); + } + else { + FL_UNSET_RAW(b, BIGNUM_SIGN_BIT); + } +} + +static inline void +BIGNUM_NEGATE(VALUE b) +{ + FL_REVERSE_RAW(b, BIGNUM_SIGN_BIT); +} + +static inline size_t +BIGNUM_LEN(VALUE b) +{ + if (! BIGNUM_EMBED_P(b)) { + return RBIGNUM(b)->as.heap.len; + } + else { + size_t ret = RBASIC(b)->flags; + ret &= BIGNUM_EMBED_LEN_MASK; + ret >>= BIGNUM_EMBED_LEN_SHIFT; + return ret; + } +} + +static inline int +BIGNUM_LENINT(VALUE b) +{ + return rb_long2int(BIGNUM_LEN(b)); +} + +/* LSB:BIGNUM_DIGITS(b)[0], MSB:BIGNUM_DIGITS(b)[BIGNUM_LEN(b)-1] */ +static inline BDIGIT * +BIGNUM_DIGITS(VALUE b) +{ + if (BIGNUM_EMBED_P(b)) { + return RBIGNUM(b)->as.ary; + } + else { + return RBIGNUM(b)->as.heap.digits; + } +} + +static inline bool +BIGNUM_EMBED_P(VALUE b) +{ + return FL_TEST_RAW(b, BIGNUM_EMBED_FLAG); +} + +#endif /* INTERNAL_BIGNUM_H */ diff --git a/internal/bits.h b/internal/bits.h new file mode 100644 index 0000000000..2602ff7a31 --- /dev/null +++ b/internal/bits.h @@ -0,0 +1,565 @@ +#ifndef INTERNAL_BITS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BITS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for bitwise integer algorithms. + * @see Henry S. Warren Jr., "Hacker's Delight" (2nd ed.), 2013. + * @see SEI CERT C Coding Standard INT32-C. "Ensure that operations on + * signed integers do not result in overflow" + * @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html + * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateleft + * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateright + * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort + * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanreverse-bitscanreverse64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/lzcnt16-lzcnt-lzcnt64 + * @see https://docs.microsoft.com/en-us/cpp/intrinsics/popcnt16-popcnt-popcnt64 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_lzcnt_u32 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_tzcnt_u32 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotl64 + * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotr64 + * @see https://stackoverflow.com/a/776523 + */ +#include "ruby/internal/config.h" +#include <limits.h> /* for CHAR_BITS */ +#include <stdint.h> /* for uintptr_t */ +#include "internal/compilers.h" /* for MSC_VERSION_SINCE */ + +#if MSC_VERSION_SINCE(1310) +# include <stdlib.h> /* for _byteswap_uint64 */ +#endif + +#if defined(HAVE_X86INTRIN_H) && ! defined(MJIT_HEADER) +# /* Rule out MJIT_HEADER, which does not interface well with <immintrin.h> */ +# include <x86intrin.h> /* for _lzcnt_u64 */ +#elif MSC_VERSION_SINCE(1310) +# include <intrin.h> /* for the following intrinsics */ +#endif + +#if defined(_MSC_VER) && defined(__AVX__) +# pragma intrinsic(__popcnt) +# pragma intrinsic(__popcnt64) +#endif + +#if defined(_MSC_VER) && defined(__AVX2__) +# pragma intrinsic(__lzcnt) +# pragma intrinsic(__lzcnt64) +#endif + +#if MSC_VERSION_SINCE(1310) +# pragma intrinsic(_rotl) +# pragma intrinsic(_rotr) +# ifdef _WIN64 +# pragma intrinsic(_rotl64) +# pragma intrinsic(_rotr64) +# endif +#endif + +#if MSC_VERSION_SINCE(1400) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# ifdef _WIN64 +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +#endif + +#include "ruby/ruby.h" /* for VALUE */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ + +/* The most significant bit of the lower part of half-long integer. + * If sizeof(long) == 4, this is 0x8000. + * If sizeof(long) == 8, this is 0x80000000. + */ +#define HALF_LONG_MSB ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2)) + +#define SIGNED_INTEGER_TYPE_P(T) (0 > ((T)0)-1) + +#define SIGNED_INTEGER_MIN(T) \ + ((sizeof(T) == sizeof(int8_t)) ? ((T)INT8_MIN) : \ + ((sizeof(T) == sizeof(int16_t)) ? ((T)INT16_MIN) : \ + ((sizeof(T) == sizeof(int32_t)) ? ((T)INT32_MIN) : \ + ((sizeof(T) == sizeof(int64_t)) ? ((T)INT64_MIN) : \ + 0)))) + +#define SIGNED_INTEGER_MAX(T) ((T)(SIGNED_INTEGER_MIN(T) ^ ((T)~(T)0))) + +#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0) + +#if __has_builtin(__builtin_mul_overflow_p) +# define MUL_OVERFLOW_P(a, b) \ + __builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0) +#elif __has_builtin(__builtin_mul_overflow) +# define MUL_OVERFLOW_P(a, b) \ + __extension__ ({ __typeof__(a) c; __builtin_mul_overflow((a), (b), &c); }) +#endif + +#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \ + (a) == 0 ? 0 : \ + (a) == -1 ? (b) < -(max) : \ + (a) > 0 ? \ + ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \ + ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b))) + +#if __has_builtin(__builtin_mul_overflow_p) +/* __builtin_mul_overflow_p can take bitfield */ +/* and GCC permits bitfields for integers other than int */ +# define MUL_OVERFLOW_FIXNUM_P(a, b) \ + __extension__ ({ \ + struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \ + __builtin_mul_overflow_p((a), (b), c.fixnum); \ + }) +#else +# define MUL_OVERFLOW_FIXNUM_P(a, b) \ + MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX) +#endif + +#ifdef MUL_OVERFLOW_P +# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b) +# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b) +# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b) +#else +# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX) +# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX) +# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX) +#endif + +#ifdef HAVE_UINT128_T +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \ + 128 - nlz_int128((uint128_t)(x))) +#else +# define bit_length(x) \ + (unsigned int) \ + (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \ + 64 - nlz_int64((uint64_t)(x))) +#endif + +#ifndef swap16 +# define swap16 ruby_swap16 +#endif + +#ifndef swap32 +# define swap32 ruby_swap32 +#endif + +#ifndef swap64 +# define swap64 ruby_swap64 +#endif + +static inline uint16_t ruby_swap16(uint16_t); +static inline uint32_t ruby_swap32(uint32_t); +static inline uint64_t ruby_swap64(uint64_t); +static inline unsigned nlz_int(unsigned x); +static inline unsigned nlz_long(unsigned long x); +static inline unsigned nlz_long_long(unsigned long long x); +static inline unsigned nlz_intptr(uintptr_t x); +static inline unsigned nlz_int32(uint32_t x); +static inline unsigned nlz_int64(uint64_t x); +#ifdef HAVE_UINT128_T +static inline unsigned nlz_int128(uint128_t x); +#endif +static inline unsigned rb_popcount32(uint32_t x); +static inline unsigned rb_popcount64(uint64_t x); +static inline unsigned rb_popcount_intptr(uintptr_t x); +static inline int ntz_int32(uint32_t x); +static inline int ntz_int64(uint64_t x); +static inline int ntz_intptr(uintptr_t x); +static inline VALUE RUBY_BIT_ROTL(VALUE, int); +static inline VALUE RUBY_BIT_ROTR(VALUE, int); + +static inline uint16_t +ruby_swap16(uint16_t x) +{ +#if __has_builtin(__builtin_bswap16) + return __builtin_bswap16(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_ushort(x); + +#else + return (x << 8) | (x >> 8); + +#endif +} + +static inline uint32_t +ruby_swap32(uint32_t x) +{ +#if __has_builtin(__builtin_bswap32) + return __builtin_bswap32(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_ulong(x); + +#else + x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16); + x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8); + return x; + +#endif +} + +static inline uint64_t +ruby_swap64(uint64_t x) +{ +#if __has_builtin(__builtin_bswap64) + return __builtin_bswap64(x); + +#elif MSC_VERSION_SINCE(1310) + return _byteswap_uint64(x); + +#else + x = ((x & 0x00000000FFFFFFFFULL) << 32) | ((x & 0xFFFFFFFF00000000ULL) >> 32); + x = ((x & 0x0000FFFF0000FFFFULL) << 16) | ((x & 0xFFFF0000FFFF0000ULL) >> 16); + x = ((x & 0x00FF00FF00FF00FFULL) << 8) | ((x & 0xFF00FF00FF00FF00ULL) >> 8); + return x; + +#endif +} + +static inline unsigned int +nlz_int32(uint32_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) + /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC. + * AMD CPUs have had this instruction for decades (since K10) but for + * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum + * safety. */ + return (unsigned int)__lzcnt(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER) + return (unsigned int)_lzcnt_u32(x); + +#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ + unsigned long r; + return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; + +#elif __has_builtin(__builtin_clz) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32); + return x ? (unsigned int)__builtin_clz(x) : 32; + +#else + uint32_t y; + unsigned n = 32; + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); +#endif +} + +static inline unsigned int +nlz_int64(uint64_t x) +{ +#if defined(_MSC_VER) && defined(__AVX2__) + return (unsigned int)__lzcnt64(x); + +#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER) + return (unsigned int)_lzcnt_u64(x); + +#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ + unsigned long r; + return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; + +#elif __has_builtin(__builtin_clzl) + if (x == 0) { + return 64; + } + else if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_clzll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + uint64_t y; + unsigned int n = 64; + y = x >> 32; if (y) {n -= 32; x = y;} + y = x >> 16; if (y) {n -= 16; x = y;} + y = x >> 8; if (y) {n -= 8; x = y;} + y = x >> 4; if (y) {n -= 4; x = y;} + y = x >> 2; if (y) {n -= 2; x = y;} + y = x >> 1; if (y) {return n - 2;} + return (unsigned int)(n - x); + +#endif +} + +#ifdef HAVE_UINT128_T +static inline unsigned int +nlz_int128(uint128_t x) +{ + uint64_t y = (uint64_t)(x >> 64); + + if (x == 0) { + return 128; + } + else if (y == 0) { + return (unsigned int)nlz_int64(x) + 64; + } + else { + return (unsigned int)nlz_int64(y); + } +} +#endif + +static inline unsigned int +nlz_int(unsigned int x) +{ + if (sizeof(unsigned int) * CHAR_BIT == 32) { + return nlz_int32((uint32_t)x); + } + else if (sizeof(unsigned int) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_long(unsigned long x) +{ + if (sizeof(unsigned long) * CHAR_BIT == 32) { + return nlz_int32((uint32_t)x); + } + else if (sizeof(unsigned long) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_long_long(unsigned long long x) +{ + if (sizeof(unsigned long long) * CHAR_BIT == 64) { + return nlz_int64((uint64_t)x); + } +#ifdef HAVE_UINT128_T + else if (sizeof(unsigned long long) * CHAR_BIT == 128) { + return nlz_int128((uint128_t)x); + } +#endif + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +nlz_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) == sizeof(unsigned int)) { + return nlz_int((unsigned int)x); + } + if (sizeof(uintptr_t) == sizeof(unsigned long)) { + return nlz_long((unsigned long)x); + } + if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + return nlz_long_long((unsigned long long)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline unsigned int +rb_popcount32(uint32_t x) +{ +#if defined(_MSC_VER) && defined(__AVX__) + /* Note: CPUs since Nehalem and Barcelona have had this instruction so SSE + * 4.2 should suffice, but it seems there is no such thing like __SSE_4_2__ + * predefined macro in MSVC. They do have __AVX__ so use it instead. */ + return (unsigned int)__popcnt(x); + +#elif __has_builtin(__builtin_popcount) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT >= 32); + return (unsigned int)__builtin_popcount(x); + +#else + x = (x & 0x55555555) + (x >> 1 & 0x55555555); + x = (x & 0x33333333) + (x >> 2 & 0x33333333); + x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f); + x = (x & 0x001f001f) + (x >> 8 & 0x001f001f); + x = (x & 0x0000003f) + (x >>16 & 0x0000003f); + return (unsigned int)x; + +#endif +} + +static inline unsigned int +rb_popcount64(uint64_t x) +{ +#if defined(_MSC_VER) && defined(__AVX__) + return (unsigned int)__popcnt64(x); + +#elif __has_builtin(__builtin_popcount) + if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_popcountl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned int)__builtin_popcountll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555); + x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333); + x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707); + x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f); + x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f); + x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f); + return (unsigned int)x; + +#endif +} + +static inline unsigned int +rb_popcount_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) * CHAR_BIT == 64) { + return rb_popcount64((uint64_t)x); + } + else if (sizeof(uintptr_t) * CHAR_BIT == 32) { + return rb_popcount32((uint32_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline int +ntz_int32(uint32_t x) +{ +#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER) + return (unsigned)_tzcnt_u32(x); + +#elif MSC_VERSION_SINCE(1400) + /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using + * assembly? Because issuing LZCNT seems possible (see nlz.h). */ + unsigned long r; + return _BitScanForward(&r, x) ? (int)r : 32; + +#elif __has_builtin(__builtin_ctz) + STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32); + return x ? (unsigned)__builtin_ctz(x) : 32; + +#else + return rb_popcount32((~x) & (x-1)); + +#endif +} + +static inline int +ntz_int64(uint64_t x) +{ +#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER) + return (unsigned)_tzcnt_u64(x); + +#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) + unsigned long r; + return _BitScanForward64(&r, x) ? (int)r : 64; + +#elif __has_builtin(__builtin_ctzl) + if (x == 0) { + return 64; + } + else if (sizeof(long) * CHAR_BIT == 64) { + return (unsigned)__builtin_ctzl((unsigned long)x); + } + else if (sizeof(long long) * CHAR_BIT == 64) { + return (unsigned)__builtin_ctzll((unsigned long long)x); + } + else { + /* :FIXME: Is there a way to make this branch a compile-time error? */ + UNREACHABLE_RETURN(~0); + } + +#else + return rb_popcount64((~x) & (x-1)); + +#endif +} + +static inline int +ntz_intptr(uintptr_t x) +{ + if (sizeof(uintptr_t) * CHAR_BIT == 64) { + return ntz_int64((uint64_t)x); + } + else if (sizeof(uintptr_t) * CHAR_BIT == 32) { + return ntz_int32((uint32_t)x); + } + else { + UNREACHABLE_RETURN(~0); + } +} + +static inline VALUE +RUBY_BIT_ROTL(VALUE v, int n) +{ +#if __has_builtin(__builtin_rotateleft32) && (SIZEOF_VALUE * CHAR_BIT == 32) + return __builtin_rotateleft32(v, n); + +#elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64) + return __builtin_rotateleft64(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) + return _rotl(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) + return _rotl64(v, n); + +#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG) + return _lrotl(v, n); + +#else + const int m = (sizeof(VALUE) * CHAR_BIT) - 1; + return (v << (n & m)) | (v >> (-n & m)); +#endif +} + +static inline VALUE +RUBY_BIT_ROTR(VALUE v, int n) +{ +#if __has_builtin(__builtin_rotateright32) && (SIZEOF_VALUE * CHAR_BIT == 32) + return __builtin_rotateright32(v, n); + +#elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64) + return __builtin_rotateright64(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) + return _rotr(v, n); + +#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) + return _rotr64(v, n); + +#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG) + return _lrotr(v, n); + +#else + const int m = (sizeof(VALUE) * CHAR_BIT) - 1; + return (v << (-n & m)) | (v >> (n & m)); +#endif +} + +#endif /* INTERNAL_BITS_H */ diff --git a/internal/class.h b/internal/class.h new file mode 100644 index 0000000000..ac20c205fa --- /dev/null +++ b/internal/class.h @@ -0,0 +1,200 @@ +#ifndef INTERNAL_CLASS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_CLASS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Class. + */ +#include "id_table.h" /* for struct rb_id_table */ +#include "internal/gc.h" /* for RB_OBJ_WRITE */ +#include "internal/serial.h" /* for rb_serial_t */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/intern.h" /* for rb_alloc_func_t */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "ruby_assert.h" +#include "vm_core.h" +#include "method.h" /* for rb_cref_t */ + +#ifdef RCLASS_SUPER +# undef RCLASS_SUPER +#endif + +struct rb_subclass_entry { + VALUE klass; + struct rb_subclass_entry *next; + struct rb_subclass_entry *prev; +}; + +struct rb_iv_index_tbl_entry { + uint32_t index; + rb_serial_t class_serial; + VALUE class_value; +}; + +struct rb_cvar_class_tbl_entry { + uint32_t index; + rb_serial_t global_cvar_state; + const rb_cref_t * cref; + VALUE class_value; +}; + +struct rb_classext_struct { + struct st_table *iv_index_tbl; // ID -> struct rb_iv_index_tbl_entry + struct st_table *iv_tbl; +#if SIZEOF_SERIAL_T == SIZEOF_VALUE /* otherwise m_tbl is in struct RClass */ + struct rb_id_table *m_tbl; +#endif + struct rb_id_table *const_tbl; + struct rb_id_table *callable_m_tbl; + struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */ + struct rb_id_table *cvc_tbl; + struct rb_subclass_entry *subclasses; + struct rb_subclass_entry *subclass_entry; + /** + * In the case that this is an `ICLASS`, `module_subclasses` points to the link + * in the module's `subclasses` list that indicates that the klass has been + * included. Hopefully that makes sense. + */ + struct rb_subclass_entry *module_subclass_entry; +#if SIZEOF_SERIAL_T != SIZEOF_VALUE /* otherwise class_serial is in struct RClass */ + rb_serial_t class_serial; +#endif + const VALUE origin_; + const VALUE refined_class; + rb_alloc_func_t allocator; + const VALUE includer; +}; + +struct RClass { + struct RBasic basic; + VALUE super; +#if !USE_RVARGC + struct rb_classext_struct *ptr; +#endif +#if SIZEOF_SERIAL_T == SIZEOF_VALUE + /* Class serial is as wide as VALUE. Place it here. */ + rb_serial_t class_serial; +#else + /* Class serial does not fit into struct RClass. Place m_tbl instead. */ + struct rb_id_table *m_tbl; +#endif +}; + +typedef struct rb_subclass_entry rb_subclass_entry_t; +typedef struct rb_classext_struct rb_classext_t; + +#if USE_RVARGC +# define RCLASS_EXT(c) ((rb_classext_t *)((char *)c + sizeof(struct RClass))) +#else +# define RCLASS_EXT(c) (RCLASS(c)->ptr) +#endif +#define RCLASS_IV_TBL(c) (RCLASS_EXT(c)->iv_tbl) +#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl) +#if SIZEOF_SERIAL_T == SIZEOF_VALUE +# define RCLASS_M_TBL(c) (RCLASS_EXT(c)->m_tbl) +#else +# define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl) +#endif +#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl) +#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl) +#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl) +#define RCLASS_IV_INDEX_TBL(c) (RCLASS_EXT(c)->iv_index_tbl) +#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_) +#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class) +#if SIZEOF_SERIAL_T == SIZEOF_VALUE +# define RCLASS_SERIAL(c) (RCLASS(c)->class_serial) +#else +# define RCLASS_SERIAL(c) (RCLASS_EXT(c)->class_serial) +#endif +#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer) +#define RCLASS_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->subclass_entry) +#define RCLASS_MODULE_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->module_subclass_entry) +#define RCLASS_ALLOCATOR(c) (RCLASS_EXT(c)->allocator) +#define RCLASS_SUBCLASSES(c) (RCLASS_EXT(c)->subclasses) + +#define RICLASS_IS_ORIGIN FL_USER5 +#define RCLASS_CLONED FL_USER6 +#define RICLASS_ORIGIN_SHARED_MTBL FL_USER8 + +/* class.c */ +void rb_class_subclass_add(VALUE super, VALUE klass); +void rb_class_remove_from_super_subclasses(VALUE); +void rb_class_remove_subclass_head(VALUE); +int rb_singleton_class_internal_p(VALUE sklass); +VALUE rb_class_boot(VALUE); +VALUE rb_class_s_alloc(VALUE klass); +VALUE rb_module_s_alloc(VALUE klass); +void rb_module_set_initialized(VALUE module); +void rb_module_check_initializable(VALUE module); +VALUE rb_make_metaclass(VALUE, VALUE); +VALUE rb_include_class_new(VALUE, VALUE); +void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE); +void rb_class_detach_subclasses(VALUE); +void rb_class_detach_module_subclasses(VALUE); +void rb_class_remove_from_module_subclasses(VALUE); +VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj); +VALUE rb_special_singleton_class(VALUE); +VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach); +VALUE rb_singleton_class_get(VALUE obj); +void rb_undef_methods_from(VALUE klass, VALUE super); + +static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin); +static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass); +static inline VALUE RCLASS_SUPER(VALUE klass); +static inline VALUE RCLASS_SET_SUPER(VALUE klass, VALUE super); +static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass); + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_class_inherited(VALUE, VALUE); +VALUE rb_keyword_error_new(const char *, VALUE); +MJIT_SYMBOL_EXPORT_END + +static inline void +RCLASS_SET_ORIGIN(VALUE klass, VALUE origin) +{ + RB_OBJ_WRITE(klass, &RCLASS_ORIGIN(klass), origin); + if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN); +} + +static inline void +RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass) +{ + FL_SET(iclass, RICLASS_ORIGIN_SHARED_MTBL); +} + +static inline bool +RICLASS_OWNS_M_TBL_P(VALUE iclass) +{ + return FL_TEST_RAW(iclass, RICLASS_IS_ORIGIN | RICLASS_ORIGIN_SHARED_MTBL) == RICLASS_IS_ORIGIN; +} + +static inline void +RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass) +{ + RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass); +} + +static inline VALUE +RCLASS_SUPER(VALUE klass) +{ + return RCLASS(klass)->super; +} + +static inline VALUE +RCLASS_SET_SUPER(VALUE klass, VALUE super) +{ + if (super) { + rb_class_remove_from_super_subclasses(klass); + rb_class_subclass_add(super, klass); + } + RB_OBJ_WRITE(klass, &RCLASS(klass)->super, super); + return super; +} + +#endif /* INTERNAL_CLASS_H */ diff --git a/internal/compar.h b/internal/compar.h new file mode 100644 index 0000000000..5e336adafa --- /dev/null +++ b/internal/compar.h @@ -0,0 +1,49 @@ +#ifndef INTERNAL_COMPAR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPAR_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Comparable. + */ +#include "internal/vm.h" /* for rb_method_basic_definition_p */ + +#define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString) + +enum { + cmp_opt_Integer, + cmp_opt_String, + cmp_opt_Float, + cmp_optimizable_count +}; + +struct cmp_opt_data { + unsigned int opt_methods; + unsigned int opt_inited; +}; + +#define NEW_CMP_OPT_MEMO(type, value) \ + NEW_PARTIAL_MEMO_FOR(type, value, cmp_opt) +#define CMP_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(cmp_opt_,type)) +#define CMP_OPTIMIZABLE(data, type) \ + (((data).opt_inited & CMP_OPTIMIZABLE_BIT(type)) ? \ + ((data).opt_methods & CMP_OPTIMIZABLE_BIT(type)) : \ + (((data).opt_inited |= CMP_OPTIMIZABLE_BIT(type)), \ + rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \ + ((data).opt_methods |= CMP_OPTIMIZABLE_BIT(type)))) + +#define OPTIMIZED_CMP(a, b, data) \ + ((FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(data, Integer)) ? \ + (((long)a > (long)b) ? 1 : ((long)a < (long)b) ? -1 : 0) : \ + (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data, String)) ? \ + rb_str_cmp(a, b) : \ + (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b) && CMP_OPTIMIZABLE(data, Float)) ? \ + rb_float_cmp(a, b) : \ + rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b)) + +/* compar.c */ +VALUE rb_invcmp(VALUE, VALUE); + +#endif /* INTERNAL_COMPAR_H */ diff --git a/internal/compile.h b/internal/compile.h new file mode 100644 index 0000000000..d32c2233c9 --- /dev/null +++ b/internal/compile.h @@ -0,0 +1,35 @@ +#ifndef INTERNAL_COMPILE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPILE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the compiler. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "ruby/ruby.h" /* for rb_event_flag_t */ + +struct rb_iseq_struct; /* in vm_core.h */ + +/* compile.c */ +int rb_dvar_defined(ID, const struct rb_iseq_struct *); +int rb_local_defined(ID, const struct rb_iseq_struct *); +const char *rb_insns_name(int i); +VALUE rb_insns_name_array(void); +int rb_iseq_cdhash_cmp(VALUE val, VALUE lit); +st_index_t rb_iseq_cdhash_hash(VALUE a); + +/* iseq.c */ +int rb_vm_insn_addr2insn(const void *); +int rb_vm_insn_decode(const VALUE encoded); +extern bool ruby_vm_keep_script_lines; + +MJIT_SYMBOL_EXPORT_BEGIN +/* iseq.c (export) */ +rb_event_flag_t rb_iseq_event_flags(const struct rb_iseq_struct *iseq, size_t pos); +MJIT_SYMBOL_EXPORT_END + +#endif /* INTERNAL_COMPILE_H */ diff --git a/internal/compilers.h b/internal/compilers.h new file mode 100644 index 0000000000..26c2f05cc0 --- /dev/null +++ b/internal/compilers.h @@ -0,0 +1,107 @@ +#ifndef INTERNAL_COMPILERS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPILERS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header absorbing C compiler differences. + */ +#include "ruby/internal/compiler_since.h" +#include "ruby/internal/has/attribute.h" +#include "ruby/internal/has/builtin.h" +#include "ruby/internal/has/c_attribute.h" +#include "ruby/internal/has/declspec_attribute.h" +#include "ruby/internal/has/extension.h" +#include "ruby/internal/has/feature.h" +#include "ruby/internal/has/warning.h" +#include "ruby/backward/2/gcc_version_since.h" + +#define MSC_VERSION_SINCE(_) RBIMPL_COMPILER_SINCE(MSVC, (_) / 100, (_) % 100, 0) +#define MSC_VERSION_BEFORE(_) RBIMPL_COMPILER_BEFORE(MSVC, (_) / 100, (_) % 100, 0) + +#ifndef __has_attribute +# define __has_attribute(...) RBIMPL_HAS_ATTRIBUTE(__VA_ARGS__) +#endif + +#ifndef __has_c_attribute +# /* As of writing everything that lacks __has_c_attribute also completely +# * lacks C2x attributes as well. Might change in future? */ +# define __has_c_attribute(...) 0 +#endif + +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(...) RBIMPL_HAS_DECLSPEC_ATTRIBUTE(__VA_ARGS__) +#endif + +#ifndef __has_builtin +# define __has_builtin(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__) +#endif + +#ifndef __has_feature +# define __has_feature(...) RBIMPL_HAS_FEATURE(__VA_ARGS__) +#endif + +#ifndef __has_extension +# define __has_extension(...) RBIMPL_HAS_EXTENSION(__VA_ARGS__) +#endif + +#ifndef __has_warning +# define __has_warning(...) RBIMPL_HAS_WARNING(__VA_ARGS__) +#endif + +#ifndef __GNUC__ +# define __extension__ /* void */ +#endif + +#ifndef MAYBE_UNUSED +# define MAYBE_UNUSED(x) x +#endif + +#ifndef WARN_UNUSED_RESULT +# define WARN_UNUSED_RESULT(x) x +#endif + +#define RB_OBJ_BUILTIN_TYPE(obj) rb_obj_builtin_type(obj) +#define OBJ_BUILTIN_TYPE(obj) RB_OBJ_BUILTIN_TYPE(obj) +#ifdef __GNUC__ +#define rb_obj_builtin_type(obj) \ +__extension__({ \ + VALUE arg_obj = (obj); \ + RB_SPECIAL_CONST_P(arg_obj) ? -1 : \ + (int)RB_BUILTIN_TYPE(arg_obj); \ + }) +#else +# include "ruby/ruby.h" +static inline int +rb_obj_builtin_type(VALUE obj) +{ + return RB_SPECIAL_CONST_P(obj) ? -1 : + (int)RB_BUILTIN_TYPE(obj); +} +#endif + +/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEX_ARY_LEN /* VALUE ary[]; */ +#elif defined(__GNUC__) && !defined(__STRICT_ANSI__) +# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */ +#else +# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */ +#endif + +/* + * For declaring bitfields out of non-unsigned int types: + * struct date { + * BITFIELD(enum months, month, 4); + * ... + * }; + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define BITFIELD(type, name, size) type name : size +#else +# define BITFIELD(type, name, size) unsigned int name : size +#endif + +#endif /* INTERNAL_COMPILERS_H */ diff --git a/internal/complex.h b/internal/complex.h new file mode 100644 index 0000000000..42151652b7 --- /dev/null +++ b/internal/complex.h @@ -0,0 +1,29 @@ +#ifndef INTERNAL_COMPLEX_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_COMPLEX_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Complex. + */ +#include "ruby/internal/value.h" /* for struct RBasic */ + +struct RComplex { + struct RBasic basic; + VALUE real; + VALUE imag; +}; + +#define RCOMPLEX(obj) ((struct RComplex *)(obj)) + +/* shortcut macro for internal only */ +#define RCOMPLEX_SET_REAL(cmp, r) RB_OBJ_WRITE((cmp), &RCOMPLEX(cmp)->real, (r)) +#define RCOMPLEX_SET_IMAG(cmp, i) RB_OBJ_WRITE((cmp), &RCOMPLEX(cmp)->imag, (i)) + +/* complex.c */ +VALUE rb_dbl_complex_new_polar_pi(double abs, double ang); +st_index_t rb_complex_hash(VALUE comp); + +#endif /* INTERNAL_COMPLEX_H */ diff --git a/internal/cont.h b/internal/cont.h new file mode 100644 index 0000000000..5ab120e9ab --- /dev/null +++ b/internal/cont.h @@ -0,0 +1,24 @@ +#ifndef INTERNAL_CONT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_CONT_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Fiber. + */ +#include "ruby/ruby.h" /* for VALUE */ + +struct rb_thread_struct; /* in vm_core.h */ +struct rb_fiber_struct; /* in cont.c */ + +/* cont.c */ +void rb_fiber_reset_root_local_storage(struct rb_thread_struct *); +void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE (*rollback_func)(VALUE)); +void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber); + +VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); +unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); + +#endif /* INTERNAL_CONT_H */ diff --git a/internal/dir.h b/internal/dir.h new file mode 100644 index 0000000000..0a4dc90ece --- /dev/null +++ b/internal/dir.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_DIR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_DIR_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Dir. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* dir.c */ +VALUE rb_dir_getwd_ospath(void); + +#endif /* INTERNAL_DIR_H */ diff --git a/internal/enc.h b/internal/enc.h new file mode 100644 index 0000000000..a005dc810d --- /dev/null +++ b/internal/enc.h @@ -0,0 +1,19 @@ +#ifndef INTERNAL_ENC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENC_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding. + */ +#include "ruby/encoding.h" /* for rb_encoding */ + +/* us_ascii.c */ +extern rb_encoding OnigEncodingUS_ASCII; + +/* utf_8.c */ +extern rb_encoding OnigEncodingUTF_8; + +#endif /* INTERNAL_ENC_H */ diff --git a/internal/encoding.h b/internal/encoding.h new file mode 100644 index 0000000000..c48cb24b04 --- /dev/null +++ b/internal/encoding.h @@ -0,0 +1,30 @@ +#ifndef INTERNAL_ENCODING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENCODING_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding. + */ +#include "ruby/ruby.h" /* for ID */ +#include "ruby/encoding.h" /* for rb_encoding */ + +#define rb_enc_autoload_p(enc) (!rb_enc_mbmaxlen(enc)) + +/* encoding.c */ +ID rb_id_encoding(void); +rb_encoding *rb_enc_get_from_index(int index); +rb_encoding *rb_enc_check_str(VALUE str1, VALUE str2); +int rb_encdb_replicate(const char *alias, const char *orig); +int rb_encdb_alias(const char *alias, const char *orig); +int rb_enc_autoload(rb_encoding *enc); +int rb_encdb_dummy(const char *name); +void rb_encdb_declare(const char *name); +void rb_enc_set_base(const char *name, const char *orig); +int rb_enc_set_dummy(int index); +void rb_encdb_set_unicode(int index); +PUREFUNC(int rb_data_is_encoding(VALUE obj)); + +#endif /* INTERNAL_ENCODING_H */ diff --git a/internal/enum.h b/internal/enum.h new file mode 100644 index 0000000000..282464436f --- /dev/null +++ b/internal/enum.h @@ -0,0 +1,18 @@ +#ifndef INTERNAL_ENUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENUM_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Enumerable. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* enum.c */ +extern VALUE rb_cArithSeq; +VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); +VALUE rb_nmin_run(VALUE obj, VALUE num, int by, int rev, int ary); + +#endif /* INTERNAL_ENUM_H */ diff --git a/internal/enumerator.h b/internal/enumerator.h new file mode 100644 index 0000000000..e11a684c5b --- /dev/null +++ b/internal/enumerator.h @@ -0,0 +1,21 @@ +#ifndef INTERNAL_ENUMERATOR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ENUMERATOR_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Enumerator. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/intern.h" /* for rb_enumerator_size_func */ + +RUBY_SYMBOL_EXPORT_BEGIN +/* enumerator.c (export) */ +VALUE rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv, + rb_enumerator_size_func *size_fn, + VALUE beg, VALUE end, VALUE step, int excl); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_ENUMERATOR_H */ diff --git a/internal/error.h b/internal/error.h new file mode 100644 index 0000000000..11601858f4 --- /dev/null +++ b/internal/error.h @@ -0,0 +1,191 @@ +#ifndef INTERNAL_ERROR_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_ERROR_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Exception. + */ +#include "ruby/internal/config.h" +#include <stdarg.h> /* for va_list */ +#include "internal/string.h" /* for rb_fstring_cstr */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "ruby/intern.h" /* for rb_exc_raise */ +#include "ruby/ruby.h" /* for enum ruby_value_type */ + +#ifdef Check_Type +# undef Check_Type /* in ruby/ruby.h */ +#endif + +#ifdef rb_raise_static +# undef rb_raise_static +# undef rb_sys_fail_path +# undef rb_syserr_fail_path +#endif + +#define rb_raise_static(e, m) \ + rb_raise_cstr_i((e), rb_str_new_static((m), rb_strlen_lit(m))) +#ifdef RUBY_FUNCTION_NAME_STRING +# define rb_sys_fail_path(path) rb_sys_fail_path_in(RUBY_FUNCTION_NAME_STRING, path) +# define rb_syserr_fail_path(err, path) rb_syserr_fail_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path)) +# define rb_syserr_new_path(err, path) rb_syserr_new_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path)) +#else +# define rb_sys_fail_path(path) rb_sys_fail_str(path) +# define rb_syserr_fail_path(err, path) rb_syserr_fail_str((err), (path)) +# define rb_syserr_new_path(err, path) rb_syserr_new_str((err), (path)) +#endif + +/* error.c */ +extern long rb_backtrace_length_limit; +extern VALUE rb_eEAGAIN; +extern VALUE rb_eEWOULDBLOCK; +extern VALUE rb_eEINPROGRESS; +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0) +void rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args); +NORETURN(void rb_async_bug_errno(const char *,int)); +const char *rb_builtin_type_name(int t); +const char *rb_builtin_class_name(VALUE x); +PRINTF_ARGS(void rb_warn_deprecated(const char *fmt, const char *suggest, ...), 1, 3); +PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const char *suggest, ...), 2, 4); +#if RUBY_DEBUG +# include "ruby/version.h" +# define RUBY_VERSION_SINCE(major, minor) (RUBY_API_VERSION_CODE >= (major * 10000) + (minor) * 100) +# define RUBY_VERSION_BEFORE(major, minor) (RUBY_API_VERSION_CODE < (major * 10000) + (minor) * 100) +# if defined(RBIMPL_WARNING_PRAGMA0) +# define RBIMPL_TODO0(x) RBIMPL_WARNING_PRAGMA0(message(x)) +# elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0) +# define RBIMPL_TODO0(x) __pragma(message(x)) +# endif + +# if RBIMPL_HAS_ATTRIBUTE(diagnose_if) || defined(__OPTIMIZE__) + +#define RUBY_VERSION_isdigit(c) ('0'<=(c)&&(c)<='9') +// upto 99 +#define RUBY_VERSION__number_len(v, ofs) \ + (!RUBY_VERSION_isdigit((v)[ofs]) ? \ + 0 : !RUBY_VERSION_isdigit((v)[(ofs) + 1]) ? 1 : 2) +#define RUBY_VERSION__to_number(v, ofs) \ + (!RUBY_VERSION_isdigit((v)[ofs]) ? \ + 0 : !RUBY_VERSION_isdigit((v)[(ofs) + 1]) ? \ + ((v)[ofs]-'0') : \ + (((v)[ofs]-'0')*10+(v)[(ofs)+1]-'0')) + +#define RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v) \ + (RUBY_VERSION__to_number(v, 0) * 10000 + \ + ((v)[RUBY_VERSION__number_len(v, 0)] == '.' ? \ + RUBY_VERSION__to_number(v, RUBY_VERSION__number_len(v, 0)+1) * 100 : 0)) +#define RUBY_VERSION_STRING_SINCE(v) (RUBY_API_VERSION_CODE >= RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v)) +#define RUBY_VERSION_STRING_BEFORE(v) (RUBY_API_VERSION_CODE < RUBY_VERSION_CODE_FROM_MAJOR_MINOR_STRING(v)) + +# if RBIMPL_HAS_ATTRIBUTE(diagnose_if) +RBIMPL_ATTR_FORCEINLINE() +static void +rb_deprecated_method_to_be_removed(const char *removal) + RBIMPL_ATTR_DIAGNOSE_IF(!RUBY_VERSION_isdigit(removal[0]), "malformed version number", "error") + RBIMPL_ATTR_DIAGNOSE_IF(RUBY_VERSION_STRING_SINCE(removal), "deprecated method to be removed", "error") +{ +} +# else +RBIMPL_ATTR_ERROR(("deprecated")) +void rb_deprecated_method_to_be_removed(const char *); +# define rb_deprecated_method_to_be_removed(removal) \ + (sizeof(char[1-2*(!RUBY_VERSION_isdigit(removal[0]) || RUBY_VERSION_STRING_SINCE(removal))])!=1 ? \ + rb_deprecated_method_to_be_removed(removal) : \ + RBIMPL_ASSERT_NOTHING) +# endif +# define rb_warn_deprecated_to_remove_at(removal, ...) \ + (rb_deprecated_method_to_be_removed(#removal), \ + rb_warn_deprecated_to_remove(#removal, __VA_ARGS__)) +# endif +#endif +#ifndef rb_warn_deprecated_to_remove_at +# define rb_warn_deprecated_to_remove_at(removal, ...) \ + rb_warn_deprecated_to_remove(#removal, __VA_ARGS__) +#endif +#ifndef RUBY_VERSION_SINCE +# define RUBY_VERSION_SINCE(major, minor) 0 +#endif +#ifndef RUBY_VERSION_BEFORE +# define RUBY_VERSION_BEFORE(major, minor) 0 +#endif +#ifndef RBIMPL_TODO0 +# define RBIMPL_TODO0(x) +#endif +#define RBIMPL_TODO(message) RBIMPL_TODO0("TODO: " message) +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0) +VALUE rb_syntax_error_append(VALUE, VALUE, int, int, rb_encoding*, const char*, va_list); +PRINTF_ARGS(void rb_enc_warn(rb_encoding *enc, const char *fmt, ...), 2, 3); +PRINTF_ARGS(void rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...), 2, 3); +PRINTF_ARGS(void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...), 3, 4); +rb_warning_category_t rb_warning_category_from_name(VALUE category); +bool rb_warning_category_enabled_p(rb_warning_category_t category); +VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method); +VALUE rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv); +VALUE rb_key_err_new(VALUE mesg, VALUE recv, VALUE name); +PRINTF_ARGS(VALUE rb_warning_string(const char *fmt, ...), 1, 2); +RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 0) +NORETURN(void rb_vraise(VALUE, const char *, va_list)); +NORETURN(static inline void rb_raise_cstr(VALUE etype, const char *mesg)); +NORETURN(static inline void rb_raise_cstr_i(VALUE etype, VALUE mesg)); +NORETURN(static inline void rb_name_err_raise_str(VALUE mesg, VALUE recv, VALUE name)); +NORETURN(static inline void rb_name_err_raise(const char *mesg, VALUE recv, VALUE name)); +NORETURN(static inline void rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name)); +static inline void Check_Type(VALUE v, enum ruby_value_type t); +static inline bool rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type); +#define rb_typeddata_is_instance_of rb_typeddata_is_instance_of_inline + +RUBY_SYMBOL_EXPORT_BEGIN +/* error.c (export) */ +int rb_bug_reporter_add(void (*func)(FILE *, void *), void *data); +#ifdef RUBY_FUNCTION_NAME_STRING +NORETURN(void rb_sys_fail_path_in(const char *func_name, VALUE path)); +NORETURN(void rb_syserr_fail_path_in(const char *func_name, int err, VALUE path)); +VALUE rb_syserr_new_path_in(const char *func_name, int n, VALUE path); +#endif +RUBY_SYMBOL_EXPORT_END + +static inline void +rb_raise_cstr_i(VALUE etype, VALUE mesg) +{ + VALUE exc = rb_exc_new_str(etype, mesg); + rb_exc_raise(exc); +} + +static inline void +rb_raise_cstr(VALUE etype, const char *mesg) +{ + VALUE str = rb_str_new_cstr(mesg); + rb_raise_cstr_i(etype, str); +} + +static inline void +rb_name_err_raise_str(VALUE mesg, VALUE recv, VALUE name) +{ + VALUE exc = rb_name_err_new(mesg, recv, name); + rb_exc_raise(exc); +} + +static inline void +rb_name_err_raise(const char *mesg, VALUE recv, VALUE name) +{ + VALUE str = rb_fstring_cstr(mesg); + rb_name_err_raise_str(str, recv, name); +} + +static inline void +rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name) +{ + VALUE exc = rb_key_err_new(mesg, recv, name); + rb_exc_raise(exc); +} + +static inline bool +rb_typeddata_is_instance_of_inline(VALUE obj, const rb_data_type_t *data_type) +{ + return RB_TYPE_P(obj, T_DATA) && RTYPEDDATA_P(obj) && (RTYPEDDATA_TYPE(obj) == data_type); +} + +#endif /* INTERNAL_ERROR_H */ diff --git a/internal/eval.h b/internal/eval.h new file mode 100644 index 0000000000..73bb656d96 --- /dev/null +++ b/internal/eval.h @@ -0,0 +1,32 @@ +#ifndef INTERNAL_EVAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_EVAL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the evaluator. + * @note There also is eval_intern.h, which is evaluator's internal + * header (related to this file, but not the same role). + */ +#include "ruby/ruby.h" /* for ID */ + +#define id_signo ruby_static_id_signo +#define id_status ruby_static_id_status + +/* eval.c */ +extern ID ruby_static_id_signo; +extern ID ruby_static_id_status; +VALUE rb_refinement_module_get_refined_class(VALUE module); +void rb_class_modify_check(VALUE); +NORETURN(VALUE rb_f_raise(int argc, VALUE *argv)); + +/* eval_error.c */ +VALUE rb_get_backtrace(VALUE info); + +/* eval_jump.c */ +void rb_call_end_proc(VALUE data); +void rb_mark_end_proc(void); + +#endif /* INTERNAL_EVAL_H */ diff --git a/internal/file.h b/internal/file.h new file mode 100644 index 0000000000..9c192ff4d1 --- /dev/null +++ b/internal/file.h @@ -0,0 +1,38 @@ +#ifndef INTERNAL_FILE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_FILE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for File. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_encodinng */ + +/* file.c */ +extern const char ruby_null_device[]; +VALUE rb_home_dir_of(VALUE user, VALUE result); +VALUE rb_default_home_dir(VALUE result); +VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict); +VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *origenc); +void rb_file_const(const char*, VALUE); +int rb_file_load_ok(const char *); +VALUE rb_file_expand_path_fast(VALUE, VALUE); +VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE); +VALUE rb_get_path_check_to_string(VALUE); +VALUE rb_get_path_check_convert(VALUE); +int ruby_is_fd_loadable(int fd); + +RUBY_SYMBOL_EXPORT_BEGIN +/* file.c (export) */ +#ifdef HAVE_READLINK +VALUE rb_readlink(VALUE path, rb_encoding *enc); +#endif +#ifdef __APPLE__ +VALUE rb_str_normalize_ospath(const char *ptr, long len); +#endif +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_FILE_H */ diff --git a/internal/fixnum.h b/internal/fixnum.h new file mode 100644 index 0000000000..cdb60ee1ff --- /dev/null +++ b/internal/fixnum.h @@ -0,0 +1,184 @@ +#ifndef INTERNAL_FIXNUM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_FIXNUM_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Fixnums. + */ +#include "ruby/internal/config.h" /* for HAVE_LONG_LONG */ +#include <limits.h> /* for CHAR_BIT */ +#include "internal/compilers.h" /* for __has_builtin */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/intern.h" /* for rb_big_mul */ +#include "ruby/ruby.h" /* for RB_FIXABLE */ + +#if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG +# define DLONG LONG_LONG +# define DL2NUM(x) LL2NUM(x) +#elif defined(HAVE_INT128_T) +# define DLONG int128_t +# define DL2NUM(x) (RB_FIXABLE(x) ? LONG2FIX(x) : rb_int128t2big(x)) +VALUE rb_int128t2big(int128_t n); /* in bignum.c */ +#endif + +static inline long rb_overflowed_fix_to_int(long x); +static inline VALUE rb_fix_plus_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_minus_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_mul_fix(VALUE x, VALUE y); +static inline void rb_fix_divmod_fix(VALUE x, VALUE y, VALUE *divp, VALUE *modp); +static inline VALUE rb_fix_div_fix(VALUE x, VALUE y); +static inline VALUE rb_fix_mod_fix(VALUE x, VALUE y); +static inline bool FIXNUM_POSITIVE_P(VALUE num); +static inline bool FIXNUM_NEGATIVE_P(VALUE num); +static inline bool FIXNUM_ZERO_P(VALUE num); + +static inline long +rb_overflowed_fix_to_int(long x) +{ + return (long)((unsigned long)(x >> 1) ^ (1LU << (SIZEOF_LONG * CHAR_BIT - 1))); +} + +static inline VALUE +rb_fix_plus_fix(VALUE x, VALUE y) +{ +#if !__has_builtin(__builtin_add_overflow) + long lz = FIX2LONG(x) + FIX2LONG(y); + return LONG2NUM(lz); +#else + long lz; + /* NOTE + * (1) `LONG2FIX(FIX2LONG(x)+FIX2LONG(y))` + + = `((lx*2+1)/2 + (ly*2+1)/2)*2+1` + + = `lx*2 + ly*2 + 1` + + = `(lx*2+1) + (ly*2+1) - 1` + + = `x + y - 1` + * (2) Fixnum's LSB is always 1. + * It means you can always run `x - 1` without overflow. + * (3) Of course `z = x + (y-1)` may overflow. + * At that time true value is + * * positive: 0b0 1xxx...1, and z = 0b1xxx...1 + * * negative: 0b1 0xxx...1, and z = 0b0xxx...1 + * To convert this true value to long, + * (a) Use arithmetic shift + * * positive: 0b11xxx... + * * negative: 0b00xxx... + * (b) invert MSB + * * positive: 0b01xxx... + * * negative: 0b10xxx... + */ + if (__builtin_add_overflow((long)x, (long)y-1, &lz)) { + return rb_int2big(rb_overflowed_fix_to_int(lz)); + } + else { + return (VALUE)lz; + } +#endif +} + +static inline VALUE +rb_fix_minus_fix(VALUE x, VALUE y) +{ +#if !__has_builtin(__builtin_sub_overflow) + long lz = FIX2LONG(x) - FIX2LONG(y); + return LONG2NUM(lz); +#else + long lz; + if (__builtin_sub_overflow((long)x, (long)y-1, &lz)) { + return rb_int2big(rb_overflowed_fix_to_int(lz)); + } + else { + return (VALUE)lz; + } +#endif +} + +/* arguments must be Fixnum */ +static inline VALUE +rb_fix_mul_fix(VALUE x, VALUE y) +{ + long lx = FIX2LONG(x); + long ly = FIX2LONG(y); +#ifdef DLONG + return DL2NUM((DLONG)lx * (DLONG)ly); +#else + if (MUL_OVERFLOW_FIXNUM_P(lx, ly)) { + return rb_big_mul(rb_int2big(lx), rb_int2big(ly)); + } + else { + return LONG2FIX(lx * ly); + } +#endif +} + +/* + * This behaves different from C99 for negative arguments. + * Note that div may overflow fixnum. + */ +static inline void +rb_fix_divmod_fix(VALUE a, VALUE b, VALUE *divp, VALUE *modp) +{ + /* assume / and % comply C99. + * ldiv(3) won't be inlined by GCC and clang. + * I expect / and % are compiled as single idiv. + */ + long x = FIX2LONG(a); + long y = FIX2LONG(b); + long div, mod; + if (x == FIXNUM_MIN && y == -1) { + if (divp) *divp = LONG2NUM(-FIXNUM_MIN); + if (modp) *modp = LONG2FIX(0); + return; + } + div = x / y; + mod = x % y; + if (y > 0 ? mod < 0 : mod > 0) { + mod += y; + div -= 1; + } + if (divp) *divp = LONG2FIX(div); + if (modp) *modp = LONG2FIX(mod); +} + +/* div() for Ruby + * This behaves different from C99 for negative arguments. + */ +static inline VALUE +rb_fix_div_fix(VALUE x, VALUE y) +{ + VALUE div; + rb_fix_divmod_fix(x, y, &div, NULL); + return div; +} + +/* mod() for Ruby + * This behaves different from C99 for negative arguments. + */ +static inline VALUE +rb_fix_mod_fix(VALUE x, VALUE y) +{ + VALUE mod; + rb_fix_divmod_fix(x, y, NULL, &mod); + return mod; +} + +static inline bool +FIXNUM_POSITIVE_P(VALUE num) +{ + return (SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0); +} + +static inline bool +FIXNUM_NEGATIVE_P(VALUE num) +{ + return (SIGNED_VALUE)num < 0; +} + +static inline bool +FIXNUM_ZERO_P(VALUE num) +{ + return num == INT2FIX(0); +} +#endif /* INTERNAL_FIXNUM_H */ diff --git a/internal/gc.h b/internal/gc.h new file mode 100644 index 0000000000..baf4f36a10 --- /dev/null +++ b/internal/gc.h @@ -0,0 +1,186 @@ +#ifndef INTERNAL_GC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_GC_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for GC. + */ +#include "ruby/internal/config.h" + +#include <stddef.h> /* for size_t */ + +#include "internal/compilers.h" /* for __has_attribute */ +#include "ruby/ruby.h" /* for rb_event_flag_t */ + +struct rb_execution_context_struct; /* in vm_core.h */ +struct rb_objspace; /* in vm_core.h */ + +#ifdef NEWOBJ_OF +# undef NEWOBJ_OF +# undef RB_NEWOBJ_OF +# undef RB_OBJ_WRITE +#endif + +#define RVALUE_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])) + +#define RB_RVARGC_NEWOBJ_OF(var, T, c, f, s) \ + T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \ + rb_wb_protected_newobj_of((c), (f) & ~FL_WB_PROTECTED, s) : \ + rb_wb_unprotected_newobj_of((c), (f), s)) + +#define RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, s) \ + T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \ + rb_ec_wb_protected_newobj_of((ec), (c), (f) & ~FL_WB_PROTECTED, s) : \ + rb_wb_unprotected_newobj_of((c), (f), s)) + +/* optimized version of NEWOBJ() */ +#define RB_NEWOBJ_OF(var, T, c, f) RB_RVARGC_NEWOBJ_OF(var, T, c, f, RVALUE_SIZE) + +#define RB_EC_NEWOBJ_OF(ec, var, T, c, f) RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, RVALUE_SIZE) + +#define NEWOBJ_OF(var, T, c, f) RB_NEWOBJ_OF((var), T, (c), (f)) +#define RVARGC_NEWOBJ_OF(var, T, c, f, s) RB_RVARGC_NEWOBJ_OF((var), T, (c), (f), (s)) +#define RB_OBJ_GC_FLAGS_MAX 6 /* used in ext/objspace */ + +#ifndef USE_UNALIGNED_MEMBER_ACCESS +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#elif ! USE_UNALIGNED_MEMBER_ACCESS +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#elif ! (__has_warning("-Waddress-of-packed-member") || GCC_VERSION_SINCE(9, 0, 0)) +# define UNALIGNED_MEMBER_ACCESS(expr) (expr) +#else +# include "internal/warnings.h" +# define UNALIGNED_MEMBER_ACCESS(expr) __extension__({ \ + COMPILER_WARNING_PUSH; \ + COMPILER_WARNING_IGNORED(-Waddress-of-packed-member); \ + __typeof__(expr) unaligned_member_access_result = (expr); \ + COMPILER_WARNING_POP; \ + unaligned_member_access_result; \ +}) +#endif + +#define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem) +#define RB_OBJ_WRITE(a, slot, b) \ + rb_obj_write((VALUE)(a), UNALIGNED_MEMBER_ACCESS((VALUE *)(slot)), \ + (VALUE)(b), __FILE__, __LINE__) + +#if USE_RVARGC +# define SIZE_POOL_COUNT 4 +#else +# define SIZE_POOL_COUNT 1 +#endif + +typedef struct ractor_newobj_size_pool_cache { + struct RVALUE *freelist; + struct heap_page *using_page; +} rb_ractor_newobj_size_pool_cache_t; + +typedef struct ractor_newobj_cache { + rb_ractor_newobj_size_pool_cache_t size_pool_caches[SIZE_POOL_COUNT]; +} rb_ractor_newobj_cache_t; + +/* gc.c */ +extern VALUE *ruby_initial_gc_stress_ptr; +extern int ruby_disable_gc; +RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size); +void ruby_mimfree(void *ptr); +void rb_objspace_set_event_hook(const rb_event_flag_t event); +VALUE rb_objspace_gc_enable(struct rb_objspace *); +VALUE rb_objspace_gc_disable(struct rb_objspace *); +void ruby_gc_set_params(void); +void rb_copy_wb_protected_attribute(VALUE dest, VALUE obj); +#if __has_attribute(alloc_align) +__attribute__((__alloc_align__(1))) +#endif +RUBY_ATTR_MALLOC void *rb_aligned_malloc(size_t, size_t) RUBY_ATTR_ALLOC_SIZE((2)); +size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */ +size_t rb_size_mul_add_or_raise(size_t, size_t, size_t, VALUE); /* used in iseq.h */ +RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add(size_t, size_t, size_t); +void *rb_xrealloc_mul_add(const void *, size_t, size_t, size_t); +RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add_mul(size_t, size_t, size_t, size_t); +RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t); +static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); +static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); +static inline void ruby_sized_xfree_inlined(void *ptr, size_t size); +VALUE rb_class_allocate_instance(VALUE klass); +void rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache); +size_t rb_gc_obj_slot_size(VALUE obj); +bool rb_gc_size_allocatable_p(size_t size); +int rb_objspace_garbage_object_p(VALUE obj); + +RUBY_SYMBOL_EXPORT_BEGIN +/* gc.c (export) */ +const char *rb_objspace_data_type_name(VALUE obj); +VALUE rb_wb_protected_newobj_of(VALUE, VALUE, size_t); +VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, size_t); +VALUE rb_ec_wb_protected_newobj_of(struct rb_execution_context_struct *ec, VALUE klass, VALUE flags, size_t); +size_t rb_obj_memsize_of(VALUE); +void rb_gc_verify_internal_consistency(void); +size_t rb_obj_gc_flags(VALUE, ID[], size_t); +void rb_gc_mark_values(long n, const VALUE *values); +void rb_gc_mark_vm_stack_values(long n, const VALUE *values); +void *ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); +void *ruby_sized_xrealloc2(void *ptr, size_t new_count, size_t element_size, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); +void ruby_sized_xfree(void *x, size_t size); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +int rb_ec_stack_check(struct rb_execution_context_struct *ec); +void rb_gc_writebarrier_remember(VALUE obj); +const char *rb_obj_info(VALUE obj); +MJIT_SYMBOL_EXPORT_END + +#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32) + +static inline void * +ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) +{ + return ruby_xrealloc(ptr, new_size); +} + +static inline void * +ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) +{ + return ruby_xrealloc2(ptr, new_count, elemsiz); +} + +static inline void +ruby_sized_xfree_inlined(void *ptr, size_t size) +{ + ruby_xfree(ptr); +} + +# define SIZED_REALLOC_N(x, y, z, w) REALLOC_N(x, y, z) + +#else + +static inline void * +ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) +{ + return ruby_sized_xrealloc(ptr, new_size, old_size); +} + +static inline void * +ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) +{ + return ruby_sized_xrealloc2(ptr, new_count, elemsiz, old_count); +} + +static inline void +ruby_sized_xfree_inlined(void *ptr, size_t size) +{ + ruby_sized_xfree(ptr, size); +} + +# define SIZED_REALLOC_N(v, T, m, n) \ + ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n))) + +#endif /* HAVE_MALLOC_USABLE_SIZE */ + +#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined +#define ruby_sized_xrealloc2 ruby_sized_xrealloc2_inlined +#define ruby_sized_xfree ruby_sized_xfree_inlined +#endif /* INTERNAL_GC_H */ diff --git a/internal/hash.h b/internal/hash.h new file mode 100644 index 0000000000..657e5eff3c --- /dev/null +++ b/internal/hash.h @@ -0,0 +1,243 @@ +#ifndef INTERNAL_HASH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_HASH_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Hash. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "ruby/st.h" /* for struct st_table */ + +#define RHASH_AR_TABLE_MAX_SIZE SIZEOF_VALUE + +struct ar_table_struct; +typedef unsigned char ar_hint_t; + +enum ruby_rhash_flags { + RHASH_PASS_AS_KEYWORDS = FL_USER1, /* FL 1 */ + RHASH_PROC_DEFAULT = FL_USER2, /* FL 2 */ + RHASH_ST_TABLE_FLAG = FL_USER3, /* FL 3 */ + RHASH_AR_TABLE_SIZE_MASK = (FL_USER4|FL_USER5|FL_USER6|FL_USER7), /* FL 4..7 */ + RHASH_AR_TABLE_SIZE_SHIFT = (FL_USHIFT+4), + RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */ + RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8), + +#if USE_TRANSIENT_HEAP + RHASH_TRANSIENT_FLAG = FL_USER12, /* FL 12 */ +#endif + + // we can not put it in "enum" because it can exceed "int" range. +#define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \ + FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19) + + RHASH_LEV_SHIFT = (FL_USHIFT + 13), + RHASH_LEV_MAX = 127, /* 7 bits */ +}; + +struct RHash { + struct RBasic basic; + union { + st_table *st; + struct ar_table_struct *ar; /* possibly 0 */ + } as; + const VALUE ifnone; + union { + ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE]; + VALUE word; + } ar_hint; +}; + +#define RHASH(obj) ((struct RHash *)(obj)) + +#ifdef RHASH_IFNONE +# undef RHASH_IFNONE +#endif + +#ifdef RHASH_SIZE +# undef RHASH_SIZE +#endif + +#ifdef RHASH_EMPTY_P +# undef RHASH_EMPTY_P +#endif + +/* hash.c */ +void rb_hash_st_table_set(VALUE hash, st_table *st); +VALUE rb_hash_default_value(VALUE hash, VALUE key); +VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); +long rb_dbl_long_hash(double d); +st_table *rb_init_identtable(void); +VALUE rb_to_hash_type(VALUE obj); +VALUE rb_hash_key_str(VALUE); +VALUE rb_hash_values(VALUE hash); +VALUE rb_hash_rehash(VALUE hash); +int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val); +VALUE rb_hash_set_pair(VALUE hash, VALUE pair); +int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval); +int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg); +int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg); +extern st_table *rb_hash_st_table(VALUE hash); +VALUE rb_ident_hash_new_with_size(st_index_t size); + +static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h); +static inline VALUE RHASH_IFNONE(VALUE h); +static inline size_t RHASH_SIZE(VALUE h); +static inline bool RHASH_EMPTY_P(VALUE h); +static inline bool RHASH_AR_TABLE_P(VALUE h); +static inline bool RHASH_ST_TABLE_P(VALUE h); +static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h); +static inline st_table *RHASH_ST_TABLE(VALUE h); +static inline size_t RHASH_ST_SIZE(VALUE h); +static inline void RHASH_ST_CLEAR(VALUE h); +static inline bool RHASH_TRANSIENT_P(VALUE h); +static inline void RHASH_SET_TRANSIENT_FLAG(VALUE h); +static inline void RHASH_UNSET_TRANSIENT_FLAG(VALUE h); + +RUBY_SYMBOL_EXPORT_BEGIN +/* hash.c (export) */ +VALUE rb_hash_delete_entry(VALUE hash, VALUE key); +VALUE rb_ident_hash_new(void); +int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_hash_new_with_size(st_index_t size); +VALUE rb_hash_resurrect(VALUE hash); +int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval); +VALUE rb_hash_keys(VALUE hash); +VALUE rb_hash_has_key(VALUE hash, VALUE key); +VALUE rb_hash_compare_by_id_p(VALUE hash); + +st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line); +#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__) +MJIT_SYMBOL_EXPORT_END + +VALUE rb_hash_compare_by_id(VALUE hash); + +#if 0 /* for debug */ + +static inline bool +RHASH_AR_TABLE_P(VALUE h) +{ + extern int rb_hash_ar_table_p(VALUE hash); + return rb_hash_ar_table_p(h) +} + +static inline struct ar_table_struct * +RHASH_AR_TABLE(VALUE h) +{ + extern struct ar_table_struct *rb_hash_ar_table(VALUE hash); + return rb_hash_ar_table(h) +} + +static inline st_table * +RHASH_ST_TABLE(VALUE h) +{ + return rb_hash_st_table(h) +} + +#else + +static inline bool +RHASH_AR_TABLE_P(VALUE h) +{ + return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG); +} + +static inline struct ar_table_struct * +RHASH_AR_TABLE(VALUE h) +{ + return RHASH(h)->as.ar; +} + +static inline st_table * +RHASH_ST_TABLE(VALUE h) +{ + return RHASH(h)->as.st; +} + +#endif + +static inline VALUE +RHASH_IFNONE(VALUE h) +{ + return RHASH(h)->ifnone; +} + +static inline size_t +RHASH_SIZE(VALUE h) +{ + if (RHASH_AR_TABLE_P(h)) { + return RHASH_AR_TABLE_SIZE_RAW(h); + } + else { + return RHASH_ST_SIZE(h); + } +} + +static inline bool +RHASH_EMPTY_P(VALUE h) +{ + return RHASH_SIZE(h) == 0; +} + +static inline bool +RHASH_ST_TABLE_P(VALUE h) +{ + return ! RHASH_AR_TABLE_P(h); +} + +static inline size_t +RHASH_ST_SIZE(VALUE h) +{ + return RHASH_ST_TABLE(h)->num_entries; +} + +static inline void +RHASH_ST_CLEAR(VALUE h) +{ + FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG); + RHASH(h)->as.ar = NULL; +} + +static inline unsigned +RHASH_AR_TABLE_SIZE_RAW(VALUE h) +{ + VALUE ret = FL_TEST_RAW(h, RHASH_AR_TABLE_SIZE_MASK); + ret >>= RHASH_AR_TABLE_SIZE_SHIFT; + return (unsigned)ret; +} + +static inline bool +RHASH_TRANSIENT_P(VALUE h) +{ +#if USE_TRANSIENT_HEAP + return FL_TEST_RAW(h, RHASH_TRANSIENT_FLAG); +#else + return false; +#endif +} + +static inline void +RHASH_SET_TRANSIENT_FLAG(VALUE h) +{ +#if USE_TRANSIENT_HEAP + FL_SET_RAW(h, RHASH_TRANSIENT_FLAG); +#endif +} + +static inline void +RHASH_UNSET_TRANSIENT_FLAG(VALUE h) +{ +#if USE_TRANSIENT_HEAP + FL_UNSET_RAW(h, RHASH_TRANSIENT_FLAG); +#endif +} + +#endif /* INTERNAL_HASH_H */ diff --git a/internal/imemo.h b/internal/imemo.h new file mode 100644 index 0000000000..ea36c4514f --- /dev/null +++ b/internal/imemo.h @@ -0,0 +1,243 @@ +#ifndef INTERNAL_IMEMO_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_IMEMO_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief IMEMO: Internal memo object. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "internal/array.h" /* for rb_ary_tmp_new_fill */ +#include "internal/gc.h" /* for RB_OBJ_WRITE */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for rb_block_call_func_t */ + +#ifndef IMEMO_DEBUG +# define IMEMO_DEBUG 0 +#endif + +#define IMEMO_MASK 0x0f + +/* FL_USER0 to FL_USER3 is for type */ +#define IMEMO_FL_USHIFT (FL_USHIFT + 4) +#define IMEMO_FL_USER0 FL_USER4 +#define IMEMO_FL_USER1 FL_USER5 +#define IMEMO_FL_USER2 FL_USER6 +#define IMEMO_FL_USER3 FL_USER7 +#define IMEMO_FL_USER4 FL_USER8 +#define IMEMO_FL_USER5 FL_USER9 + +enum imemo_type { + imemo_env = 0, + imemo_cref = 1, /*!< class reference */ + imemo_svar = 2, /*!< special variable */ + imemo_throw_data = 3, + imemo_ifunc = 4, /*!< iterator function */ + imemo_memo = 5, + imemo_ment = 6, + imemo_iseq = 7, + imemo_tmpbuf = 8, + imemo_ast = 9, + imemo_parser_strterm = 10, + imemo_callinfo = 11, + imemo_callcache = 12, + imemo_constcache = 13, +}; + +/* CREF (Class REFerence) is defined in method.h */ + +/*! SVAR (Special VARiable) */ +struct vm_svar { + VALUE flags; + const VALUE cref_or_me; /*!< class reference or rb_method_entry_t */ + const VALUE lastline; + const VALUE backref; + const VALUE others; +}; + +/*! THROW_DATA */ +struct vm_throw_data { + VALUE flags; + VALUE reserved; + const VALUE throw_obj; + const struct rb_control_frame_struct *catch_frame; + int throw_state; +}; + +#define THROW_DATA_CONSUMED IMEMO_FL_USER0 + +/* IFUNC (Internal FUNCtion) */ + +struct vm_ifunc_argc { +#if SIZEOF_INT * 2 > SIZEOF_VALUE + signed int min: (SIZEOF_VALUE * CHAR_BIT) / 2; + signed int max: (SIZEOF_VALUE * CHAR_BIT) / 2; +#else + int min, max; +#endif +}; + +/*! IFUNC (Internal FUNCtion) */ +struct vm_ifunc { + VALUE flags; + VALUE reserved; + rb_block_call_func_t func; + const void *data; + struct vm_ifunc_argc argc; +}; + +struct rb_imemo_tmpbuf_struct { + VALUE flags; + VALUE reserved; + VALUE *ptr; /* malloc'ed buffer */ + struct rb_imemo_tmpbuf_struct *next; /* next imemo */ + size_t cnt; /* buffer size in VALUE */ +}; + +/*! MEMO + * + * @see imemo_type + * */ +struct MEMO { + VALUE flags; + VALUE reserved; + const VALUE v1; + const VALUE v2; + union { + long cnt; + long state; + const VALUE value; + void (*func)(void); + } u3; +}; + +/* ment is in method.h */ + +#define THROW_DATA_P(err) imemo_throw_data_p((VALUE)err) +#define MEMO_CAST(m) ((struct MEMO *)(m)) +#define MEMO_NEW(a, b, c) ((struct MEMO *)rb_imemo_new(imemo_memo, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0)) +#define MEMO_FOR(type, value) ((type *)RARRAY_PTR(value)) +#define NEW_MEMO_FOR(type, value) \ + ((value) = rb_ary_tmp_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value)) +#define NEW_PARTIAL_MEMO_FOR(type, value, member) \ + ((value) = rb_ary_tmp_new_fill(type_roomof(type, VALUE)), \ + rb_ary_set_len((value), offsetof(type, member) / sizeof(VALUE)), \ + MEMO_FOR(type, value)) + +typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t; +VALUE rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0); +rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt); +struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc); +void rb_strterm_mark(VALUE obj); +static inline enum imemo_type imemo_type(VALUE imemo); +static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type); +static inline bool imemo_throw_data_p(VALUE imemo); +static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data); +static inline VALUE rb_imemo_tmpbuf_auto_free_pointer(void); +static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v); +static inline void *rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr); +static inline VALUE rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str); +static inline void MEMO_V1_SET(struct MEMO *m, VALUE v); +static inline void MEMO_V2_SET(struct MEMO *m, VALUE v); + +RUBY_SYMBOL_EXPORT_BEGIN +#if IMEMO_DEBUG +VALUE rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, const char *file, int line); +#define rb_imemo_new(type, v1, v2, v3, v0) rb_imemo_new_debug(type, v1, v2, v3, v0, __FILE__, __LINE__) +#else +VALUE rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0); +#endif +const char *rb_imemo_name(enum imemo_type type); +RUBY_SYMBOL_EXPORT_END + +static inline enum imemo_type +imemo_type(VALUE imemo) +{ + return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK; +} + +static inline int +imemo_type_p(VALUE imemo, enum imemo_type imemo_type) +{ + if (LIKELY(!RB_SPECIAL_CONST_P(imemo))) { + /* fixed at compile time if imemo_type is given. */ + const VALUE mask = (IMEMO_MASK << FL_USHIFT) | RUBY_T_MASK; + const VALUE expected_type = (imemo_type << FL_USHIFT) | T_IMEMO; + /* fixed at runtime. */ + return expected_type == (RBASIC(imemo)->flags & mask); + } + else { + return 0; + } +} + +#define IMEMO_TYPE_P(v, t) imemo_type_p((VALUE)v, t) + +static inline bool +imemo_throw_data_p(VALUE imemo) +{ + return RB_TYPE_P(imemo, T_IMEMO); +} + +static inline struct vm_ifunc * +rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data) +{ + return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS); +} + +static inline VALUE +rb_imemo_tmpbuf_auto_free_pointer(void) +{ + return rb_imemo_new(imemo_tmpbuf, 0, 0, 0, 0); +} + +static inline void * +RB_IMEMO_TMPBUF_PTR(VALUE v) +{ + const struct rb_imemo_tmpbuf_struct *p = (const void *)v; + return p->ptr; +} + +static inline void * +rb_imemo_tmpbuf_set_ptr(VALUE v, void *ptr) +{ + return ((rb_imemo_tmpbuf_t *)v)->ptr = ptr; +} + +static inline VALUE +rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str) +{ + const void *src; + VALUE imemo; + rb_imemo_tmpbuf_t *tmpbuf; + void *dst; + size_t len; + + SafeStringValue(str); + /* create tmpbuf to keep the pointer before xmalloc */ + imemo = rb_imemo_tmpbuf_auto_free_pointer(); + tmpbuf = (rb_imemo_tmpbuf_t *)imemo; + len = RSTRING_LEN(str); + src = RSTRING_PTR(str); + dst = ruby_xmalloc(len); + memcpy(dst, src, len); + tmpbuf->ptr = dst; + return imemo; +} + +static inline void +MEMO_V1_SET(struct MEMO *m, VALUE v) +{ + RB_OBJ_WRITE(m, &m->v1, v); +} + +static inline void +MEMO_V2_SET(struct MEMO *m, VALUE v) +{ + RB_OBJ_WRITE(m, &m->v2, v); +} + +#endif /* INTERNAL_IMEMO_H */ diff --git a/internal/inits.h b/internal/inits.h new file mode 100644 index 0000000000..03e180f77b --- /dev/null +++ b/internal/inits.h @@ -0,0 +1,50 @@ +#ifndef INTERNAL_INITS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_INITS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header aggregating init functions. + */ + +/* class.c */ +void Init_class_hierarchy(void); + +/* dmyext.c */ +void Init_enc(void); +void Init_ext(void); + +/* file.c */ +void Init_File(void); + +/* gc.c */ +void Init_heap(void); + +/* localeinit.c */ +int Init_enc_set_filesystem_encoding(void); + +/* newline.c */ +void Init_newline(void); + +/* vm.c */ +void Init_BareVM(void); +void Init_vm_objects(void); + +/* vm_backtrace.c */ +void Init_vm_backtrace(void); + +/* vm_eval.c */ +void Init_vm_eval(void); + +/* vm_insnhelper.c */ +void Init_vm_stack_canary(void); + +/* vm_method.c */ +void Init_eval_method(void); + +/* inits.c */ +void rb_call_inits(void); + +#endif /* INTERNAL_INITS_H */ diff --git a/internal/io.h b/internal/io.h new file mode 100644 index 0000000000..b5f15499d7 --- /dev/null +++ b/internal/io.h @@ -0,0 +1,38 @@ +#ifndef INTERNAL_IO_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_IO_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for IO. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/io.h" /* for rb_io_t */ + +/* io.c */ +void ruby_set_inplace_mode(const char *); +void rb_stdio_set_default_encoding(void); +VALUE rb_io_flush_raw(VALUE, int); +size_t rb_io_memsize(const rb_io_t *); +int rb_stderr_tty_p(void); +void rb_io_fptr_finalize_internal(void *ptr); +#ifdef rb_io_fptr_finalize +# undef rb_io_fptr_finalize +#endif +#define rb_io_fptr_finalize rb_io_fptr_finalize_internal +VALUE rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt); + +VALUE rb_io_prep_stdin(void); +VALUE rb_io_prep_stdout(void); +VALUE rb_io_prep_stderr(void); + +RUBY_SYMBOL_EXPORT_BEGIN +/* io.c (export) */ +void rb_maygvl_fd_fix_cloexec(int fd); +int rb_gc_for_fd(int err); +void rb_write_error_str(VALUE mesg); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_IO_H */ diff --git a/internal/load.h b/internal/load.h new file mode 100644 index 0000000000..d4c0bb91ba --- /dev/null +++ b/internal/load.h @@ -0,0 +1,18 @@ +#ifndef INTERNAL_LOAD_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_LOAD_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for require. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* load.c */ +VALUE rb_get_expanded_load_path(void); +int rb_require_internal(VALUE fname); +NORETURN(void rb_load_fail(VALUE, const char*)); + +#endif /* INTERNAL_LOAD_H */ diff --git a/internal/loadpath.h b/internal/loadpath.h new file mode 100644 index 0000000000..b3a85e7b41 --- /dev/null +++ b/internal/loadpath.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_LOADPATH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_LOADPATH_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for $LOAD_PATH. + */ + +/* loadpath.c */ +extern const char ruby_exec_prefix[]; +extern const char ruby_initial_load_paths[]; + +#endif /* INTERNAL_LOADPATH_H */ diff --git a/internal/math.h b/internal/math.h new file mode 100644 index 0000000000..08f852ffc1 --- /dev/null +++ b/internal/math.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_MATH_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_MATH_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Math. + */ +#include "ruby/ruby.h" /* for VALUE */ + +/* math.c */ +VALUE rb_math_atan2(VALUE, VALUE); +VALUE rb_math_cos(VALUE); +VALUE rb_math_cosh(VALUE); +VALUE rb_math_exp(VALUE); +VALUE rb_math_hypot(VALUE, VALUE); +VALUE rb_math_log(int argc, const VALUE *argv); +VALUE rb_math_sin(VALUE); +VALUE rb_math_sinh(VALUE); + +#endif /* INTERNAL_MATH_H */ diff --git a/internal/missing.h b/internal/missing.h new file mode 100644 index 0000000000..c0992a151a --- /dev/null +++ b/internal/missing.h @@ -0,0 +1,18 @@ +#ifndef INTERNAL_MISSING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_MISSING_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header corresponding missing. + */ +#include "ruby/internal/config.h" /* for HAVE_SETPROCTITLE */ + +/* missing/setproctitle.c */ +#ifndef HAVE_SETPROCTITLE +extern void ruby_init_setproctitle(int argc, char *argv[]); +#endif + +#endif /* INTERNAL_MISSING_H */ diff --git a/internal/numeric.h b/internal/numeric.h new file mode 100644 index 0000000000..19069cb3bc --- /dev/null +++ b/internal/numeric.h @@ -0,0 +1,271 @@ +#ifndef INTERNAL_NUMERIC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_NUMERIC_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Numeric. + */ +#include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */ +#include "internal/bits.h" /* for RUBY_BIT_ROTL */ +#include "internal/fixnum.h" /* for FIXNUM_POSITIVE_P */ +#include "internal/vm.h" /* for rb_method_basic_definition_p */ +#include "ruby/intern.h" /* for rb_cmperr */ +#include "ruby/ruby.h" /* for USE_FLONUM */ + +#define ROUND_TO(mode, even, up, down) \ + ((mode) == RUBY_NUM_ROUND_HALF_EVEN ? even : \ + (mode) == RUBY_NUM_ROUND_HALF_UP ? up : down) +#define ROUND_FUNC(mode, name) \ + ROUND_TO(mode, name##_half_even, name##_half_up, name##_half_down) +#define ROUND_CALL(mode, name, args) \ + ROUND_TO(mode, name##_half_even args, \ + name##_half_up args, name##_half_down args) + +#ifndef ROUND_DEFAULT +# define ROUND_DEFAULT RUBY_NUM_ROUND_HALF_UP +#endif + +enum ruby_num_rounding_mode { + RUBY_NUM_ROUND_HALF_UP, + RUBY_NUM_ROUND_HALF_EVEN, + RUBY_NUM_ROUND_HALF_DOWN, + RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT, +}; + +#if SIZEOF_DOUBLE <= SIZEOF_VALUE +typedef double rb_float_value_type; +#else +typedef struct { + VALUE values[(SIZEOF_DOUBLE + SIZEOF_VALUE - 1) / SIZEOF_VALUE]; + /* roomof() needs internal.h, and the order of some macros may matter */ +} rb_float_value_type; +#endif + +struct RFloat { + struct RBasic basic; + rb_float_value_type float_value; +}; + +#define RFLOAT(obj) ((struct RFloat *)(obj)) + +/* numeric.c */ +int rb_num_to_uint(VALUE val, unsigned int *ret); +VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl); +double ruby_float_step_size(double beg, double end, double unit, int excl); +int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless); +int rb_num_negative_p(VALUE); +VALUE rb_int_succ(VALUE num); +VALUE rb_float_uminus(VALUE num); +VALUE rb_int_plus(VALUE x, VALUE y); +VALUE rb_float_plus(VALUE x, VALUE y); +VALUE rb_int_minus(VALUE x, VALUE y); +VALUE rb_float_minus(VALUE x, VALUE y); +VALUE rb_int_mul(VALUE x, VALUE y); +VALUE rb_float_mul(VALUE x, VALUE y); +VALUE rb_float_div(VALUE x, VALUE y); +VALUE rb_int_idiv(VALUE x, VALUE y); +VALUE rb_int_modulo(VALUE x, VALUE y); +VALUE rb_int2str(VALUE num, int base); +VALUE rb_fix_plus(VALUE x, VALUE y); +VALUE rb_int_gt(VALUE x, VALUE y); +VALUE rb_float_gt(VALUE x, VALUE y); +VALUE rb_int_ge(VALUE x, VALUE y); +enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts); +double rb_int_fdiv_double(VALUE x, VALUE y); +VALUE rb_int_pow(VALUE x, VALUE y); +VALUE rb_float_pow(VALUE x, VALUE y); +VALUE rb_int_cmp(VALUE x, VALUE y); +VALUE rb_int_equal(VALUE x, VALUE y); +VALUE rb_int_divmod(VALUE x, VALUE y); +VALUE rb_int_and(VALUE x, VALUE y); +VALUE rb_int_lshift(VALUE x, VALUE y); +VALUE rb_int_div(VALUE x, VALUE y); +int rb_int_positive_p(VALUE num); +int rb_int_negative_p(VALUE num); +VALUE rb_check_integer_type(VALUE); +VALUE rb_num_pow(VALUE x, VALUE y); +VALUE rb_float_ceil(VALUE num, int ndigits); +VALUE rb_float_floor(VALUE x, int ndigits); +VALUE rb_float_abs(VALUE flt); +static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid); +static inline int rb_num_positive_int_p(VALUE num); +static inline int rb_num_negative_int_p(VALUE num); +static inline double rb_float_flonum_value(VALUE v); +static inline double rb_float_noflonum_value(VALUE v); +static inline double rb_float_value_inline(VALUE v); +static inline VALUE rb_float_new_inline(double d); +static inline bool INT_POSITIVE_P(VALUE num); +static inline bool INT_NEGATIVE_P(VALUE num); +static inline bool FLOAT_ZERO_P(VALUE num); +#define rb_float_value rb_float_value_inline +#define rb_float_new rb_float_new_inline + +RUBY_SYMBOL_EXPORT_BEGIN +/* numeric.c (export) */ +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_flo_div_flo(VALUE x, VALUE y); +double ruby_float_mod(double x, double y); +VALUE rb_float_equal(VALUE x, VALUE y); +int rb_float_cmp(VALUE x, VALUE y); +VALUE rb_float_eql(VALUE x, VALUE y); +VALUE rb_fix_aref(VALUE fix, VALUE idx); +VALUE rb_int_zero_p(VALUE num); +VALUE rb_int_even_p(VALUE num); +VALUE rb_int_odd_p(VALUE num); +VALUE rb_int_abs(VALUE num); +VALUE rb_int_bit_length(VALUE num); +VALUE rb_int_uminus(VALUE num); +VALUE rb_int_comp(VALUE num); +MJIT_SYMBOL_EXPORT_END + +static inline bool +INT_POSITIVE_P(VALUE num) +{ + if (FIXNUM_P(num)) { + return FIXNUM_POSITIVE_P(num); + } + else { + return BIGNUM_POSITIVE_P(num); + } +} + +static inline bool +INT_NEGATIVE_P(VALUE num) +{ + if (FIXNUM_P(num)) { + return FIXNUM_NEGATIVE_P(num); + } + else { + return BIGNUM_NEGATIVE_P(num); + } +} + +static inline bool +FLOAT_ZERO_P(VALUE num) +{ + return RFLOAT_VALUE(num) == 0.0; +} + +static inline VALUE +rb_num_compare_with_zero(VALUE num, ID mid) +{ + VALUE zero = INT2FIX(0); + VALUE r = rb_check_funcall(num, mid, 1, &zero); + if (r == Qundef) { + rb_cmperr(num, zero); + } + return r; +} + +static inline int +rb_num_positive_int_p(VALUE num) +{ + const ID mid = '>'; + + if (FIXNUM_P(num)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return FIXNUM_POSITIVE_P(num); + } + else if (RB_TYPE_P(num, T_BIGNUM)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return BIGNUM_POSITIVE_P(num); + } + return RTEST(rb_num_compare_with_zero(num, mid)); +} + +static inline int +rb_num_negative_int_p(VALUE num) +{ + const ID mid = '<'; + + if (FIXNUM_P(num)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return FIXNUM_NEGATIVE_P(num); + } + else if (RB_TYPE_P(num, T_BIGNUM)) { + if (rb_method_basic_definition_p(rb_cInteger, mid)) + return BIGNUM_NEGATIVE_P(num); + } + return RTEST(rb_num_compare_with_zero(num, mid)); +} + +static inline double +rb_float_flonum_value(VALUE v) +{ +#if USE_FLONUM + if (v != (VALUE)0x8000000000000002) { /* LIKELY */ + union { + double d; + VALUE v; + } t; + + VALUE b63 = (v >> 63); + /* e: xx1... -> 011... */ + /* xx0... -> 100... */ + /* ^b63 */ + t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~(VALUE)0x03), 3); + return t.d; + } +#endif + return 0.0; +} + +static inline double +rb_float_noflonum_value(VALUE v) +{ +#if SIZEOF_DOUBLE <= SIZEOF_VALUE + return RFLOAT(v)->float_value; +#else + union { + rb_float_value_type v; + double d; + } u = {RFLOAT(v)->float_value}; + return u.d; +#endif +} + +static inline double +rb_float_value_inline(VALUE v) +{ + if (FLONUM_P(v)) { + return rb_float_flonum_value(v); + } + return rb_float_noflonum_value(v); +} + +static inline VALUE +rb_float_new_inline(double d) +{ +#if USE_FLONUM + union { + double d; + VALUE v; + } t; + int bits; + + t.d = d; + bits = (int)((VALUE)(t.v >> 60) & 0x7); + /* bits contains 3 bits of b62..b60. */ + /* bits - 3 = */ + /* b011 -> b000 */ + /* b100 -> b001 */ + + if (t.v != 0x3000000000000000 /* 1.72723e-77 */ && + !((bits-3) & ~0x01)) { + return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02; + } + else if (t.v == (VALUE)0) { + /* +0.0 */ + return 0x8000000000000002; + } + /* out of range */ +#endif + return rb_float_new_in_heap(d); +} + +#endif /* INTERNAL_NUMERIC_H */ diff --git a/internal/object.h b/internal/object.h new file mode 100644 index 0000000000..f560fb7f9f --- /dev/null +++ b/internal/object.h @@ -0,0 +1,83 @@ +#ifndef INTERNAL_OBJECT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_OBJECT_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Object. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "internal/class.h" /* for RCLASS_IV_INDEX_TBL */ + +#ifdef ROBJECT_IV_INDEX_TBL +# undef ROBJECT_IV_INDEX_TBL +#endif + +/* object.c */ +VALUE rb_class_search_ancestor(VALUE klass, VALUE super); +NORETURN(void rb_undefined_alloc(VALUE klass)); +double rb_num_to_dbl(VALUE val); +VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound); +VALUE rb_immutable_obj_clone(int, VALUE *, VALUE); +VALUE rb_check_convert_type_with_id(VALUE,int,const char*,ID); +int rb_bool_expected(VALUE, const char *); +static inline void RBASIC_CLEAR_CLASS(VALUE obj); +static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); +static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); +static inline struct st_table *ROBJECT_IV_INDEX_TBL_inline(VALUE obj); + +RUBY_SYMBOL_EXPORT_BEGIN +/* object.c (export) */ +int rb_opts_exception_p(VALUE opts, int default_value); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +CONSTFUNC(VALUE rb_obj_equal(VALUE obj1, VALUE obj2)); +CONSTFUNC(VALUE rb_obj_not(VALUE obj)); +VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); +void rb_obj_copy_ivar(VALUE dest, VALUE obj); +VALUE rb_false(VALUE obj); +VALUE rb_convert_type_with_id(VALUE v, int t, const char* nam, ID mid); +VALUE rb_obj_size(VALUE self, VALUE args, VALUE obj); +VALUE rb_get_freeze_opt(int argc, VALUE *argv); +MJIT_SYMBOL_EXPORT_END + +static inline void +RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass) +{ + const VALUE *ptr = &RBASIC(obj)->klass; + *(VALUE *)ptr = klass; +} + +static inline void +RBASIC_CLEAR_CLASS(VALUE obj) +{ + RBASIC_SET_CLASS_RAW(obj, 0); +} + +static inline void +RBASIC_SET_CLASS(VALUE obj, VALUE klass) +{ + VALUE oldv = RBASIC_CLASS(obj); + RBASIC_SET_CLASS_RAW(obj, klass); + RB_OBJ_WRITTEN(obj, oldv, klass); +} + +RBIMPL_ATTR_PURE() +static inline struct st_table * +ROBJECT_IV_INDEX_TBL_inline(VALUE obj) +{ + if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { + VALUE klass = rb_obj_class(obj); + return RCLASS_IV_INDEX_TBL(klass); + } + else { + const struct RObject *const ptr = ROBJECT(obj); + return ptr->as.heap.iv_index_tbl; + } +} +#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL_inline + +#endif /* INTERNAL_OBJECT_H */ diff --git a/internal/parse.h b/internal/parse.h new file mode 100644 index 0000000000..d9f5b56bc5 --- /dev/null +++ b/internal/parse.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_PARSE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PARSE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for the parser. + */ +#include "ruby/ruby.h" /* for VALUE */ +struct rb_iseq_struct; /* in vm_core.h */ + +/* parse.y */ +VALUE rb_parser_set_yydebug(VALUE, VALUE); +void *rb_parser_load_file(VALUE parser, VALUE name); +void rb_parser_keep_script_lines(VALUE vparser); + +RUBY_SYMBOL_EXPORT_BEGIN +VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_PARSE_H */ diff --git a/internal/proc.h b/internal/proc.h new file mode 100644 index 0000000000..2416c31e14 --- /dev/null +++ b/internal/proc.h @@ -0,0 +1,32 @@ +#ifndef INTERNAL_PROC_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PROC_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Proc. + */ +#include "ruby/ruby.h" /* for rb_block_call_func_t */ +#include "ruby/st.h" /* for st_index_t */ +struct rb_block; /* in vm_core.h */ +struct rb_iseq_struct; /* in vm_core.h */ + +/* proc.c */ +VALUE rb_proc_location(VALUE self); +st_index_t rb_hash_proc(st_index_t hash, VALUE proc); +int rb_block_pair_yield_optimizable(void); +int rb_block_arity(void); +int rb_block_min_max_arity(int *max); +VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info); +VALUE rb_callable_receiver(VALUE); + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val); +VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc); +VALUE rb_iseq_location(const struct rb_iseq_struct *iseq); +VALUE rb_sym_to_proc(VALUE sym); +MJIT_SYMBOL_EXPORT_END + +#endif /* INTERNAL_PROC_H */ diff --git a/internal/process.h b/internal/process.h new file mode 100644 index 0000000000..ceadfdcbbb --- /dev/null +++ b/internal/process.h @@ -0,0 +1,137 @@ +#ifndef INTERNAL_PROCESS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_PROCESS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Process. + */ +#include "ruby/internal/config.h" /* for rb_pid_t */ +#include <stddef.h> /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> /* for mode_t */ +#endif + +#ifdef _WIN32 +# include "ruby/win32.h" /* for mode_t */ +#endif + +#include "ruby/ruby.h" /* for VALUE */ +#include "internal/imemo.h" /* for RB_IMEMO_TMPBUF_PTR */ +#include "internal/warnings.h" /* for COMPILER_WARNING_PUSH */ + +#define RB_MAX_GROUPS (65536) + +struct waitpid_state; +struct rb_process_status; +struct rb_execarg { + union { + struct { + VALUE shell_script; + } sh; + struct { + VALUE command_name; + VALUE command_abspath; /* full path string or nil */ + VALUE argv_str; + VALUE argv_buf; + } cmd; + } invoke; + VALUE redirect_fds; + VALUE envp_str; + VALUE envp_buf; + VALUE dup2_tmpbuf; + unsigned use_shell : 1; + unsigned pgroup_given : 1; + unsigned umask_given : 1; + unsigned unsetenv_others_given : 1; + unsigned unsetenv_others_do : 1; + unsigned close_others_given : 1; + unsigned close_others_do : 1; + unsigned chdir_given : 1; + unsigned new_pgroup_given : 1; + unsigned new_pgroup_flag : 1; + unsigned uid_given : 1; + unsigned gid_given : 1; + unsigned exception : 1; + unsigned exception_given : 1; + struct rb_process_status *status; + struct waitpid_state *waitpid_state; /* for async process management */ + rb_pid_t pgroup_pgid; /* asis(-1), new pgroup(0), specified pgroup (0<V). */ + VALUE rlimit_limits; /* Qfalse or [[rtype, softlim, hardlim], ...] */ + mode_t umask_mask; + rb_uid_t uid; + rb_gid_t gid; + int close_others_maxhint; + VALUE fd_dup2; + VALUE fd_close; + VALUE fd_open; + VALUE fd_dup2_child; + VALUE env_modification; /* Qfalse or [[k1,v1], ...] */ + VALUE path_env; + VALUE chdir_dir; +}; + +/* process.c */ +rb_pid_t rb_call_proc__fork(void); +void rb_last_status_clear(void); +static inline char **ARGVSTR2ARGV(VALUE argv_str); +static inline size_t ARGVSTR2ARGC(VALUE argv_str); + +#ifdef HAVE_PWD_H +VALUE rb_getlogin(void); +VALUE rb_getpwdirnam_for_login(VALUE login); /* read as: "get pwd db home dir by username for login" */ +VALUE rb_getpwdiruid(void); /* read as: "get pwd db home dir for getuid()" */ +#endif + +RUBY_SYMBOL_EXPORT_BEGIN +/* process.c (export) */ +int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen); +rb_pid_t rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds, char *errmsg, size_t errmsg_buflen); +VALUE rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt); +struct rb_execarg *rb_execarg_get(VALUE execarg_obj); /* dangerous. needs GC guard. */ +int rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val); +void rb_execarg_parent_start(VALUE execarg_obj); +void rb_execarg_parent_end(VALUE execarg_obj); +int rb_execarg_run_options(const struct rb_execarg *e, struct rb_execarg *s, char* errmsg, size_t errmsg_buflen); +VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash); +void rb_execarg_setenv(VALUE execarg_obj, VALUE env); +RUBY_SYMBOL_EXPORT_END + +/* argv_str contains extra two elements. + * The beginning one is for /bin/sh used by exec_with_sh. + * The last one for terminating NULL used by execve. + * See rb_exec_fillarg() in process.c. */ +static inline char ** +ARGVSTR2ARGV(VALUE argv_str) +{ + char **buf = RB_IMEMO_TMPBUF_PTR(argv_str); + return &buf[1]; +} + +static inline size_t +ARGVSTR2ARGC(VALUE argv_str) +{ + size_t i = 0; + char *const *p = ARGVSTR2ARGV(argv_str); + while (p[i++]) + ; + return i - 1; +} + +#ifdef HAVE_WORKING_FORK +COMPILER_WARNING_PUSH +#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC) +COMPILER_WARNING_IGNORED(-Wdeprecated-declarations) +#endif +static inline rb_pid_t +rb_fork(void) +{ + return fork(); +} +COMPILER_WARNING_POP +#endif + +#endif /* INTERNAL_PROCESS_H */ diff --git a/internal/random.h b/internal/random.h new file mode 100644 index 0000000000..231e2d5d7e --- /dev/null +++ b/internal/random.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_RANDOM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RANDOM_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Random. + */ +#include <stddef.h> /* for size_t */ + +/* random.c */ +int ruby_fill_random_bytes(void *, size_t, int); + +#endif /* INTERNAL_RANDOM_H */ diff --git a/internal/range.h b/internal/range.h new file mode 100644 index 0000000000..8daba0ecab --- /dev/null +++ b/internal/range.h @@ -0,0 +1,40 @@ +#ifndef INTERNAL_RANGE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RANGE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Range. + */ +#include "internal/struct.h" /* for RSTRUCT */ + +/* range.c */ +static inline VALUE RANGE_BEG(VALUE r); +static inline VALUE RANGE_END(VALUE r); +static inline VALUE RANGE_EXCL(VALUE r); + +static inline VALUE +RANGE_BEG(VALUE r) +{ + return RSTRUCT(r)->as.ary[0]; +} + +static inline VALUE +RANGE_END(VALUE r) +{ + return RSTRUCT(r)->as.ary[1]; +} + +static inline VALUE +RANGE_EXCL(VALUE r) +{ + return RSTRUCT(r)->as.ary[2]; +} + +VALUE +rb_range_component_beg_len(VALUE b, VALUE e, int excl, + long *begp, long *lenp, long len, int err); + +#endif /* INTERNAL_RANGE_H */ diff --git a/internal/rational.h b/internal/rational.h new file mode 100644 index 0000000000..61ddbf089a --- /dev/null +++ b/internal/rational.h @@ -0,0 +1,72 @@ +#ifndef INTERNAL_RATIONAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RATIONAL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Rational. + */ +#include "ruby/internal/config.h" /* for HAVE_LIBGMP */ +#include "ruby/ruby.h" /* for struct RBasic */ +#include "internal/gc.h" /* for RB_OBJ_WRITE */ +#include "internal/numeric.h" /* for INT_POSITIVE_P */ +#include "ruby_assert.h" /* for assert */ + +struct RRational { + struct RBasic basic; + VALUE num; + VALUE den; +}; + +#define RRATIONAL(obj) ((struct RRational *)(obj)) + +/* rational.c */ +VALUE rb_rational_canonicalize(VALUE x); +VALUE rb_rational_uminus(VALUE self); +VALUE rb_rational_plus(VALUE self, VALUE other); +VALUE rb_rational_minus(VALUE self, VALUE other); +VALUE rb_rational_mul(VALUE self, VALUE other); +VALUE rb_rational_div(VALUE self, VALUE other); +VALUE rb_lcm(VALUE x, VALUE y); +VALUE rb_rational_reciprocal(VALUE x); +VALUE rb_cstr_to_rat(const char *, int); +VALUE rb_rational_hash(VALUE self); +VALUE rb_rational_abs(VALUE self); +VALUE rb_rational_cmp(VALUE self, VALUE other); +VALUE rb_rational_pow(VALUE self, VALUE other); +VALUE rb_rational_floor(VALUE self, int ndigits); +VALUE rb_numeric_quo(VALUE x, VALUE y); +VALUE rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num); +VALUE rb_float_numerator(VALUE x); +VALUE rb_float_denominator(VALUE x); + +static inline void RATIONAL_SET_NUM(VALUE r, VALUE n); +static inline void RATIONAL_SET_DEN(VALUE r, VALUE d); + +RUBY_SYMBOL_EXPORT_BEGIN +/* rational.c (export) */ +VALUE rb_gcd(VALUE x, VALUE y); +VALUE rb_gcd_normal(VALUE self, VALUE other); +#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H) +VALUE rb_gcd_gmp(VALUE x, VALUE y); +#endif +RUBY_SYMBOL_EXPORT_END + +static inline void +RATIONAL_SET_NUM(VALUE r, VALUE n) +{ + assert(RB_INTEGER_TYPE_P(n)); + RB_OBJ_WRITE(r, &RRATIONAL(r)->num, n); +} + +static inline void +RATIONAL_SET_DEN(VALUE r, VALUE d) +{ + assert(RB_INTEGER_TYPE_P(d)); + assert(INT_POSITIVE_P(d)); + RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d); +} + +#endif /* INTERNAL_RATIONAL_H */ diff --git a/internal/re.h b/internal/re.h new file mode 100644 index 0000000000..8b31b3d8a5 --- /dev/null +++ b/internal/re.h @@ -0,0 +1,30 @@ +#ifndef INTERNAL_RE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_RE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Regexp. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ + +/* re.c */ +VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline); +VALUE rb_reg_check_preprocess(VALUE); +long rb_reg_search0(VALUE, VALUE, long, int, int); +VALUE rb_reg_match_p(VALUE re, VALUE str, long pos); +bool rb_reg_start_with_p(VALUE re, VALUE str); +VALUE rb_reg_hash(VALUE re); +VALUE rb_reg_equal(VALUE re1, VALUE re2); +void rb_backref_set_string(VALUE string, long pos, long len); +void rb_match_unbusy(VALUE); +int rb_match_count(VALUE match); +int rb_match_nth_defined(int nth, VALUE match); +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_reg_new_ary(VALUE ary, int options); +MJIT_SYMBOL_EXPORT_END + +#endif /* INTERNAL_RE_H */ diff --git a/internal/sanitizers.h b/internal/sanitizers.h new file mode 100644 index 0000000000..6e2d81137f --- /dev/null +++ b/internal/sanitizers.h @@ -0,0 +1,190 @@ +#ifndef INTERNAL_SANITIZERS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SANITIZERS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for ASAN / MSAN / etc. + */ +#include "ruby/internal/config.h" +#include "internal/compilers.h" /* for __has_feature */ + +#ifdef HAVE_VALGRIND_MEMCHECK_H +# include <valgrind/memcheck.h> +#endif + +#ifdef HAVE_SANITIZER_ASAN_INTERFACE_H +# include <sanitizer/asan_interface.h> +#endif + +#ifdef HAVE_SANITIZER_MSAN_INTERFACE_H +# if __has_feature(memory_sanitizer) +# include <sanitizer/msan_interface.h> +# endif +#endif + +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ + +#if 0 +#elif __has_feature(memory_sanitizer) && __has_feature(address_sanitizer) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("memory, address"), __noinline__)) x +#elif __has_feature(address_sanitizer) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + __attribute__((__no_sanitize__("address"), __noinline__)) x +#elif defined(NO_SANITIZE_ADDRESS) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + NO_SANITIZE_ADDRESS(NOINLINE(x)) +#elif defined(NO_ADDRESS_SAFETY_ANALYSIS) +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \ + NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x)) +#else +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x +#endif + +#if defined(NO_SANITIZE) && RBIMPL_COMPILER_IS(GCC) +/* GCC warns about unknown sanitizer, which is annoying. */ +# include "internal/warnings.h" +# undef NO_SANITIZE +# define NO_SANITIZE(x, y) \ + COMPILER_WARNING_PUSH; \ + COMPILER_WARNING_IGNORED(-Wattributes); \ + __attribute__((__no_sanitize__(x))) y; \ + COMPILER_WARNING_POP +#endif + +#ifndef NO_SANITIZE +# define NO_SANITIZE(x, y) y +#endif + +#if !__has_feature(address_sanitizer) +# define __asan_poison_memory_region(x, y) +# define __asan_unpoison_memory_region(x, y) +# define __asan_region_is_poisoned(x, y) 0 +#endif + +#if !__has_feature(memory_sanitizer) +# define __msan_allocated_memory(x, y) ((void)(x), (void)(y)) +# define __msan_poison(x, y) ((void)(x), (void)(y)) +# define __msan_unpoison(x, y) ((void)(x), (void)(y)) +# define __msan_unpoison_string(x) ((void)(x)) +#endif + +#ifdef VALGRIND_MAKE_READABLE +# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n)) +#endif + +#ifdef VALGRIND_MAKE_WRITABLE +# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n)) +#endif + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(p, n) 0 +#endif + +#ifndef VALGRIND_MAKE_MEM_UNDEFINED +# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0 +#endif + +#ifndef MJIT_HEADER + +/*! + * This function asserts that a (continuous) memory region from ptr to size + * being "poisoned". Both read / write access to such memory region are + * prohibited until properly unpoisoned. The region must be previously + * allocated (do not pass a freed pointer here), but not necessarily be an + * entire object that the malloc returns. You can punch hole a part of a + * gigantic heap arena. This is handy when you do not free an allocated memory + * region to reuse later: poison when you keep it unused, and unpoison when you + * reuse. + * + * \param[in] ptr pointer to the beginning of the memory region to poison. + * \param[in] size the length of the memory region to poison. + */ +static inline void +asan_poison_memory_region(const volatile void *ptr, size_t size) +{ + __msan_poison(ptr, size); + __asan_poison_memory_region(ptr, size); +} + +/*! + * This is a variant of asan_poison_memory_region that takes a VALUE. + * + * \param[in] obj target object. + */ +static inline void +asan_poison_object(VALUE obj) +{ + MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj; + asan_poison_memory_region(ptr, SIZEOF_VALUE); +} + +#if !__has_feature(address_sanitizer) +#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj)) +#else +#define asan_poison_object_if(ptr, obj) do { \ + if (ptr) asan_poison_object(obj); \ + } while (0) +#endif + +/*! + * This function predicates if the given object is fully addressable or not. + * + * \param[in] obj target object. + * \retval 0 the given object is fully addressable. + * \retval otherwise pointer to first such byte who is poisoned. + */ +static inline void * +asan_poisoned_object_p(VALUE obj) +{ + MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj; + return __asan_region_is_poisoned(ptr, SIZEOF_VALUE); +} + +/*! + * This function asserts that a (formally poisoned) memory region from ptr to + * size is now addressable. Write access to such memory region gets allowed. + * However read access might or might not be possible depending on situations, + * because the region can have contents of previous usages. That information + * should be passed by the malloc_p flag. If that is true, the contents of the + * region is _not_ fully defined (like the return value of malloc behaves). + * Reading from there is NG; write something first. If malloc_p is false on + * the other hand, that memory region is fully defined and can be read + * immediately. + * + * \param[in] ptr pointer to the beginning of the memory region to unpoison. + * \param[in] size the length of the memory region. + * \param[in] malloc_p if the memory region is like a malloc's return value or not. + */ +static inline void +asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p) +{ + __asan_unpoison_memory_region(ptr, size); + if (malloc_p) { + __msan_allocated_memory(ptr, size); + } + else { + __msan_unpoison(ptr, size); + } +} + +/*! + * This is a variant of asan_unpoison_memory_region that takes a VALUE. + * + * \param[in] obj target object. + * \param[in] malloc_p if the memory region is like a malloc's return value or not. + */ +static inline void +asan_unpoison_object(VALUE obj, bool newobj_p) +{ + MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj; + asan_unpoison_memory_region(ptr, SIZEOF_VALUE, newobj_p); +} + +#endif /* MJIT_HEADER */ + +#endif /* INTERNAL_SANITIZERS_H */ diff --git a/internal/serial.h b/internal/serial.h new file mode 100644 index 0000000000..df9e9a44f0 --- /dev/null +++ b/internal/serial.h @@ -0,0 +1,23 @@ +#ifndef INTERNAL_SERIAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SERIAL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for rb_serial_t. + */ +#include "ruby/internal/config.h" /* for HAVE_LONG_LONG */ +#include "ruby/defines.h" /* for LONG_LONG */ + +#ifndef HAVE_LONG_LONG +# error need C99+ +#endif + +typedef unsigned LONG_LONG rb_serial_t; +#define SERIALT2NUM ULL2NUM +#define PRI_SERIALT_PREFIX PRI_LL_PREFIX +#define SIZEOF_SERIAL_T SIZEOF_LONG_LONG + +#endif /* INTERNAL_SERIAL_H */ diff --git a/internal/signal.h b/internal/signal.h new file mode 100644 index 0000000000..86fb54e949 --- /dev/null +++ b/internal/signal.h @@ -0,0 +1,21 @@ +#ifndef INTERNAL_SIGNAL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SIGNAL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for SignalException. + */ + +/* signal.c */ +extern int ruby_enable_coredump; +int rb_get_next_signal(void); + +RUBY_SYMBOL_EXPORT_BEGIN +/* signal.c (export) */ +int rb_grantpt(int fd); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_SIGNAL_H */ diff --git a/internal/static_assert.h b/internal/static_assert.h new file mode 100644 index 0000000000..70dd0b7a1e --- /dev/null +++ b/internal/static_assert.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_STATIC_ASSERT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STATIC_ASSERT_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief C11 shim for _Static_assert. + */ +#include "ruby/internal/static_assert.h" +#ifndef STATIC_ASSERT +# define STATIC_ASSERT RBIMPL_STATIC_ASSERT +#endif + +#endif /* INTERNAL_STATIC_ASSERT_H */ diff --git a/internal/string.h b/internal/string.h new file mode 100644 index 0000000000..18b01862f7 --- /dev/null +++ b/internal/string.h @@ -0,0 +1,141 @@ +#ifndef INTERNAL_STRING_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STRING_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for String. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "internal/compilers.h" /* for __has_builtin */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "ruby/ruby.h" /* for VALUE */ + +#define STR_NOEMBED FL_USER1 +#define STR_SHARED FL_USER2 /* = ELTS_SHARED */ + +#ifdef rb_fstring_cstr +# undef rb_fstring_cstr +#endif + +/* string.c */ +VALUE rb_fstring(VALUE); +VALUE rb_fstring_cstr(const char *str); +VALUE rb_fstring_enc_new(const char *ptr, long len, rb_encoding *enc); +int rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p); +int rb_str_symname_p(VALUE); +VALUE rb_str_quote_unprintable(VALUE); +char *rb_str_fill_terminator(VALUE str, const int termlen); +void rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen); +VALUE rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg); +VALUE rb_str_chomp_string(VALUE str, VALUE chomp); +VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc); +VALUE rb_str_cat_conv_enc_opts(VALUE newstr, long ofs, const char *ptr, long len, + rb_encoding *from, int ecflags, VALUE ecopts); +VALUE rb_enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl); +VALUE rb_str_escape(VALUE str); +size_t rb_str_memsize(VALUE); +char *rb_str_to_cstr(VALUE str); +const char *ruby_escaped_char(int c); +void rb_str_make_independent(VALUE str); +int rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc); + +static inline bool STR_EMBED_P(VALUE str); +static inline bool STR_SHARED_P(VALUE str); +static inline VALUE QUOTE(VALUE v); +static inline VALUE QUOTE_ID(ID v); +static inline bool is_ascii_string(VALUE str); +static inline bool is_broken_string(VALUE str); +static inline VALUE rb_str_eql_internal(const VALUE str1, const VALUE str2); + +RUBY_SYMBOL_EXPORT_BEGIN +/* string.c (export) */ +VALUE rb_str_tmp_frozen_acquire(VALUE str); +void rb_str_tmp_frozen_release(VALUE str, VALUE tmp); +VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc); +VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE); +VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_fstring_new(const char *ptr, long len); +VALUE rb_obj_as_string_result(VALUE str, VALUE obj); +VALUE rb_str_opt_plus(VALUE x, VALUE y); +VALUE rb_str_concat_literals(size_t num, const VALUE *strary); +VALUE rb_str_eql(VALUE str1, VALUE str2); +VALUE rb_id_quote_unprintable(ID); +VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc); + +struct rb_execution_context_struct; +VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str); +MJIT_SYMBOL_EXPORT_END + +#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str)) +#define rb_fstring_literal(str) rb_fstring_lit(str) +#define rb_fstring_enc_lit(str, enc) rb_fstring_enc_new((str), rb_strlen_lit(str), (enc)) +#define rb_fstring_enc_literal(str, enc) rb_fstring_enc_lit(str, enc) + +static inline VALUE +QUOTE(VALUE v) +{ + return rb_str_quote_unprintable(v); +} + +static inline VALUE +QUOTE_ID(ID i) +{ + return rb_id_quote_unprintable(i); +} + +static inline bool +STR_EMBED_P(VALUE str) +{ + return ! FL_TEST_RAW(str, STR_NOEMBED); +} + +static inline bool +STR_SHARED_P(VALUE str) +{ + return FL_ALL_RAW(str, STR_NOEMBED | ELTS_SHARED); +} + +static inline bool +is_ascii_string(VALUE str) +{ + return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT; +} + +static inline bool +is_broken_string(VALUE str) +{ + return rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN; +} + +/* expect tail call optimization */ +// YJIT needs this function to never allocate and never raise +static inline VALUE +rb_str_eql_internal(const VALUE str1, const VALUE str2) +{ + const long len = RSTRING_LEN(str1); + const char *ptr1, *ptr2; + + if (len != RSTRING_LEN(str2)) return Qfalse; + if (!rb_str_comparable(str1, str2)) return Qfalse; + if ((ptr1 = RSTRING_PTR(str1)) == (ptr2 = RSTRING_PTR(str2))) + return Qtrue; + if (memcmp(ptr1, ptr2, len) == 0) + return Qtrue; + return Qfalse; +} + +#if __has_builtin(__builtin_constant_p) +# define rb_fstring_cstr(str) \ + (__builtin_constant_p(str) ? \ + rb_fstring_new((str), (long)strlen(str)) : \ + (rb_fstring_cstr)(str)) +#endif +#endif /* INTERNAL_STRING_H */ diff --git a/internal/struct.h b/internal/struct.h new file mode 100644 index 0000000000..8acc00ec3c --- /dev/null +++ b/internal/struct.h @@ -0,0 +1,153 @@ +#ifndef INTERNAL_STRUCT_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_STRUCT_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Struct. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "internal/gc.h" /* for RB_OBJ_WRITE */ +#include "ruby/ruby.h" /* for struct RBasic */ + +enum { + RSTRUCT_EMBED_LEN_MAX = RVALUE_EMBED_LEN_MAX, + RSTRUCT_EMBED_LEN_MASK = (RUBY_FL_USER2|RUBY_FL_USER1), + RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1), + RSTRUCT_TRANSIENT_FLAG = FL_USER3, +}; + +struct RStruct { + struct RBasic basic; + union { + struct { + long len; + const VALUE *ptr; + } heap; + const VALUE ary[RSTRUCT_EMBED_LEN_MAX]; + } as; +}; + +#define RSTRUCT(obj) ((struct RStruct *)(obj)) + +#ifdef RSTRUCT_LEN +# undef RSTRUCT_LEN +#endif + +#ifdef RSTRUCT_PTR +# undef RSTRUCT_PTR +#endif + +#ifdef RSTRUCT_SET +# undef RSTRUCT_SET +#endif + +#ifdef RSTRUCT_GET +# undef RSTRUCT_GET +#endif + +#define RSTRUCT_LEN internal_RSTRUCT_LEN +#define RSTRUCT_SET internal_RSTRUCT_SET +#define RSTRUCT_GET internal_RSTRUCT_GET + +/* struct.c */ +VALUE rb_struct_init_copy(VALUE copy, VALUE s); +VALUE rb_struct_lookup(VALUE s, VALUE idx); +VALUE rb_struct_s_keyword_init(VALUE klass); +static inline const VALUE *rb_struct_const_heap_ptr(VALUE st); +static inline bool RSTRUCT_TRANSIENT_P(VALUE st); +static inline void RSTRUCT_TRANSIENT_SET(VALUE st); +static inline void RSTRUCT_TRANSIENT_UNSET(VALUE st); +static inline long RSTRUCT_EMBED_LEN(VALUE st); +static inline long RSTRUCT_LEN(VALUE st); +static inline int RSTRUCT_LENINT(VALUE st); +static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st); +static inline void RSTRUCT_SET(VALUE st, long k, VALUE v); +static inline VALUE RSTRUCT_GET(VALUE st, long k); + +static inline bool +RSTRUCT_TRANSIENT_P(VALUE st) +{ +#if USE_TRANSIENT_HEAP + return FL_TEST_RAW(st, RSTRUCT_TRANSIENT_FLAG); +#else + return false; +#endif +} + +static inline void +RSTRUCT_TRANSIENT_SET(VALUE st) +{ +#if USE_TRANSIENT_HEAP + FL_SET_RAW(st, RSTRUCT_TRANSIENT_FLAG); +#endif +} + +static inline void +RSTRUCT_TRANSIENT_UNSET(VALUE st) +{ +#if USE_TRANSIENT_HEAP + FL_UNSET_RAW(st, RSTRUCT_TRANSIENT_FLAG); +#endif +} + +static inline long +RSTRUCT_EMBED_LEN(VALUE st) +{ + long ret = FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK); + ret >>= RSTRUCT_EMBED_LEN_SHIFT; + return ret; +} + +static inline long +RSTRUCT_LEN(VALUE st) +{ + if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) { + return RSTRUCT_EMBED_LEN(st); + } + else { + return RSTRUCT(st)->as.heap.len; + } +} + +static inline int +RSTRUCT_LENINT(VALUE st) +{ + return rb_long2int(RSTRUCT_LEN(st)); +} + +static inline const VALUE * +RSTRUCT_CONST_PTR(VALUE st) +{ + const struct RStruct *p = RSTRUCT(st); + + if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) { + return p->as.ary; + } + else { + return p->as.heap.ptr; + } +} + +static inline void +RSTRUCT_SET(VALUE st, long k, VALUE v) +{ + RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v); +} + +static inline VALUE +RSTRUCT_GET(VALUE st, long k) +{ + return RSTRUCT_CONST_PTR(st)[k]; +} + +static inline const VALUE * +rb_struct_const_heap_ptr(VALUE st) +{ + /* TODO: check embed on debug mode */ + return RSTRUCT(st)->as.heap.ptr; +} + +#endif /* INTERNAL_STRUCT_H */ diff --git a/internal/symbol.h b/internal/symbol.h new file mode 100644 index 0000000000..4f041330f9 --- /dev/null +++ b/internal/symbol.h @@ -0,0 +1,41 @@ +#ifndef INTERNAL_SYMBOL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_SYMBOL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Symbol. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_encoding */ +#include "internal/compilers.h" /* for __has_builtin */ + +#ifdef rb_sym_intern_ascii_cstr +# undef rb_sym_intern_ascii_cstr +#endif + +/* symbol.c */ +VALUE rb_to_symbol_type(VALUE obj); +VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc); +VALUE rb_sym_intern_ascii(const char *ptr, long len); +VALUE rb_sym_intern_ascii_cstr(const char *ptr); +int rb_is_const_name(VALUE name); +int rb_is_class_name(VALUE name); +int rb_is_instance_name(VALUE name); +int rb_is_local_name(VALUE name); +PUREFUNC(int rb_is_const_sym(VALUE sym)); +PUREFUNC(int rb_is_attrset_sym(VALUE sym)); +ID rb_make_internal_id(void); +ID rb_make_temporary_id(size_t n); +void rb_gc_free_dsymbol(VALUE); + +#if __has_builtin(__builtin_constant_p) +#define rb_sym_intern_ascii_cstr(ptr) \ + (__builtin_constant_p(ptr) ? \ + rb_sym_intern_ascii((ptr), (long)strlen(ptr)) : \ + rb_sym_intern_ascii_cstr(ptr)) +#endif + +#endif /* INTERNAL_SYMBOL_H */ diff --git a/internal/thread.h b/internal/thread.h new file mode 100644 index 0000000000..c7fe16eb6b --- /dev/null +++ b/internal/thread.h @@ -0,0 +1,54 @@ +#ifndef INTERNAL_THREAD_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_THREAD_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Thread. + */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/intern.h" /* for rb_blocking_function_t */ + +struct rb_thread_struct; /* in vm_core.h */ + +/* thread.c */ +#define COVERAGE_INDEX_LINES 0 +#define COVERAGE_INDEX_BRANCHES 1 +#define COVERAGE_TARGET_LINES 1 +#define COVERAGE_TARGET_BRANCHES 2 +#define COVERAGE_TARGET_METHODS 4 +#define COVERAGE_TARGET_ONESHOT_LINES 8 + +VALUE rb_obj_is_mutex(VALUE obj); +VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg); +void rb_thread_execute_interrupts(VALUE th); +VALUE rb_get_coverages(void); +int rb_get_coverage_mode(void); +VALUE rb_default_coverage(int); +VALUE rb_thread_shield_new(void); +bool rb_thread_shield_owned(VALUE self); +VALUE rb_thread_shield_wait(VALUE self); +VALUE rb_thread_shield_release(VALUE self); +VALUE rb_thread_shield_destroy(VALUE self); +int rb_thread_to_be_killed(VALUE thread); +void rb_mutex_allow_trap(VALUE self, int val); +VALUE rb_uninterruptible(VALUE (*b_proc)(VALUE), VALUE data); +VALUE rb_mutex_owned_p(VALUE self); + +int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout); + +RUBY_SYMBOL_EXPORT_BEGIN +/* Temporary. This API will be removed (renamed). */ +VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd); + +/* thread.c (export) */ +int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */ +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +int rb_threadptr_execute_interrupts(struct rb_thread_struct *th, int blocking_timing); +MJIT_SYMBOL_EXPORT_END + +#endif /* INTERNAL_THREAD_H */ diff --git a/internal/time.h b/internal/time.h new file mode 100644 index 0000000000..a3bf0587ec --- /dev/null +++ b/internal/time.h @@ -0,0 +1,34 @@ +#ifndef INTERNAL_TIME_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_TIME_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Time. + */ +#include "ruby/internal/config.h" /* for SIGNEDNESS_OF_TIME_T */ +#include "internal/bits.h" /* for SIGNED_INTEGER_MAX */ +#include "ruby/ruby.h" /* for VALUE */ + +#if SIGNEDNESS_OF_TIME_T < 0 /* signed */ +# define TIMET_MAX SIGNED_INTEGER_MAX(time_t) +# define TIMET_MIN SIGNED_INTEGER_MIN(time_t) +#elif SIGNEDNESS_OF_TIME_T > 0 /* unsigned */ +# define TIMET_MAX UNSIGNED_INTEGER_MAX(time_t) +# define TIMET_MIN ((time_t)0) +#endif + +struct timeval; /* <- in <sys/time.h> or <winsock2.h> */ + +/* time.c */ +struct timeval rb_time_timeval(VALUE); + +RUBY_SYMBOL_EXPORT_BEGIN +/* time.c (export) */ +void ruby_reset_leap_second_info(void); +void ruby_reset_timezone(void); +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_TIME_H */ diff --git a/internal/transcode.h b/internal/transcode.h new file mode 100644 index 0000000000..9922332ea9 --- /dev/null +++ b/internal/transcode.h @@ -0,0 +1,20 @@ +#ifndef INTERNAL_TRANSCODE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_TRANSCODE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for Encoding::Converter. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "ruby/ruby.h" /* for VALUE */ +#include "ruby/encoding.h" /* for rb_econv_t */ + +/* transcode.c */ +extern VALUE rb_cEncodingConverter; +size_t rb_econv_memsize(rb_econv_t *); + +#endif /* INTERNAL_TRANSCODE_H */ diff --git a/internal/util.h b/internal/util.h new file mode 100644 index 0000000000..6eadbb9f94 --- /dev/null +++ b/internal/util.h @@ -0,0 +1,27 @@ +#ifndef INTERNAL_UTIL_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_UTIL_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header corresponding util.c. + * @warning DO NOT ADD RANDOM GARBAGE HERE THIS FILE IS FOR util.c + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> /* for ssize_t (note: on Windows ssize_t is */ +#endif /* `#define`d in ruby/config.h) */ + +/* util.c */ +char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve); +char *ruby_hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve); + +RUBY_SYMBOL_EXPORT_BEGIN +/* util.c (export) */ +RUBY_SYMBOL_EXPORT_END + +#endif /* INTERNAL_UTIL_H */ diff --git a/internal/variable.h b/internal/variable.h new file mode 100644 index 0000000000..4b67bef907 --- /dev/null +++ b/internal/variable.h @@ -0,0 +1,83 @@ +#ifndef INTERNAL_VARIABLE_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_VARIABLE_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for variables. + */ +#include "ruby/internal/config.h" +#include <stddef.h> /* for size_t */ +#include "constant.h" /* for rb_const_entry_t */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "ruby/ruby.h" /* for VALUE */ + +/* global variable */ + +#define ROBJECT_TRANSIENT_FLAG FL_USER13 + +/* variable.c */ +void rb_gc_mark_global_tbl(void); +void rb_gc_update_global_tbl(void); +size_t rb_generic_ivar_memsize(VALUE); +VALUE rb_search_class_path(VALUE); +VALUE rb_attr_delete(VALUE, ID); +VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef); +void rb_autoload_str(VALUE mod, ID id, VALUE file); +VALUE rb_autoload_at_p(VALUE, ID, int); +NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE)); +rb_gvar_getter_t *rb_gvar_getter_function_of(ID); +rb_gvar_setter_t *rb_gvar_setter_function_of(ID); +void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_); +void rb_gvar_ractor_local(const char *name); +static inline bool ROBJ_TRANSIENT_P(VALUE obj); +static inline void ROBJ_TRANSIENT_SET(VALUE obj); +static inline void ROBJ_TRANSIENT_UNSET(VALUE obj); +uint32_t rb_obj_ensure_iv_index_mapping(VALUE obj, ID id); + +RUBY_SYMBOL_EXPORT_BEGIN +/* variable.c (export) */ +void rb_mark_generic_ivar(VALUE); +void rb_mv_generic_ivar(VALUE src, VALUE dst); +VALUE rb_const_missing(VALUE klass, VALUE name); +int rb_class_ivar_set(VALUE klass, ID vid, VALUE value); +void rb_iv_tbl_copy(VALUE dst, VALUE src); +RUBY_SYMBOL_EXPORT_END + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_gvar_get(ID); +VALUE rb_gvar_set(ID, VALUE); +VALUE rb_gvar_defined(ID); +void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); +void rb_init_iv_list(VALUE obj); +MJIT_SYMBOL_EXPORT_END + +static inline bool +ROBJ_TRANSIENT_P(VALUE obj) +{ +#if USE_TRANSIENT_HEAP + return FL_TEST_RAW(obj, ROBJECT_TRANSIENT_FLAG); +#else + return false; +#endif +} + +static inline void +ROBJ_TRANSIENT_SET(VALUE obj) +{ +#if USE_TRANSIENT_HEAP + FL_SET_RAW(obj, ROBJECT_TRANSIENT_FLAG); +#endif +} + +static inline void +ROBJ_TRANSIENT_UNSET(VALUE obj) +{ +#if USE_TRANSIENT_HEAP + FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG); +#endif +} + +#endif /* INTERNAL_VARIABLE_H */ diff --git a/internal/vm.h b/internal/vm.h new file mode 100644 index 0000000000..bfb593176e --- /dev/null +++ b/internal/vm.h @@ -0,0 +1,133 @@ +#ifndef INTERNAL_VM_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_VM_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header for RubyVM. + */ +#include "ruby/internal/stdbool.h" /* for bool */ +#include "internal/serial.h" /* for rb_serial_t */ +#include "internal/static_assert.h" /* for STATIC_ASSERT */ +#include "ruby/ruby.h" /* for ID */ +#include "ruby/st.h" /* for st_table */ + +#ifdef rb_funcallv +# undef rb_funcallv +#endif + +#ifdef rb_method_basic_definition_p +# undef rb_method_basic_definition_p +#endif + +struct rb_callable_method_entry_struct; /* in method.h */ +struct rb_method_definition_struct; /* in method.h */ +struct rb_execution_context_struct; /* in vm_core.h */ +struct rb_control_frame_struct; /* in vm_core.h */ +struct rb_callinfo; /* in vm_core.h */ + +enum method_missing_reason { + MISSING_NOENTRY = 0x00, + MISSING_PRIVATE = 0x01, + MISSING_PROTECTED = 0x02, + MISSING_FCALL = 0x04, + MISSING_VCALL = 0x08, + MISSING_SUPER = 0x10, + MISSING_MISSING = 0x20, + MISSING_NONE = 0x40 +}; + +/* vm_insnhelper.h */ +rb_serial_t rb_next_class_serial(void); + +/* vm.c */ +VALUE rb_obj_is_thread(VALUE obj); +void rb_vm_mark(void *ptr); +void rb_vm_each_stack_value(void *ptr, void (*cb)(VALUE, void*), void *ctx); +PUREFUNC(VALUE rb_vm_top_self(void)); +void rb_vm_inc_const_missing_count(void); +const void **rb_vm_get_insns_address_table(void); +VALUE rb_source_location(int *pline); +const char *rb_source_location_cstr(int *pline); +MJIT_STATIC void rb_vm_pop_cfunc_frame(void); +int rb_vm_add_root_module(VALUE module); +void rb_vm_check_redefinition_by_prepend(VALUE klass); +int rb_vm_check_optimizable_mid(VALUE mid); +VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements); +MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE); +PUREFUNC(st_table *rb_vm_fstring_table(void)); + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE vm_exec(struct rb_execution_context_struct *, bool); /* used in JIT-ed code */ +MJIT_SYMBOL_EXPORT_END + +/* vm_eval.c */ +VALUE rb_current_realfilepath(void); +VALUE rb_check_block_call(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE); +typedef void rb_check_funcall_hook(int, VALUE, ID, int, const VALUE *, VALUE); +VALUE rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv, + rb_check_funcall_hook *hook, VALUE arg); +VALUE rb_check_funcall_with_hook_kw(VALUE recv, ID mid, int argc, const VALUE *argv, + rb_check_funcall_hook *hook, VALUE arg, int kw_splat); +const char *rb_type_str(enum ruby_value_type type); +VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE); +VALUE rb_check_funcall_basic_kw(VALUE, ID, VALUE, int, const VALUE*, int); +VALUE rb_yield_1(VALUE val); +VALUE rb_yield_force_blockarg(VALUE values); +VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, + rb_block_call_func_t bl_proc, int min_argc, int max_argc, + VALUE data2); +void rb_check_stack_overflow(void); + +/* vm_insnhelper.c */ +VALUE rb_equal_opt(VALUE obj1, VALUE obj2); +VALUE rb_eql_opt(VALUE obj1, VALUE obj2); + +struct rb_iseq_struct; +MJIT_SYMBOL_EXPORT_BEGIN +const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass); +MJIT_SYMBOL_EXPORT_END + +/* vm_method.c */ +struct rb_execution_context_struct; +MJIT_SYMBOL_EXPORT_BEGIN +int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv); +MJIT_SYMBOL_EXPORT_END + +/* vm_dump.c */ +void rb_print_backtrace(void); + +/* vm_backtrace.c */ +VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval); +VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval); +VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); +VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); +VALUE rb_make_backtrace(void); +void rb_backtrace_print_as_bugreport(void); +int rb_backtrace_p(VALUE obj); +VALUE rb_backtrace_to_str_ary(VALUE obj); +VALUE rb_backtrace_to_location_ary(VALUE obj); +void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output); +int rb_frame_info_p(VALUE obj); +int rb_get_node_id_from_frame_info(VALUE obj); +const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj); + +MJIT_SYMBOL_EXPORT_BEGIN +VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec); +void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self); +MJIT_SYMBOL_EXPORT_END + +#define RUBY_DTRACE_CREATE_HOOK(name, arg) \ + RUBY_DTRACE_HOOK(name##_CREATE, arg) +#define RUBY_DTRACE_HOOK(name, arg) \ +do { \ + if (UNLIKELY(RUBY_DTRACE_##name##_ENABLED())) { \ + int dtrace_line; \ + const char *dtrace_file = rb_source_location_cstr(&dtrace_line); \ + if (!dtrace_file) dtrace_file = ""; \ + RUBY_DTRACE_##name(arg, dtrace_file, dtrace_line); \ + } \ +} while (0) +#endif /* INTERNAL_VM_H */ diff --git a/internal/warnings.h b/internal/warnings.h new file mode 100644 index 0000000000..020212ebd8 --- /dev/null +++ b/internal/warnings.h @@ -0,0 +1,16 @@ +#ifndef INTERNAL_WARNINGS_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_WARNINGS_H +/** + * @author Ruby developers <ruby-core@ruby-lang.org> + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Internal header to suppress / mandate warnings. + */ +#include "ruby/internal/warning_push.h" +#define COMPILER_WARNING_PUSH RBIMPL_WARNING_PUSH() +#define COMPILER_WARNING_POP RBIMPL_WARNING_POP() +#define COMPILER_WARNING_ERROR(flag) RBIMPL_WARNING_ERROR(flag) +#define COMPILER_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag) +#endif /* INTERNAL_WARNINGS_H */ |
