diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/array.h | 3 | ||||
| -rw-r--r-- | internal/basic_operators.h | 1 | ||||
| -rw-r--r-- | internal/bignum.h | 41 | ||||
| -rw-r--r-- | internal/bits.h | 31 | ||||
| -rw-r--r-- | internal/box.h | 96 | ||||
| -rw-r--r-- | internal/class.h | 318 | ||||
| -rw-r--r-- | internal/compar.h | 1 | ||||
| -rw-r--r-- | internal/cont.h | 1 | ||||
| -rw-r--r-- | internal/encoding.h | 1 | ||||
| -rw-r--r-- | internal/error.h | 12 | ||||
| -rw-r--r-- | internal/eval.h | 2 | ||||
| -rw-r--r-- | internal/file.h | 2 | ||||
| -rw-r--r-- | internal/gc.h | 94 | ||||
| -rw-r--r-- | internal/hash.h | 18 | ||||
| -rw-r--r-- | internal/imemo.h | 148 | ||||
| -rw-r--r-- | internal/inits.h | 7 | ||||
| -rw-r--r-- | internal/io.h | 3 | ||||
| -rw-r--r-- | internal/load.h | 2 | ||||
| -rw-r--r-- | internal/namespace.h | 86 | ||||
| -rw-r--r-- | internal/numeric.h | 54 | ||||
| -rw-r--r-- | internal/object.h | 11 | ||||
| -rw-r--r-- | internal/range.h | 6 | ||||
| -rw-r--r-- | internal/rational.h | 23 | ||||
| -rw-r--r-- | internal/re.h | 53 | ||||
| -rw-r--r-- | internal/set_table.h | 15 | ||||
| -rw-r--r-- | internal/st.h | 11 | ||||
| -rw-r--r-- | internal/string.h | 36 | ||||
| -rw-r--r-- | internal/struct.h | 75 | ||||
| -rw-r--r-- | internal/symbol.h | 4 | ||||
| -rw-r--r-- | internal/thread.h | 6 | ||||
| -rw-r--r-- | internal/time.h | 7 | ||||
| -rw-r--r-- | internal/variable.h | 16 | ||||
| -rw-r--r-- | internal/vm.h | 8 |
33 files changed, 679 insertions, 513 deletions
diff --git a/internal/array.h b/internal/array.h index 398676df4a..a2cd06f2e3 100644 --- a/internal/array.h +++ b/internal/array.h @@ -37,6 +37,7 @@ size_t rb_ary_size_as_embedded(VALUE ary); void rb_ary_make_embedded(VALUE ary); bool rb_ary_embeddable_p(VALUE ary); VALUE rb_ary_diff(VALUE ary1, VALUE ary2); +VALUE rb_ary_compact_bang(VALUE ary); RUBY_EXTERN VALUE rb_cArray_empty_frozen; static inline VALUE rb_ary_entry_internal(VALUE ary, long offset); @@ -140,6 +141,8 @@ RARRAY_AREF(VALUE ary, long i) VALUE val; RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); + RUBY_ASSERT(i < RARRAY_LEN(ary)); + RBIMPL_WARNING_PUSH(); #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13 RBIMPL_WARNING_IGNORED(-Warray-bounds); diff --git a/internal/basic_operators.h b/internal/basic_operators.h index 5dc8d7fe8d..493d2fa7f7 100644 --- a/internal/basic_operators.h +++ b/internal/basic_operators.h @@ -24,6 +24,7 @@ enum ruby_basic_operators { BOP_SUCC, BOP_GT, BOP_GE, + BOP_GTGT, BOP_NOT, BOP_NEQ, BOP_MATCH, diff --git a/internal/bignum.h b/internal/bignum.h index 0ba21a4923..7389a17c74 100644 --- a/internal/bignum.h +++ b/internal/bignum.h @@ -9,6 +9,7 @@ * @brief Internal header for Bignums. */ #include "ruby/internal/config.h" /* for HAVE_LIBGMP */ +#include "internal/compilers.h" /* for FLEX_ARY_LEN */ #include <stddef.h> /* for size_t */ #ifdef HAVE_SYS_TYPES_H @@ -76,26 +77,17 @@ #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 + +/* This is likely more bits than we need today and will also need adjustment if + * we change GC slot sizes. + */ +#define BIGNUM_EMBED_LEN_NUMBITS 9 #define BIGNUM_EMBED_LEN_MASK \ - (~(~(VALUE)0U << BIGNUM_EMBED_LEN_NUMBITS) << BIGNUM_EMBED_LEN_SHIFT) + (RUBY_FL_USER11 | RUBY_FL_USER10 | RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | \ + RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3) #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, -}; +#define BIGNUM_EMBED_LEN_MAX (BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT) struct RBignum { struct RBasic basic; @@ -104,12 +96,18 @@ struct RBignum { size_t len; BDIGIT *digits; } heap; - BDIGIT ary[BIGNUM_EMBED_LEN_MAX]; + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + BDIGIT ary[1]; } as; }; /* bignum.c */ extern const char ruby_digitmap[]; +extern const char ruby_decimal_digit_pairs[]; double rb_big_fdiv_double(VALUE x, VALUE y); VALUE rb_big_uminus(VALUE x); VALUE rb_big_hash(VALUE); @@ -161,10 +159,15 @@ 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 +#if HAVE_LONG_LONG +VALUE rb_ull2big(unsigned LONG_LONG n); +VALUE rb_ll2big(LONG_LONG n); +#endif + #if defined(HAVE_INT128_T) +VALUE rb_uint128t2big(uint128_t n); VALUE rb_int128t2big(int128_t n); #endif diff --git a/internal/bits.h b/internal/bits.h index 2b5aecf112..698ab3e219 100644 --- a/internal/bits.h +++ b/internal/bits.h @@ -30,13 +30,13 @@ #include <stdint.h> /* for uintptr_t */ #include "internal/compilers.h" /* for MSC_VERSION_SINCE */ -#if MSC_VERSION_SINCE(1310) +#ifdef _MSC_VER # include <stdlib.h> /* for _byteswap_uint64 */ #endif #if defined(HAVE_X86INTRIN_H) # include <x86intrin.h> /* for _lzcnt_u64 */ -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) # include <intrin.h> /* for the following intrinsics */ #endif @@ -50,16 +50,13 @@ # pragma intrinsic(__lzcnt64) #endif -#if MSC_VERSION_SINCE(1310) +#if defined(_MSC_VER) # 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 @@ -266,7 +263,7 @@ ruby_swap16(uint16_t x) #if __has_builtin(__builtin_bswap16) return __builtin_bswap16(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ushort(x); #else @@ -281,7 +278,7 @@ ruby_swap32(uint32_t x) #if __has_builtin(__builtin_bswap32) return __builtin_bswap32(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ulong(x); #else @@ -298,7 +295,7 @@ ruby_swap64(uint64_t x) #if __has_builtin(__builtin_bswap64) return __builtin_bswap64(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_uint64(x); #else @@ -323,7 +320,7 @@ nlz_int32(uint32_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; @@ -352,7 +349,7 @@ nlz_int64(uint64_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u64(x); -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; @@ -538,7 +535,7 @@ ntz_int32(uint32_t x) #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) +#elif defined(_MSC_VER) /* :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; @@ -560,7 +557,7 @@ ntz_int64(uint64_t x) #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u64(x); -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) +#elif defined(_WIN64) && defined(_MSC_VER) unsigned long r; return _BitScanForward64(&r, x) ? (int)r : 64; @@ -608,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int 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) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotl(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotl64(v, n); #elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG) @@ -632,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int 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) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotr(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotr64(v, n); #elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG) diff --git a/internal/box.h b/internal/box.h new file mode 100644 index 0000000000..c717dc4e24 --- /dev/null +++ b/internal/box.h @@ -0,0 +1,96 @@ +#ifndef INTERNAL_BOX_H /*-*-C-*-vi:se ft=c:*/ +#define INTERNAL_BOX_H + +#include "ruby/ruby.h" /* for VALUE */ + +/** + * @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 Ruby Box. + */ +struct rb_box_struct { + /* + * To retrieve Ruby::Box object that provides #require and so on. + * That is used from load.c, etc., that uses rb_box_t internally. + */ + VALUE box_object; + long box_id; // box_id to generate ext filenames + + VALUE top_self; + + VALUE load_path; + VALUE load_path_snapshot; + VALUE load_path_check_cache; + VALUE expanded_load_path; + VALUE loaded_features; + VALUE loaded_features_snapshot; + VALUE loaded_features_realpaths; + VALUE loaded_features_realpath_map; + struct st_table *loaded_features_index; + struct st_table *loading_table; + VALUE ruby_dln_libmap; + + VALUE gvar_tbl; + struct st_table *classext_cow_classes; + + bool is_root; + bool is_user; + bool is_optional; +}; +typedef struct rb_box_struct rb_box_t; + +struct rb_box_gem_flags { + bool gem; + bool error_highlight; + bool did_you_mean; + bool syntax_suggest; +}; +typedef struct rb_box_gem_flags rb_box_gem_flags_t; + +#define BOX_OBJ_P(obj) (rb_obj_class(obj) == rb_cBox) + +#define BOX_MASTER_P(box) (box && !box->is_root && !box->is_user) +#define BOX_MUTABLE_P(box) (box && (box->is_root || box->is_user)) +#define BOX_ROOT_P(box) (box && box->is_root) +#define BOX_USER_P(box) (box && box->is_user) +#define BOX_OPTIONAL_P(box) (box && box->is_optional) +#define BOX_MAIN_P(box) (box && box->is_user && !box->is_optional) + +#define BOX_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL) +#define BOX_METHOD_ENTRY(me) (me ? BOX_METHOD_DEFINITION(me->def) : NULL) +#define BOX_CC(cc) (cc ? BOX_METHOD_ENTRY(cc->cme_) : NULL) +#define BOX_CC_ENTRIES(ccs) (ccs ? BOX_METHOD_ENTRY(ccs->cme) : NULL) + +RUBY_EXTERN bool ruby_box_enabled; +RUBY_EXTERN bool ruby_box_init_done; +RUBY_EXTERN bool ruby_box_crashed; + +static inline bool +rb_box_available(void) +{ + return ruby_box_enabled; +} + +const rb_box_t * rb_master_box(void); +const rb_box_t * rb_root_box(void); +const rb_box_t * rb_main_box(void); +const rb_box_t * rb_current_box(void); +const rb_box_t * rb_loading_box(void); +const rb_box_t * rb_current_box_in_crash_report(void); + +void rb_box_entry_mark(void *); +void rb_box_gc_update_references(void *ptr); + +rb_box_t * rb_get_box_t(VALUE ns); +VALUE rb_get_box_object(rb_box_t *ns); + +VALUE rb_box_local_extension(VALUE box, VALUE fname, VALUE path, VALUE *cleanup); +void rb_box_cleanup_local_extension(VALUE cleanup); + +void rb_initialize_mandatory_boxes(void); +void rb_box_init_done(void); +void rb_box_set_gem_flags(rb_box_gem_flags_t *); +#endif /* INTERNAL_BOX_H */ diff --git a/internal/class.h b/internal/class.h index 520994170f..0773dbad95 100644 --- a/internal/class.h +++ b/internal/class.h @@ -10,7 +10,7 @@ */ #include "id.h" #include "id_table.h" /* for struct rb_id_table */ -#include "internal/namespace.h" /* for rb_current_namespace */ +#include "internal/box.h" #include "internal/serial.h" /* for rb_serial_t */ #include "internal/static_assert.h" #include "internal/variable.h" /* for rb_class_ivar_set */ @@ -27,84 +27,30 @@ # undef RCLASS_SUPER #endif -struct rb_ns_subclasses { - long refcount; - struct st_table *tbl; -}; -typedef struct rb_ns_subclasses rb_ns_subclasses_t; - -static inline long -rb_ns_subclasses_ref_count(rb_ns_subclasses_t *ns_sub) -{ - return ns_sub->refcount; -} - -static inline rb_ns_subclasses_t * -rb_ns_subclasses_ref_inc(rb_ns_subclasses_t *ns_sub) -{ - ns_sub->refcount++; - return ns_sub; -} - -static inline void -rb_ns_subclasses_ref_dec(rb_ns_subclasses_t *ns_sub) -{ - ns_sub->refcount--; - if (ns_sub->refcount == 0) { - st_free_table(ns_sub->tbl); - xfree(ns_sub); - } -} - -struct rb_subclass_anchor { - rb_ns_subclasses_t *ns_subclasses; - struct rb_subclass_entry *head; -}; -typedef struct rb_subclass_anchor rb_subclass_anchor_t; - -struct rb_subclass_entry { - VALUE klass; - struct rb_subclass_entry *next; - struct rb_subclass_entry *prev; -}; -typedef struct rb_subclass_entry rb_subclass_entry_t; - struct rb_cvar_class_tbl_entry { + VALUE imemo_flags; uint32_t index; rb_serial_t global_cvar_state; - const rb_cref_t * cref; + const rb_cref_t *cref; VALUE class_value; }; struct rb_classext_struct { - const rb_namespace_t *ns; + const rb_box_t *box; VALUE super; VALUE fields_obj; // Fields are either ivar or other internal properties stored inline + VALUE classpath; struct rb_id_table *m_tbl; struct rb_id_table *const_tbl; struct rb_id_table *callable_m_tbl; - struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */ - struct rb_id_table *cvc_tbl; + VALUE cc_tbl; /* { ID => { cme, [cc1, cc2, ...] }, ... } */ + VALUE cvc_tbl; VALUE *superclasses; /** - * The head of subclasses is a blank (w/o klass) entry to be referred from anchor (and be never deleted). - * (anchor -> head -> 1st-entry) - */ - struct rb_subclass_anchor *subclasses; - /** - * The `ns_super_subclasses` points the `ns_subclasses` struct to retreive the subclasses - * of the super class in a specific namespace. - * In compaction GCs, collecting a classext should trigger the deletion of a rb_subclass_entry - * from the super's subclasses. But it may be prevented by the read barrier. - * Fetching the super's subclasses for a ns is to avoid the read barrier in that process. + * imemo_subclasses VALUE tracking this class's subclasses. + * Only used in prime classext. Lazily allocated on first subclass addition. */ - rb_ns_subclasses_t *ns_super_subclasses; - /** - * In the case that this is an `ICLASS`, `ns_module_subclasses` points to the link - * in the module's `subclasses` list that indicates that the klass has been - * included. Hopefully that makes sense. - */ - rb_ns_subclasses_t *ns_module_subclasses; + VALUE subclasses; const VALUE origin_; const VALUE refined_class; @@ -119,16 +65,15 @@ struct rb_classext_struct { const VALUE includer; } iclass; } as; - attr_index_t max_iv_count; uint16_t superclass_depth; - unsigned char variation_count; + attr_index_t max_iv_count; + uint8_t variation_count; bool permanent_classpath : 1; - bool cloned : 1; bool shared_const_tbl : 1; bool iclass_is_origin : 1; bool iclass_origin_shared_mtbl : 1; bool superclasses_with_self : 1; - VALUE classpath; + bool expect_no_ivar : 1; }; typedef struct rb_classext_struct rb_classext_t; @@ -138,7 +83,7 @@ struct RClass { struct RBasic basic; VALUE object_id; /* - * If ns_classext_tbl is NULL, then the prime classext is readable (because no other classext exists). + * If box_classext_tbl is NULL, then the prime classext is readable (because no other classext exists). * For the check whether writable or not, check flag RCLASS_PRIME_CLASSEXT_WRITABLE */ }; @@ -149,14 +94,14 @@ struct RClass_and_rb_classext_t { }; #if SIZEOF_VALUE >= SIZEOF_LONG_LONG -// Assert that classes can be embedded in heaps[2] (which has 160B slot size) +// Assert that classes can be embedded in heaps[3] (256B slot size on 64-bit). // On 32bit platforms there is no variable width allocation so it doesn't matter. -STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 4 * RVALUE_SIZE); +STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass_and_rb_classext_t) <= 256); #endif -struct RClass_namespaceable { +struct RClass_boxable { struct RClass_and_rb_classext_t base; - st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *) + st_table *box_classext_tbl; // box_object -> (rb_classext_t *) }; static const uint16_t RCLASS_MAX_SUPERCLASS_DEPTH = ((uint16_t)-1); @@ -170,13 +115,13 @@ static inline void RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE obj, bool writable); #define RCLASS_EXT_PRIME(c) (&((struct RClass_and_rb_classext_t*)(c))->classext) #define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext) -static inline rb_classext_t * RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns); +static inline rb_classext_t * RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box); static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj); -static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns); +static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box); static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj); // Raw accessor -#define RCLASSEXT_NS(ext) (ext->ns) +#define RCLASSEXT_BOX(ext) (ext->box) #define RCLASSEXT_SUPER(ext) (ext->super) #define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL) #define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj) @@ -188,14 +133,11 @@ static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj); #define RCLASSEXT_SUPERCLASS_DEPTH(ext) (ext->superclass_depth) #define RCLASSEXT_SUPERCLASSES(ext) (ext->superclasses) #define RCLASSEXT_SUBCLASSES(ext) (ext->subclasses) -#define RCLASSEXT_NS_SUPER_SUBCLASSES(ext) (ext->ns_super_subclasses) -#define RCLASSEXT_NS_MODULE_SUBCLASSES(ext) (ext->ns_module_subclasses) #define RCLASSEXT_ORIGIN(ext) (ext->origin_) #define RCLASSEXT_REFINED_CLASS(ext) (ext->refined_class) // class.allocator/singleton_class.attached_object are not accessed directly via RCLASSEXT_* #define RCLASSEXT_INCLUDER(ext) (ext->as.iclass.includer) #define RCLASSEXT_PERMANENT_CLASSPATH(ext) (ext->permanent_classpath) -#define RCLASSEXT_CLONED(ext) (ext->cloned) #define RCLASSEXT_SHARED_CONST_TBL(ext) (ext->shared_const_tbl) #define RCLASSEXT_ICLASS_IS_ORIGIN(ext) (ext->iclass_is_origin) #define RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) (ext->iclass_origin_shared_mtbl) @@ -206,7 +148,7 @@ static inline void RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE o static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer); /* Prime classext entry accessor for very specific reason */ -#define RCLASS_PRIME_NS(c) (RCLASS_EXT_PRIME(c)->ns) +#define RCLASS_PRIME_BOX(c) (RCLASS_EXT_PRIME(c)->box) // To invalidate CC by inserting&invalidating method entry into tables containing the target cme // See clear_method_cache_by_id_in_class() #define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj) @@ -218,7 +160,7 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE #define RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->callable_m_tbl != tbl) #define RCLASS_CC_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT_PRIME(c)->cc_tbl != tbl) -// Read accessor, regarding namespaces +// Read accessor, regarding box #define RCLASS_SUPER(c) (RCLASS_EXT_READABLE(c)->super) #define RCLASS_M_TBL(c) (RCLASS_EXT_READABLE(c)->m_tbl) #define RCLASS_CONST_TBL(c) (RCLASS_EXT_READABLE(c)->const_tbl) @@ -227,12 +169,10 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE * so always those should be writable. */ #define RCLASS_CVC_TBL(c) (RCLASS_EXT_READABLE(c)->cvc_tbl) -#define RCLASS_SUBCLASSES_X(c) (RCLASS_EXT_READABLE(c)->subclasses) -#define RCLASS_SUBCLASSES_FIRST(c) (RCLASS_EXT_READABLE(c)->subclasses->head->next) +#define RCLASS_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses) #define RCLASS_ORIGIN(c) (RCLASS_EXT_READABLE(c)->origin_) #define RICLASS_IS_ORIGIN_P(c) (RCLASS_EXT_READABLE(c)->iclass_is_origin) #define RCLASS_PERMANENT_CLASSPATH_P(c) (RCLASS_EXT_READABLE(c)->permanent_classpath) -#define RCLASS_CLONED_P(c) (RCLASS_EXT_READABLE(c)->cloned) #define RCLASS_CLASSPATH(c) (RCLASS_EXT_READABLE(c)->classpath) // Superclasses can't be changed after initialization @@ -240,12 +180,12 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE #define RCLASS_SUPERCLASSES(c) (RCLASS_EXT_PRIME(c)->superclasses) #define RCLASS_SUPERCLASSES_WITH_SELF_P(c) (RCLASS_EXT_PRIME(c)->superclasses_with_self) -// namespaces don't make changes on these refined_class/attached_object/includer +// Ruby Box doesn't make changes on these refined_class/attached_object/includer #define RCLASS_REFINED_CLASS(c) (RCLASS_EXT_PRIME(c)->refined_class) #define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT_PRIME(c)->as.singleton_class.attached_object) #define RCLASS_INCLUDER(c) (RCLASS_EXT_PRIME(c)->as.iclass.includer) -// max IV count and variation count are just hints, so they don't need to be per-namespace +// max IV count and variation count are just hints, so they don't need to be per-box #define RCLASS_MAX_IV_COUNT(ext) (RCLASS_EXT_PRIME(ext)->max_iv_count) #define RCLASS_VARIATION_COUNT(ext) (RCLASS_EXT_PRIME(ext)->variation_count) @@ -255,21 +195,20 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE #define RCLASS_WRITABLE_CALLABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->callable_m_tbl) #define RCLASS_WRITABLE_CC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cc_tbl) #define RCLASS_WRITABLE_CVC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cvc_tbl) -#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_WRITABLE(c)->subclasses) +// Subclasses are only in the prime classext (box-invariant) +#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_PRIME(c)->subclasses) static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super); static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super); static inline void RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared); static inline void RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared); static inline void RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table); -static inline void RCLASS_WRITE_CC_TBL(VALUE klass, struct rb_id_table *table); -static inline void RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table); -static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table); +static inline void RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table); +static inline void RCLASS_SET_CVC_TBL(VALUE klass, VALUE table); +static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table); static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool with_self); -static inline void RCLASS_SET_SUBCLASSES(VALUE klass, rb_subclass_anchor_t *anchor); -static inline void RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses); -static inline void RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses); +static inline void RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses); static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin); static inline void RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin); @@ -284,7 +223,6 @@ static inline VALUE RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_objec static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass); static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count); -static inline void RCLASS_SET_CLONED(VALUE klass, bool cloned); static inline void RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent); static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent); @@ -293,14 +231,16 @@ static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool per #define RCLASS_PRIME_CLASSEXT_WRITABLE FL_USER2 #define RCLASS_IS_INITIALIZED FL_USER3 // 3 is RMODULE_IS_REFINEMENT for RMODULE -#define RCLASS_NAMESPACEABLE FL_USER4 +#define RCLASS_BOXABLE FL_USER4 +#define RCLASS_ALLOCATOR_DEFINED FL_USER5 +#define RCLASS_HAS_SUBCLASSES FL_USER6 static inline st_table * RCLASS_CLASSEXT_TBL(VALUE klass) { - if (FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE)) { - struct RClass_namespaceable *ns_klass = (struct RClass_namespaceable *)klass; - return ns_klass->ns_classext_tbl; + if (FL_TEST_RAW(klass, RCLASS_BOXABLE)) { + struct RClass_boxable *box_klass = (struct RClass_boxable *)klass; + return box_klass->box_classext_tbl; } return NULL; } @@ -308,23 +248,25 @@ RCLASS_CLASSEXT_TBL(VALUE klass) static inline void RCLASS_SET_CLASSEXT_TBL(VALUE klass, st_table *tbl) { - RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE)); - struct RClass_namespaceable *ns_klass = (struct RClass_namespaceable *)klass; - ns_klass->ns_classext_tbl = tbl; + RUBY_ASSERT(FL_TEST_RAW(klass, RCLASS_BOXABLE)); + struct RClass_boxable *box_klass = (struct RClass_boxable *)klass; + box_klass->box_classext_tbl = tbl; } /* class.c */ -rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_namespace_t *ns); +rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_box_t *box); void rb_class_ensure_writable(VALUE obj); +void rb_class_set_box_classext(VALUE obj, const rb_box_t *box, rb_classext_t *ext); + static inline int -RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext) +RCLASS_SET_BOX_CLASSEXT(VALUE obj, const rb_box_t *box, rb_classext_t *ext) { int first_set = 0; st_table *tbl = RCLASS_CLASSEXT_TBL(obj); - VM_ASSERT(NAMESPACE_USER_P(ns)); // non-prime classext is only for user namespace, with ns_object - VM_ASSERT(ns->ns_object); - VM_ASSERT(RCLASSEXT_NS(ext) == ns); + VM_ASSERT(BOX_MUTABLE_P(box)); // Setting non-prime classext never happens on the master box + VM_ASSERT(box->box_object); + VM_ASSERT(RCLASSEXT_BOX(ext) == box); if (!tbl) { tbl = st_init_numtable_with_size(1); RCLASS_SET_CLASSEXT_TBL(obj, tbl); @@ -332,45 +274,53 @@ RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t if (rb_st_table_size(tbl) == 0) { first_set = 1; } - rb_st_insert(tbl, (st_data_t)ns->ns_object, (st_data_t)ext); + + rb_class_set_box_classext(obj, box, ext); + return first_set; } +#define VM_ASSERT_BOXABLE_TYPE(klass) \ + VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS), "%s is not boxable type", rb_type_str(BUILTIN_TYPE(klass))) + static inline bool RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE klass) { - VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)); + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); // if the lookup table exists, then it means the prime classext is NOT directly readable. - return !FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL; + return !FL_TEST_RAW(klass, RCLASS_BOXABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL; } static inline bool RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE klass) { - VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)); - return FL_TEST(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); + RBIMPL_ASSUME(klass != 0); + return FL_TEST_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); } static inline void RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE klass, bool writable) { - VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)); - + VM_ASSERT(klass != 0, "klass should be a valid object"); + VM_ASSERT_BOXABLE_TYPE(klass); if (writable) { - FL_SET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); + FL_SET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); } else { - FL_UNSET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); + FL_UNSET_RAW(klass, RCLASS_PRIME_CLASSEXT_WRITABLE); } } static inline rb_classext_t * -RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_namespace_t *ns) +RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_box_t *box) { st_data_t classext_ptr; st_table *classext_tbl = RCLASS_CLASSEXT_TBL(obj); if (classext_tbl) { - if (rb_st_lookup(classext_tbl, (st_data_t)ns->ns_object, &classext_ptr)) { + if (rb_st_lookup(classext_tbl, (st_data_t)box->box_object, &classext_ptr)) { return (rb_classext_t *)classext_ptr; } } @@ -378,9 +328,9 @@ RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_namespace_t *ns) } static inline rb_classext_t * -RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns) +RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_box_t *box) { - rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns); + rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); if (ext) return ext; // Classext for the ns not found. Refer the prime one instead. @@ -388,48 +338,48 @@ RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns) } static inline rb_classext_t * -RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns) +RCLASS_EXT_READABLE_IN_BOX(VALUE obj, const rb_box_t *box) { - if (!ns - || NAMESPACE_BUILTIN_P(ns) + if (BOX_MASTER_P(box) || RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) { return RCLASS_EXT_PRIME(obj); } - return RCLASS_EXT_READABLE_LOOKUP(obj, ns); + return RCLASS_EXT_READABLE_LOOKUP(obj, box); } static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj) { - const rb_namespace_t *ns; + const rb_box_t *box; if (RCLASS_PRIME_CLASSEXT_READABLE_P(obj)) { return RCLASS_EXT_PRIME(obj); } - // delay namespace loading to optimize for unmodified classes - ns = rb_current_namespace(); - if (!ns || NAMESPACE_BUILTIN_P(ns)) { + // delay determining the current box to optimize for unmodified classes + box = rb_current_box(); + if (BOX_MASTER_P(box)) { return RCLASS_EXT_PRIME(obj); } - return RCLASS_EXT_READABLE_LOOKUP(obj, ns); + return RCLASS_EXT_READABLE_LOOKUP(obj, box); } static inline rb_classext_t * -RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns) +RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_box_t *box) { rb_classext_t *ext; int first_set = 0; - ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns); + ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); if (ext) return ext; RB_VM_LOCKING() { // re-check the classext is not created to avoid the multi-thread race - ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns); + ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, box); if (!ext) { - ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, ns); - first_set = RCLASS_SET_NAMESPACE_CLASSEXT(obj, ns, ext); + ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, box); + first_set = RCLASS_SET_BOX_CLASSEXT(obj, box, ext); if (first_set) { + // TODO: are there any case that a class/module become non-writable after its birthtime? RCLASS_SET_PRIME_CLASSEXT_WRITABLE(obj, false); } } @@ -438,31 +388,28 @@ RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns) } static inline rb_classext_t * -RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns) +RCLASS_EXT_WRITABLE_IN_BOX(VALUE obj, const rb_box_t *box) { - if (!ns - || NAMESPACE_BUILTIN_P(ns) + if (BOX_MASTER_P(box) || RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj)) { return RCLASS_EXT_PRIME(obj); } - return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns); + return RCLASS_EXT_WRITABLE_LOOKUP(obj, box); } static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj) { - const rb_namespace_t *ns; + const rb_box_t *box; if (LIKELY(RCLASS_PRIME_CLASSEXT_WRITABLE_P(obj))) { return RCLASS_EXT_PRIME(obj); } - // delay namespace loading to optimize for unmodified classes - ns = rb_current_namespace(); - if (!ns || NAMESPACE_BUILTIN_P(ns)) { - // If no namespace is specified, Ruby VM is in bootstrap - // and the clean class definition is under construction. + // delay determining the current box to optimize for unmodified classes + box = rb_current_box(); + if (BOX_MASTER_P(box)) { return RCLASS_EXT_PRIME(obj); } - return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns); + return RCLASS_EXT_WRITABLE_LOOKUP(obj, box); } static inline void @@ -479,18 +426,11 @@ RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer) } /* class.c */ -typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE namespace, void *arg); +typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE box_value, void *arg); void rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg); void rb_class_subclass_add(VALUE super, VALUE klass); -void rb_class_remove_from_super_subclasses(VALUE); -void rb_class_remove_from_module_subclasses(VALUE); -void rb_class_classext_free_subclasses(rb_classext_t *, 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_update_superclasses(VALUE); -size_t rb_class_superclasses_memsize(VALUE); -void rb_class_remove_subclass_head(VALUE); int rb_singleton_class_internal_p(VALUE sklass); VALUE rb_class_set_super(VALUE klass, VALUE super); VALUE rb_class_boot(VALUE); @@ -513,6 +453,10 @@ void rb_undef_methods_from(VALUE klass, VALUE super); VALUE rb_class_inherited(VALUE, VALUE); VALUE rb_keyword_error_new(const char *, VALUE); +rb_classext_t *rb_class_unlink_classext(VALUE klass, const rb_box_t *box); +void rb_class_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); +void rb_iclass_classext_free(VALUE klass, rb_classext_t *ext, bool is_prime); + RUBY_SYMBOL_EXPORT_BEGIN /* for objspace */ @@ -525,7 +469,8 @@ RUBY_SYMBOL_EXPORT_END static inline bool RCLASS_SINGLETON_P(VALUE klass) { - return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON); + RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS)); + return RB_BUILTIN_TYPE(klass) == T_CLASS && FL_TEST_RAW(klass, FL_SINGLETON); } static inline void @@ -546,7 +491,7 @@ RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj) RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj); if (!ext->fields_obj) { - RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(rb_singleton_class(obj), 1)); + RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, ROOT_SHAPE_ID, true)); } return ext->fields_obj; } @@ -581,7 +526,7 @@ RCLASS_FIELDS_COUNT(VALUE obj) VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); if (fields_obj) { - if (rb_shape_obj_too_complex_p(fields_obj)) { + if (rb_obj_shape_complex_p(fields_obj)) { return (uint32_t)rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj)); } else { @@ -628,21 +573,21 @@ RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table) } static inline void -RCLASS_WRITE_CC_TBL(VALUE klass, struct rb_id_table *table) +RCLASS_WRITE_CC_TBL(VALUE klass, VALUE table) { - RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)) = table; + RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), table); } static inline void -RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table) +RCLASS_SET_CVC_TBL(VALUE klass, VALUE table) { - RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)) = table; + RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_PRIME(klass)), table); } static inline void -RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table) +RCLASS_WRITE_CVC_TBL(VALUE klass, VALUE table) { - RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)) = table; + RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)), table); } static inline void @@ -654,10 +599,8 @@ RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined) static inline rb_alloc_func_t RCLASS_ALLOCATOR(VALUE klass) { - RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS)); - if (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS)) { - return 0; - } + RBIMPL_ASSERT_TYPE(klass, T_CLASS); + RUBY_ASSERT(!RCLASS_SINGLETON_P(klass)); return RCLASS_EXT_PRIME(klass)->as.class.allocator; } @@ -704,6 +647,14 @@ RICLASS_OWNS_M_TBL_P(VALUE iclass) return RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext); } +static inline bool +RICLASS_FOR_REFINEMENT_P(VALUE iclass) +{ + return BUILTIN_TYPE(iclass) == T_ICLASS && + RB_TYPE_P(RBASIC(iclass)->klass, T_MODULE) && + FL_TEST_RAW(RBASIC(iclass)->klass, RMODULE_IS_REFINEMENT); +} + static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass) { @@ -723,28 +674,10 @@ RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool w } static inline void -RCLASS_SET_SUBCLASSES(VALUE klass, struct rb_subclass_anchor *anchor) +RCLASS_SET_SUBCLASSES(VALUE klass, VALUE subclasses) { rb_classext_t *ext = RCLASS_EXT_PRIME(klass); - RCLASSEXT_SUBCLASSES(ext) = anchor; -} - -static inline void -RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses) -{ - rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); - if (RCLASSEXT_NS_SUPER_SUBCLASSES(ext)) - rb_ns_subclasses_ref_dec(RCLASSEXT_NS_SUPER_SUBCLASSES(ext)); - RCLASSEXT_NS_SUPER_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses); -} - -static inline void -RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses) -{ - rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); - if (RCLASSEXT_NS_MODULE_SUBCLASSES(ext)) - rb_ns_subclasses_ref_dec(RCLASSEXT_NS_MODULE_SUBCLASSES(ext)); - RCLASSEXT_NS_MODULE_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses); + RB_OBJ_WRITE(klass, &RCLASSEXT_SUBCLASSES(ext), subclasses); } static inline void @@ -753,6 +686,7 @@ RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) rb_classext_t *ext = RCLASS_EXT_READABLE(klass); assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; @@ -764,6 +698,7 @@ RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass); assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); + assert(!RB_FL_ABLE(classpath) || FL_TEST_RAW(classpath, RUBY_FL_SHAREABLE)); RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath); RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent; @@ -781,13 +716,22 @@ RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object) static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count) { + RUBY_ASSERT(klass != rb_cObject); + RUBY_ASSERT(klass != rb_cBasicObject); + RCLASS_MAX_IV_COUNT(klass) = count; } static inline void -RCLASS_SET_CLONED(VALUE klass, bool cloned) +RCLASS_SET_EXPECT_NO_IVAR(VALUE klass) +{ + RCLASS_EXT_PRIME(klass)->expect_no_ivar = true; +} + +static inline bool +RCLASS_EXPECT_NO_IVAR(VALUE klass) { - RCLASSEXT_CLONED(RCLASS_EXT_PRIME(klass)) = cloned; + return RCLASS_EXT_PRIME(klass)->expect_no_ivar; } static inline bool diff --git a/internal/compar.h b/internal/compar.h index 9115e4bd63..5eb5e8714e 100644 --- a/internal/compar.h +++ b/internal/compar.h @@ -25,5 +25,6 @@ /* compar.c */ VALUE rb_invcmp(VALUE, VALUE); +NORETURN(void rb_cmperr_reason(VALUE, VALUE, const char*)); #endif /* INTERNAL_COMPAR_H */ diff --git a/internal/cont.h b/internal/cont.h index 3c2528a02a..dcf6f820a3 100644 --- a/internal/cont.h +++ b/internal/cont.h @@ -31,5 +31,4 @@ VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber); unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber); struct rb_execution_context_struct * rb_fiberptr_get_ec(struct rb_fiber_struct *fiber); - #endif /* INTERNAL_CONT_H */ diff --git a/internal/encoding.h b/internal/encoding.h index c2ffaf4514..38bf8fc9da 100644 --- a/internal/encoding.h +++ b/internal/encoding.h @@ -29,6 +29,7 @@ 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_enc_raw_set(VALUE obj, rb_encoding *enc); +int rb_enc_registered(const char *name); PUREFUNC(int rb_data_is_encoding(VALUE obj)); diff --git a/internal/error.h b/internal/error.h index de189698b8..fead2aee95 100644 --- a/internal/error.h +++ b/internal/error.h @@ -75,11 +75,11 @@ PRINTF_ARGS(void rb_warn_deprecated_to_remove(const char *removal, const char *f PRINTF_ARGS(void rb_warn_reserved_name(const char *removal, const char *fmt, ...), 2, 3); #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) +# 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) +# elif RBIMPL_COMPILER_IS(MSVC) # define RBIMPL_TODO0(x) __pragma(message(x)) # endif @@ -186,6 +186,9 @@ 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 void rb_bug_without_die(const char *fmt, ...); +NORETURN(void rb_no_implicit_conversion(VALUE val, const char *tname)); +NORETURN(void rb_cant_convert(VALUE val, const char *tname)); +NORETURN(void rb_cant_convert_invalid_return(VALUE val, const char *tname, const char *method_name, VALUE ret)); RUBY_SYMBOL_EXPORT_BEGIN /* error.c (export) */ @@ -235,10 +238,11 @@ rb_key_err_raise(VALUE mesg, VALUE recv, VALUE name) rb_exc_raise(exc); } +RBIMPL_ATTR_NONNULL((2)) 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); + return rbimpl_obj_typeddata_p(obj) && (RTYPEDDATA_TYPE(obj) == data_type); } typedef enum { diff --git a/internal/eval.h b/internal/eval.h index 4c1c045b4e..17ade0a7f1 100644 --- a/internal/eval.h +++ b/internal/eval.h @@ -11,6 +11,7 @@ * header (related to this file, but not the same role). */ #include "ruby/ruby.h" /* for ID */ +#include "vm_core.h" /* for ID */ #define id_signo ruby_static_id_signo #define id_status ruby_static_id_status @@ -30,6 +31,7 @@ VALUE rb_exception_setup(int argc, VALUE *argv); void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass); void rb_vm_using_module(VALUE module); VALUE rb_top_main_class(const char *method); +VALUE rb_ec_ensure(rb_execution_context_t *ec, VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2); /* eval_error.c */ VALUE rb_get_backtrace(VALUE info); diff --git a/internal/file.h b/internal/file.h index 9c192ff4d1..1aa4c67043 100644 --- a/internal/file.h +++ b/internal/file.h @@ -23,7 +23,9 @@ 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); +VALUE rb_get_path_check_no_convert(VALUE); int ruby_is_fd_loadable(int fd); +char *rb_enc_path_skip_prefix_root(const char *path, const char *end, rb_encoding *enc); RUBY_SYMBOL_EXPORT_BEGIN /* file.c (export) */ diff --git a/internal/gc.h b/internal/gc.h index f0dc04fc58..e21fb89267 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -83,8 +83,6 @@ rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr) #define RUBY_GC_INFO if(0)printf #endif -#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;} - #if STACK_GROW_DIRECTION > 0 # define STACK_UPPER(x, a, b) (a) #elif STACK_GROW_DIRECTION < 0 @@ -122,10 +120,11 @@ const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj) struct rb_execution_context_struct; /* in vm_core.h */ struct rb_objspace; /* in vm_core.h */ -#define NEWOBJ_OF(var, T, c, f, s, ec) \ - T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \ - rb_wb_protected_newobj_of((ec ? ec : GET_EC()), (c), (f) & ~FL_WB_PROTECTED, s) : \ - rb_wb_unprotected_newobj_of((c), (f), s)) +#define EC_NEWOBJ_OF(var, T, c, f, s, ec) \ + T *(var) = (T *)rb_ec_newobj_of((ec), (c), (f), s) +#define NEWOBJ_OF(var, T, c, f, s) EC_NEWOBJ_OF(var, T, c, f, s, GET_EC()) +#define UNPROTECTED_NEWOBJ_OF(var, T, c, f, s) \ + T *(var) = (T *)rb_newobj((GET_EC()), (c), (f), ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER, false, s) #ifndef RB_GC_OBJECT_METADATA_ENTRY_DEFINED # define RB_GC_OBJECT_METADATA_ENTRY_DEFINED @@ -198,10 +197,9 @@ RUBY_ATTR_MALLOC void *rb_xcalloc_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); void rb_gc_obj_id_moved(VALUE obj); +void rb_gc_register_pinning_obj(VALUE obj); +rb_execution_context_t *rb_gc_get_ec(void); void *rb_gc_ractor_cache_alloc(rb_ractor_t *ractor); void rb_gc_ractor_cache_free(void *cache); @@ -212,9 +210,6 @@ size_t rb_gc_heap_id_for_size(size_t size); void rb_gc_mark_and_move(VALUE *ptr); -void rb_gc_mark_weak(VALUE *ptr); -void rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr); - void rb_gc_ref_update_table_values_only(st_table *tbl); void rb_gc_initial_stress_set(VALUE flag); @@ -235,6 +230,8 @@ void rb_objspace_reachable_objects_from_root(void (func)(const char *category, V int rb_objspace_internal_object_p(VALUE obj); int rb_objspace_garbage_object_p(VALUE obj); bool rb_gc_pointer_to_heap_p(VALUE obj); +void rb_gc_declare_weak_references(VALUE obj); +bool rb_gc_handle_weak_references_alive_p(VALUE obj); void rb_objspace_each_objects( int (*callback)(void *start, void *end, size_t stride, void *data), @@ -248,19 +245,21 @@ VALUE rb_gc_disable_no_rest(void); /* gc.c (export) */ const char *rb_objspace_data_type_name(VALUE obj); -VALUE rb_wb_protected_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t); -VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, size_t); +VALUE rb_newobj(struct rb_execution_context_struct *, VALUE, VALUE, uint32_t /* shape_id_t */, bool, size_t); +VALUE rb_newobj_of(VALUE, VALUE, size_t); +VALUE rb_ec_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t); size_t rb_obj_memsize_of(VALUE); struct rb_gc_object_metadata_entry *rb_gc_object_metadata(VALUE obj); void rb_gc_mark_values(long n, const VALUE *values); void rb_gc_mark_vm_stack_values(long n, const VALUE *values); void rb_gc_update_values(long n, 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); +void rb_gc_mark_set_no_pin(st_table *); +void rb_gc_update_set_refs(st_table *); +#if USE_MODULAR_GC const char *rb_gc_active_gc_name(void); int rb_gc_modular_gc_loaded_p(void); +#endif RUBY_SYMBOL_EXPORT_END @@ -289,66 +288,19 @@ void rb_gc_writebarrier_remember(VALUE obj); const char *rb_obj_info(VALUE obj); void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name); -#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) - -static inline void * -ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count) -{ - return ruby_xrealloc2(ptr, new_count, element_size); -} - -#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))) + ((v) = (T *)ruby_xrealloc2_sized((void *)(v), (m), sizeof(T), (n))) + +# define SIZED_FREE(v) ruby_xfree_sized((void *)(v), sizeof(*(v))) +# define SIZED_FREE_N(v, n) ruby_xfree_sized((void *)(v), sizeof(*(v)) * (n)) static inline void * ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count) { - return ruby_sized_xrealloc2(ptr, new_count, element_size, old_count); + return ruby_xrealloc2_sized(ptr, new_count, element_size, old_count); } -#endif /* HAVE_MALLOC_USABLE_SIZE */ +void rb_gc_verify_shareable(VALUE); +bool rb_gc_checking_shareable(void); -#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 index 03cd830506..0386a5009c 100644 --- a/internal/hash.h +++ b/internal/hash.h @@ -70,7 +70,6 @@ struct RHash { #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(VALUE hash, VALUE ifnone); VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); @@ -88,6 +87,7 @@ 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); bool rb_hash_default_unredefined(VALUE hash); +VALUE rb_hash_alloc_fixed_size(VALUE klass, st_index_t size); VALUE rb_ident_hash_new_with_size(st_index_t size); void rb_hash_free(VALUE hash); RUBY_EXTERN VALUE rb_cHash_empty_frozen; @@ -111,6 +111,7 @@ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t RUBY_SYMBOL_EXPORT_END VALUE rb_hash_new_with_size(st_index_t size); +VALUE rb_hash_new_with_bulk_insert(long argc, const VALUE *argv); 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); @@ -191,4 +192,19 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h) return (unsigned)ret; } +#define RHASH_AR_TABLE_BOUND_RAW(h) \ + ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \ + (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT))) + +#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type) + +static inline unsigned int +RHASH_AR_TABLE_BOUND(VALUE h) +{ + RUBY_ASSERT(RHASH_AR_TABLE_P(h)); + const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h); + RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE); + return bound; +} + #endif /* INTERNAL_HASH_H */ diff --git a/internal/imemo.h b/internal/imemo.h index 0ad00fe6b7..e8a5f0fc8e 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -37,10 +37,13 @@ enum imemo_type { imemo_ment = 6, imemo_iseq = 7, imemo_tmpbuf = 8, + imemo_cvar_entry = 9, imemo_callinfo = 10, imemo_callcache = 11, imemo_constcache = 12, - imemo_fields = 13, + imemo_fields = 13, + imemo_subclasses = 14, + imemo_cdhash = 15, }; /* CREF (Class REFerence) is defined in method.h */ @@ -57,7 +60,6 @@ struct vm_svar { /*! 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; @@ -93,30 +95,36 @@ struct vm_ifunc { 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 */ + size_t size; /* buffer size in bytes */ }; +struct rb_imemo_cdhash { + VALUE flags; + st_table tbl; +}; + +/* Set on imemo_memo when u3 holds a VALUE that GC must mark. + * When unset, u3 is a non-VALUE (cnt/state). */ +#define MEMO_U3_IS_VALUE IMEMO_FL_USER0 + /*! 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; }; -#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T))) +#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false)) +#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true)) /* ment is in method.h */ @@ -133,40 +141,27 @@ struct MEMO { #ifndef RUBY_RUBYPARSER_H typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t; #endif -rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt); +VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable); +VALUE rb_imemo_tmpbuf_new(void); +struct MEMO *rb_imemo_memo_new(VALUE a, VALUE b, long c); +struct MEMO *rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c); struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc); 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); size_t rb_imemo_memsize(VALUE obj); void rb_imemo_mark_and_move(VALUE obj, bool reference_updating); -void rb_cc_tbl_free(struct rb_id_table *cc_tbl, VALUE klass); void rb_imemo_free(VALUE obj); RUBY_SYMBOL_EXPORT_BEGIN -VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size); const char *rb_imemo_name(enum imemo_type type); RUBY_SYMBOL_EXPORT_END -static inline struct MEMO * -MEMO_NEW(VALUE a, VALUE b, VALUE c) -{ - struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0); - *((VALUE *)&memo->v1) = a; - *((VALUE *)&memo->v2) = b; - *((VALUE *)&memo->u3.value) = c; - - return memo; -} - static inline enum imemo_type imemo_type(VALUE imemo) { @@ -202,12 +197,6 @@ 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, sizeof(rb_imemo_tmpbuf_t)); -} - static inline void * RB_IMEMO_TMPBUF_PTR(VALUE v) { @@ -215,30 +204,16 @@ RB_IMEMO_TMPBUF_PTR(VALUE 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) +rb_imemo_tmpbuf_new_from_an_RString(VALUE str) { - const void *src; VALUE imemo; - rb_imemo_tmpbuf_t *tmpbuf; - void *dst; size_t len; StringValue(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; + rb_alloc_tmp_buffer(&imemo, len); + memcpy(RB_IMEMO_TMPBUF_PTR(imemo), RSTRING_PTR(str), len); return imemo; } @@ -254,6 +229,15 @@ MEMO_V2_SET(struct MEMO *m, VALUE v) RB_OBJ_WRITE(m, &m->v2, v); } +VALUE rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type); + +static inline st_table * +rb_imemo_cdhash_tbl(VALUE obj) +{ + RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_cdhash)); + return &((struct rb_imemo_cdhash *)obj)->tbl; +} + struct rb_fields { struct RBasic basic; union { @@ -271,42 +255,82 @@ struct rb_fields { } as; }; -#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0 +// IMEMO/fields and T_OBJECT have exactly the same layout. +// This is useful for JIT and common codepaths. +#define OBJ_FIELD_HEAP ROBJECT_HEAP +STATIC_ASSERT(imemo_fields_flags, OBJ_FIELD_HEAP == IMEMO_FL_USER0); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields)); +STATIC_ASSERT(imemo_fields_external_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.external.ptr)); +STATIC_ASSERT(imemo_fields_complex_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.complex.table)); + #define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields) -VALUE rb_imemo_fields_new(VALUE klass, size_t capa); -VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa); -VALUE rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl); +#define IMEMO_SUBCLASSES_HEAP IMEMO_FL_USER0 + +struct rb_subclasses { + VALUE flags; + uint32_t count; + uint32_t capacity; + union { + VALUE *external; + VALUE embed[1]; + } as; +}; + +static inline VALUE * +rb_imemo_subclasses_entries(VALUE v) +{ + struct rb_subclasses *s = (struct rb_subclasses *)v; + return FL_TEST_RAW(v, IMEMO_SUBCLASSES_HEAP) ? s->as.external : s->as.embed; +} + +VALUE rb_imemo_fields_new(VALUE owner, /* shape_id_t */ uint32_t shape_id, bool shareable); +VALUE rb_imemo_subclasses_new(uint32_t capacity); +VALUE rb_imemo_fields_new_complex(VALUE owner, /* shape_id_t */ uint32_t shape_id, size_t capa, bool shareable); +VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, /* shape_id_t */ uint32_t shape_id, st_table *tbl, bool shareable); VALUE rb_imemo_fields_clone(VALUE fields_obj); void rb_imemo_fields_clear(VALUE fields_obj); +static inline VALUE +rb_imemo_fields_owner(VALUE fields_obj) +{ + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields)); + + return CLASS_OF(fields_obj); +} + static inline VALUE * -rb_imemo_fields_ptr(VALUE obj_fields) +rb_imemo_fields_ptr(VALUE fields_obj) { - if (!obj_fields) { + if (!fields_obj) { return NULL; } - RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields)); + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); - if (RB_UNLIKELY(FL_TEST_RAW(obj_fields, OBJ_FIELD_EXTERNAL))) { - return IMEMO_OBJ_FIELDS(obj_fields)->as.external.ptr; + if (UNLIKELY(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP))) { + return IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr; } else { - return IMEMO_OBJ_FIELDS(obj_fields)->as.embed.fields; + return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields; } } static inline st_table * -rb_imemo_fields_complex_tbl(VALUE obj_fields) +rb_imemo_fields_complex_tbl(VALUE fields_obj) { - if (!obj_fields) { + if (!fields_obj) { return NULL; } - RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields)); + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); + RUBY_ASSERT(FL_TEST_RAW(fields_obj, OBJ_FIELD_HEAP)); + + // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the + // shape is complex. + RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table); - return IMEMO_OBJ_FIELDS(obj_fields)->as.complex.table; + return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table; } #endif /* INTERNAL_IMEMO_H */ diff --git a/internal/inits.h b/internal/inits.h index e618d87cc3..be73dac1dc 100644 --- a/internal/inits.h +++ b/internal/inits.h @@ -9,6 +9,10 @@ * @brief Internal header aggregating init functions. */ +/* box.c */ +void Init_enable_box(void); +void Init_master_box(void); + /* class.c */ void Init_class_hierarchy(void); @@ -25,9 +29,6 @@ int Init_enc_set_filesystem_encoding(void); /* newline.c */ void Init_newline(void); -/* namespace.c */ -void Init_enable_namespace(void); - /* vm.c */ void Init_BareVM(void); void Init_vm_objects(void); diff --git a/internal/io.h b/internal/io.h index e6a741ee71..2110f0b087 100644 --- a/internal/io.h +++ b/internal/io.h @@ -132,7 +132,7 @@ struct rb_io { struct rb_execution_context_struct *closing_ec; VALUE wakeup_mutex; - // The fork generation of the the blocking operations list. + // The fork generation of the blocking operations list. rb_serial_t fork_generation; }; @@ -149,6 +149,7 @@ VALUE rb_io_prep_stdout(void); VALUE rb_io_prep_stderr(void); int rb_io_notify_close(struct rb_io *fptr); +bool rb_io_fptr_finalize_closed(struct rb_io *fptr); RUBY_SYMBOL_EXPORT_BEGIN /* io.c (export) */ diff --git a/internal/load.h b/internal/load.h index fb880a43ba..6cffe0ce64 100644 --- a/internal/load.h +++ b/internal/load.h @@ -12,7 +12,7 @@ /* load.c */ VALUE rb_get_expanded_load_path(void); -VALUE rb_load_entrypoint(VALUE args); +VALUE rb_load_entrypoint(VALUE fname, VALUE wrap); VALUE rb_require_relative_entrypoint(VALUE fname); int rb_require_internal(VALUE fname); NORETURN(void rb_load_fail(VALUE, const char*)); diff --git a/internal/namespace.h b/internal/namespace.h deleted file mode 100644 index 4cdfbc305f..0000000000 --- a/internal/namespace.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef INTERNAL_NAMESPACE_H /*-*-C-*-vi:se ft=c:*/ -#define INTERNAL_NAMESPACE_H - -#include "ruby/ruby.h" /* for VALUE */ - -/** - * @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 Namespace. - */ -struct rb_namespace_struct { - /* - * To retrieve Namespace object that provides #require and so on. - * That is used from load.c, etc., that uses rb_namespace_t internally. - */ - VALUE ns_object; - long ns_id; // namespace id to generate ext filenames - - VALUE top_self; - - VALUE load_path; - VALUE load_path_snapshot; - VALUE load_path_check_cache; - VALUE expanded_load_path; - VALUE loaded_features; - VALUE loaded_features_snapshot; - VALUE loaded_features_realpaths; - VALUE loaded_features_realpath_map; - struct st_table *loaded_features_index; - struct st_table *loading_table; - VALUE ruby_dln_libmap; - - VALUE gvar_tbl; - - bool is_builtin; - bool is_user; - bool is_optional; -}; -typedef struct rb_namespace_struct rb_namespace_t; - -#define NAMESPACE_BUILTIN_P(ns) (ns && ns->is_builtin) -#define NAMESPACE_USER_P(ns) (ns && ns->is_user) -#define NAMESPACE_OPTIONAL_P(ns) (ns && ns->is_optional) -#define NAMESPACE_MAIN_P(ns) (ns && ns->is_user && !ns->is_optional) - -#define NAMESPACE_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL) -#define NAMESPACE_METHOD_ENTRY(me) (me ? NAMESPACE_METHOD_DEFINITION(me->def) : NULL) -#define NAMESPACE_CC(cc) (cc ? NAMESPACE_METHOD_ENTRY(cc->cme_) : NULL) -#define NAMESPACE_CC_ENTRIES(ccs) (ccs ? NAMESPACE_METHOD_ENTRY(ccs->cme) : NULL) - -RUBY_EXTERN bool ruby_namespace_enabled; -RUBY_EXTERN bool ruby_namespace_init_done; - -static inline bool -rb_namespace_available(void) -{ - return ruby_namespace_enabled; -} - -void rb_namespace_enable_builtin(void); -void rb_namespace_disable_builtin(void); -void rb_namespace_push_loading_namespace(const rb_namespace_t *); -void rb_namespace_pop_loading_namespace(const rb_namespace_t *); -rb_namespace_t * rb_root_namespace(void); -const rb_namespace_t *rb_builtin_namespace(void); -rb_namespace_t * rb_main_namespace(void); -const rb_namespace_t * rb_definition_namespace(void); -const rb_namespace_t * rb_loading_namespace(void); -const rb_namespace_t * rb_current_namespace(void); -VALUE rb_current_namespace_details(VALUE); - -void rb_namespace_entry_mark(void *); - -rb_namespace_t * rb_get_namespace_t(VALUE ns); -VALUE rb_get_namespace_object(rb_namespace_t *ns); -typedef VALUE namespace_exec_func(VALUE arg); -VALUE rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg); - -VALUE rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path); - -void rb_initialize_main_namespace(void); -void rb_namespace_init_done(void); -#endif /* INTERNAL_NAMESPACE_H */ diff --git a/internal/numeric.h b/internal/numeric.h index 58f42f41ac..a24432df1e 100644 --- a/internal/numeric.h +++ b/internal/numeric.h @@ -10,9 +10,9 @@ */ #include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */ #include "internal/bits.h" /* for RUBY_BIT_ROTL */ +#include "internal/compar.h" /* for rb_cmperr_reason */ #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) \ @@ -70,6 +70,7 @@ 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_flo_to_i(VALUE num); VALUE rb_int_idiv(VALUE x, VALUE y); VALUE rb_int_modulo(VALUE x, VALUE y); VALUE rb_int2str(VALUE num, int base); @@ -78,6 +79,7 @@ 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); +VALUE rb_int_fdiv(VALUE x, VALUE y); 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); @@ -127,6 +129,54 @@ VALUE rb_int_bit_length(VALUE num); VALUE rb_int_uminus(VALUE num); VALUE rb_int_comp(VALUE num); +// Unified 128-bit integer structures that work with or without native support: +union rb_uint128 { +#ifdef WORDS_BIGENDIAN + struct { + uint64_t high; + uint64_t low; + } parts; +#else + struct { + uint64_t low; + uint64_t high; + } parts; +#endif +#ifdef HAVE_UINT128_T + uint128_t value; +#endif +}; +typedef union rb_uint128 rb_uint128_t; + +union rb_int128 { +#ifdef WORDS_BIGENDIAN + struct { + uint64_t high; + uint64_t low; + } parts; +#else + struct { + uint64_t low; + uint64_t high; + } parts; +#endif +#ifdef HAVE_UINT128_T + int128_t value; +#endif +}; +typedef union rb_int128 rb_int128_t; + +union uint128_int128_conversion { + rb_uint128_t uint128; + rb_int128_t int128; +}; + +// Conversion functions for 128-bit integers: +rb_uint128_t rb_numeric_to_uint128(VALUE x); +rb_int128_t rb_numeric_to_int128(VALUE x); +VALUE rb_uint128_to_numeric(rb_uint128_t n); +VALUE rb_int128_to_numeric(rb_int128_t n); + static inline bool INT_POSITIVE_P(VALUE num) { @@ -161,7 +211,7 @@ rb_num_compare_with_zero(VALUE num, ID mid) VALUE zero = INT2FIX(0); VALUE r = rb_check_funcall(num, mid, 1, &zero); if (RB_UNDEF_P(r)) { - rb_cmperr(num, zero); + rb_cmperr_reason(num, zero, "unable to compare with zero"); } return r; } diff --git a/internal/object.h b/internal/object.h index 3bde53c31b..99aa1f524b 100644 --- a/internal/object.h +++ b/internal/object.h @@ -11,7 +11,7 @@ #include "ruby/ruby.h" /* for VALUE */ /* object.c */ -size_t rb_obj_embedded_size(uint32_t fields_count); + VALUE rb_class_allocate_instance(VALUE klass); VALUE rb_class_search_ancestor(VALUE klass, VALUE super); NORETURN(void rb_undefined_alloc(VALUE klass)); @@ -60,4 +60,13 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass) RBASIC_SET_CLASS_RAW(obj, klass); RB_OBJ_WRITTEN(obj, oldv, klass); } + +static inline size_t +rb_obj_embedded_size(uint32_t fields_count) +{ + size_t size = offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count); + // Ensure enough room for the heap pointer if this expands + if (size < sizeof(struct RObject)) size = sizeof(struct RObject); + return size; +} #endif /* INTERNAL_OBJECT_H */ diff --git a/internal/range.h b/internal/range.h index 2394937bf8..80493ce13e 100644 --- a/internal/range.h +++ b/internal/range.h @@ -18,19 +18,19 @@ static inline VALUE RANGE_EXCL(VALUE r); static inline VALUE RANGE_BEG(VALUE r) { - return RSTRUCT(r)->as.ary[0]; + return RSTRUCT_GET_RAW(r, 0); } static inline VALUE RANGE_END(VALUE r) { - return RSTRUCT_GET(r, 1); + return RSTRUCT_GET_RAW(r, 1); } static inline VALUE RANGE_EXCL(VALUE r) { - return RSTRUCT_GET(r, 2); + return RSTRUCT_GET_RAW(r, 2); } VALUE diff --git a/internal/rational.h b/internal/rational.h index f11fab4583..6861a90130 100644 --- a/internal/rational.h +++ b/internal/rational.h @@ -28,6 +28,7 @@ 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_rational_fdiv(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); @@ -37,7 +38,9 @@ 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_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode); +VALUE rb_flo_ceil_by_rational(VALUE num, int ndigits); +VALUE rb_flo_floor_by_rational(VALUE num, int ndigits); VALUE rb_float_numerator(VALUE x); VALUE rb_float_denominator(VALUE x); @@ -68,4 +71,22 @@ RATIONAL_SET_DEN(VALUE r, VALUE d) RB_OBJ_WRITE(r, &RRATIONAL(r)->den, d); } +inline static bool +f_zero_p(VALUE x) +{ + if (RB_INTEGER_TYPE_P(x)) { + return FIXNUM_ZERO_P(x); + } + else if (RB_FLOAT_TYPE_P(x)) { + return FLOAT_ZERO_P(x); + } + else if (RB_TYPE_P(x, T_RATIONAL)) { + const VALUE num = RRATIONAL(x)->num; + return FIXNUM_ZERO_P(num); + } + return rb_equal(x, INT2FIX(0)) != 0; +} + +#define f_nonzero_p(x) (!f_zero_p(x)) + #endif /* INTERNAL_RATIONAL_H */ diff --git a/internal/re.h b/internal/re.h index 2788f8b42a..6c0aee6d06 100644 --- a/internal/re.h +++ b/internal/re.h @@ -10,19 +10,70 @@ */ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/ruby.h" /* for VALUE */ +#include "ruby/re.h" /* for struct RMatch and struct re_registers */ + +#define RMATCH_ONIG FL_USER1 +#define RMATCH_OFFSETS_EXTERNAL FL_USER2 + +static inline OnigPosition * +RMATCH_BEG_PTR(VALUE match) +{ + if (FL_TEST_RAW(match, RMATCH_ONIG)) { + return RMATCH(match)->as.onig.beg; + } + else { + return &RMATCH(match)->as.embed[0]; + } +} + +static inline OnigPosition * +RMATCH_END_PTR(VALUE match) +{ + if (FL_TEST_RAW(match, RMATCH_ONIG)) { + return RMATCH(match)->as.onig.end; + } + else { + return &RMATCH(match)->as.embed[RMATCH(match)->num_regs]; + } +} + +static inline long +RMATCH_BEG(VALUE match, int i) +{ + return RMATCH_BEG_PTR(match)[i]; +} + +static inline long +RMATCH_END(VALUE match, int i) +{ + return RMATCH_END_PTR(match)[i]; +} + +static inline int +RMATCH_NREGS(VALUE match) +{ + return RMATCH(match)->num_regs; +} /* re.c */ +VALUE rb_reg_s_alloc(VALUE klass); 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 *); VALUE rb_reg_match_p(VALUE re, VALUE str, long pos); +VALUE rb_reg_regsub_match(VALUE str, VALUE src, VALUE match); bool rb_reg_start_with_p(VALUE re, VALUE str); VALUE rb_reg_hash(VALUE re); VALUE rb_reg_equal(VALUE re1, VALUE re2); VALUE rb_backref_set_string(VALUE string, long pos, long len); void rb_match_unbusy(VALUE); int rb_match_count(VALUE match); -VALUE rb_reg_new_ary(VALUE ary, int options); +VALUE rb_reg_new_from_values(long cnt, const VALUE *elements, int opt); VALUE rb_reg_last_defined(VALUE match); +#define ARG_REG_OPTION_MASK \ + (ONIG_OPTION_IGNORECASE|ONIG_OPTION_MULTILINE|ONIG_OPTION_EXTEND) +#define ARG_ENCODING_FIXED 16 +#define ARG_ENCODING_NONE 32 + #endif /* INTERNAL_RE_H */ diff --git a/internal/set_table.h b/internal/set_table.h index 3cb9c64349..3876a8935e 100644 --- a/internal/set_table.h +++ b/internal/set_table.h @@ -1,7 +1,7 @@ #ifndef INTERNAL_SET_TABLE_H #define INTERNAL_SET_TABLE_H -#include "include/ruby/st.h" +#include "ruby/st.h" struct set_table_entry; @@ -15,13 +15,16 @@ struct set_table { const struct st_hash_type *type; /* Number of entries currently in the table. */ st_index_t num_entries; - /* Array of bins used for access by keys. */ - st_index_t *bins; + /* Start and bound index of entries in array entries. entries_starts and entries_bound are in interval [0,allocated_entries]. */ st_index_t entries_start, entries_bound; - /* Array of size 2^entry_power. */ + + /** + * Array of size 2^entry_power. + * Followed by st_index_t *bins, Array of bins used for access by keys. + */ set_table_entry *entries; }; @@ -39,6 +42,8 @@ set_table *rb_set_init_table_with_size(set_table *tab, const struct st_hash_type set_table *rb_set_init_numtable(void); #define set_init_numtable_with_size rb_set_init_numtable_with_size set_table *rb_set_init_numtable_with_size(st_index_t size); +#define set_init_embedded_numtable_with_size rb_set_init_embedded_numtable_with_size +set_table *rb_set_init_embedded_numtable_with_size(struct set_table *tbl, st_index_t size); #define set_table_delete rb_set_table_delete int rb_set_table_delete(set_table *, st_data_t *); /* returns 0:notfound 1:deleted */ #define set_insert rb_set_insert @@ -55,6 +60,8 @@ int rb_set_foreach_check(set_table *, set_foreach_check_callback_func *, st_data st_index_t rb_set_keys(set_table *table, st_data_t *keys, st_index_t size); #define set_free_table rb_set_free_table void rb_set_free_table(set_table *); +#define set_free_embedded_table rb_set_free_embedded_table +void set_free_embedded_table(set_table *tab); #define set_table_clear rb_set_table_clear void rb_set_table_clear(set_table *); #define set_copy rb_set_copy diff --git a/internal/st.h b/internal/st.h index a26b224505..14dcb25511 100644 --- a/internal/st.h +++ b/internal/st.h @@ -1,11 +1,20 @@ #ifndef INTERNAL_ST_H #define INTERNAL_ST_H -#include "include/ruby/st.h" +#include "ruby/st.h" st_table *rb_st_replace(st_table *new_tab, st_table *old_tab); #define st_replace rb_st_replace st_table *rb_st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type, st_index_t size); #define st_init_existing_table_with_size rb_st_init_existing_table_with_size +st_table *rb_st_init_existing_numtable_with_size(st_table *tab, st_index_t size); +#define st_init_existing_numtable_with_size rb_st_init_existing_numtable_with_size + +st_table *rb_st_init_existing_strtable_with_size(st_table *tab, st_index_t size); +#define st_init_existing_strtable_with_size rb_st_init_existing_strtable_with_size + +void rb_st_free_embedded_table(st_table *tab); +#define st_free_embedded_table rb_st_free_embedded_table + #endif diff --git a/internal/string.h b/internal/string.h index d6fea62061..94a46a9657 100644 --- a/internal/string.h +++ b/internal/string.h @@ -14,6 +14,7 @@ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/encoding.h" /* for rb_encoding */ #include "ruby/ruby.h" /* for VALUE */ +#include "encindex.h" #define STR_SHARED FL_USER0 /* = ELTS_SHARED */ #define STR_NOEMBED FL_USER1 @@ -29,6 +30,39 @@ enum ruby_rstring_private_flags { # undef rb_fstring_cstr #endif +static inline bool +rb_str_encindex_fastpath(int encindex) +{ + // The overwhelming majority of strings are in one of these 3 encodings, + // which are all either ASCII or perfect ASCII supersets. + // Hence you can use fast, single byte algorithms on them, such as `memchr` etc, + // without all the overhead of fetching the rb_encoding and using functions such as + // rb_enc_mbminlen etc. + // Many other encodings could qualify, but they are expected to be rare occurrences, + // so it's better to keep that list small. + switch (encindex) { + case ENCINDEX_ASCII_8BIT: + case ENCINDEX_UTF_8: + case ENCINDEX_US_ASCII: + return true; + default: + return false; + } +} + +static inline bool +rb_str_enc_fastpath(VALUE str) +{ + return rb_str_encindex_fastpath(ENCODING_GET_INLINED(str)); +} + +static inline rb_encoding * +rb_str_enc_get(VALUE str) +{ + RUBY_ASSERT(RB_TYPE_P(str, T_STRING)); + return rb_enc_from_index(ENCODING_GET(str)); +} + /* string.c */ VALUE rb_str_dup_m(VALUE str); VALUE rb_fstring(VALUE); @@ -63,6 +97,8 @@ bool rb_str_reembeddable_p(VALUE); VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE); VALUE rb_str_with_debug_created_info(VALUE, VALUE, int); VALUE rb_str_frozen_bare_string(VALUE); +const char *rb_str_null_check(VALUE); +VALUE rb_str_casecmp(VALUE str1, VALUE str2); /* error.c */ void rb_warn_unchilled_literal(VALUE str); diff --git a/internal/struct.h b/internal/struct.h index a8c773b730..d3c8157393 100644 --- a/internal/struct.h +++ b/internal/struct.h @@ -11,10 +11,23 @@ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/ruby.h" /* for struct RBasic */ +/* Flags of RStruct + * + * 1-7: RSTRUCT_EMBED_LEN + * If non-zero, the struct is embedded (its contents follow the + * header, rather than being on a separately allocated buffer) and + * these bits are the length of the Struct. + * 8: RSTRUCT_GEN_FIELDS + * The struct is embedded and has no space left to store the + * IMEMO/fields reference. Any ivar this struct may have will be in + * the generic_fields_tbl. This flag doesn't imply the struct has + * ivars. + */ enum { RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1, RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1), + RSTRUCT_GEN_FIELDS = RUBY_FL_USER8, }; struct RStruct { @@ -23,6 +36,7 @@ struct RStruct { struct { long len; const VALUE *ptr; + VALUE fields_obj; } heap; /* This is a length 1 array because: * 1. GCC has a bug that does not optimize C flexible array members @@ -35,36 +49,16 @@ struct RStruct { #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 long RSTRUCT_EMBED_LEN(VALUE st); -static inline long RSTRUCT_LEN(VALUE st); +static inline long RSTRUCT_LEN_RAW(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 void RSTRUCT_SET_RAW(VALUE st, long k, VALUE v); +static inline VALUE RSTRUCT_GET_RAW(VALUE st, long k); static inline long RSTRUCT_EMBED_LEN(VALUE st) @@ -75,7 +69,7 @@ RSTRUCT_EMBED_LEN(VALUE st) } static inline long -RSTRUCT_LEN(VALUE st) +RSTRUCT_LEN_RAW(VALUE st) { if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) { return RSTRUCT_EMBED_LEN(st); @@ -88,7 +82,7 @@ RSTRUCT_LEN(VALUE st) static inline int RSTRUCT_LENINT(VALUE st) { - return rb_long2int(RSTRUCT_LEN(st)); + return rb_long2int(RSTRUCT_LEN_RAW(st)); } static inline const VALUE * @@ -105,15 +99,42 @@ RSTRUCT_CONST_PTR(VALUE st) } static inline void -RSTRUCT_SET(VALUE st, long k, VALUE v) +RSTRUCT_SET_RAW(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) +RSTRUCT_GET_RAW(VALUE st, long k) { return RSTRUCT_CONST_PTR(st)[k]; } +static inline VALUE +RSTRUCT_FIELDS_OBJ(VALUE st) +{ + const long embed_len = RSTRUCT_EMBED_LEN(st); + VALUE fields_obj; + if (embed_len) { + RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS)); + fields_obj = RSTRUCT_GET_RAW(st, embed_len); + } + else { + fields_obj = RSTRUCT(st)->as.heap.fields_obj; + } + return fields_obj; +} + +static inline void +RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj) +{ + const long embed_len = RSTRUCT_EMBED_LEN(st); + if (embed_len) { + RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS)); + RSTRUCT_SET_RAW(st, embed_len, fields_obj); + } + else { + RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj); + } +} #endif /* INTERNAL_STRUCT_H */ diff --git a/internal/symbol.h b/internal/symbol.h index 131cddef90..b9109b1347 100644 --- a/internal/symbol.h +++ b/internal/symbol.h @@ -17,8 +17,7 @@ #endif /* symbol.c */ -void rb_sym_global_symbols_mark(void); -void rb_sym_global_symbols_update_references(void); +void rb_sym_global_symbols_mark_and_move(void); 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); @@ -35,6 +34,7 @@ bool rb_obj_is_symbol_table(VALUE obj); void rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data); void rb_gc_free_dsymbol(VALUE); int rb_static_id_valid_p(ID id); +void rb_free_global_symbol_table(void); #if __has_builtin(__builtin_constant_p) #define rb_sym_intern_ascii_cstr(ptr) \ diff --git a/internal/thread.h b/internal/thread.h index 928126c3b0..ea891b4372 100644 --- a/internal/thread.h +++ b/internal/thread.h @@ -56,14 +56,16 @@ VALUE rb_mutex_owned_p(VALUE self); VALUE rb_exec_recursive_outer_mid(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h, ID mid); void ruby_mn_threads_params(void); -int rb_thread_io_wait(struct rb_io *io, int events, struct timeval * timeout); -int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout); +int rb_thread_io_wait(struct rb_thread_struct *th, struct rb_io *io, int events, struct timeval * timeout); +int rb_thread_wait_for_single_fd(struct rb_thread_struct *th, int fd, int events, struct timeval * timeout); size_t rb_thread_io_close_interrupt(struct rb_io *); void rb_thread_io_close_wait(struct rb_io *); void rb_ec_check_ints(struct rb_execution_context_struct *ec); +void rb_thread_free_native_thread(void *th_ptr); + RUBY_SYMBOL_EXPORT_BEGIN void *rb_thread_prevent_fork(void *(*func)(void *), void *data); /* for ext/socket/raddrinfo.c */ diff --git a/internal/time.h b/internal/time.h index e21b3574f6..1f3505f5bc 100644 --- a/internal/time.h +++ b/internal/time.h @@ -27,11 +27,8 @@ struct timeval rb_time_timeval(VALUE); RUBY_SYMBOL_EXPORT_BEGIN /* time.c (export) */ -void ruby_reset_leap_second_info(void); -#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY -RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() -#endif -void ruby_reset_timezone(const char *); RUBY_SYMBOL_EXPORT_END +void ruby_reset_timezone(const char *); + #endif /* INTERNAL_TIME_H */ diff --git a/internal/variable.h b/internal/variable.h index bbf3243fe9..58364941c1 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -22,13 +22,14 @@ VALUE rb_search_class_path(VALUE); VALUE rb_attr_delete(VALUE, ID); void rb_autoload_str(VALUE mod, ID id, VALUE file); VALUE rb_autoload_at_p(VALUE, ID, int); -void rb_autoload_copy_table_for_namespace(st_table *, const rb_namespace_t *); +void rb_autoload_copy_table_for_box(st_table *, const rb_box_t *); 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); -void rb_gvar_namespace_ready(const char *name); +void rb_gvar_box_ready(const char *name); +void rb_gvar_box_dynamic(const char *name); /** * Sets the name of a module. @@ -46,14 +47,16 @@ void rb_gvar_namespace_ready(const char *name); */ VALUE rb_mod_set_temporary_name(VALUE, VALUE); -int rb_gen_fields_tbl_get(VALUE obj, ID id, VALUE *fields_obj); void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table); -void rb_obj_init_too_complex(VALUE obj, st_table *table); +void rb_obj_init_complex(VALUE obj, st_table *table); void rb_evict_ivars_to_hash(VALUE obj); -shape_id_t rb_evict_fields_to_hash(VALUE obj); VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id); void rb_ivar_set_internal(VALUE obj, ID id, VALUE val); -void rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val); +void rb_ivar_foreach_buffered(VALUE obj, int (*func)(ID name, VALUE val, st_data_t arg), st_data_t arg); +attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val); +attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val); +VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id); +VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index); RUBY_SYMBOL_EXPORT_BEGIN /* variable.c (export) */ @@ -69,6 +72,5 @@ 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_ensure_iv_list_size(VALUE obj, uint32_t current_len, uint32_t newsize); -attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val); #endif /* INTERNAL_VARIABLE_H */ diff --git a/internal/vm.h b/internal/vm.h index 3a99011c44..4e50ec2710 100644 --- a/internal/vm.h +++ b/internal/vm.h @@ -69,6 +69,7 @@ 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_ec_yield(struct rb_execution_context_struct *ec, 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, @@ -77,11 +78,12 @@ void rb_check_stack_overflow(void); #define RB_BLOCK_NO_USE_PACKED_ARGS 2 VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags); struct vm_ifunc *rb_current_ifunc(void); -VALUE rb_gccct_clear_table(VALUE); +VALUE rb_gccct_clear_table(void); +VALUE rb_eval_cmd_call_kw(VALUE cmd, int argc, const VALUE *argv, int kw_splat); #if USE_YJIT || USE_ZJIT /* vm_exec.c */ -extern uint64_t rb_vm_insns_count; +extern uint64_t rb_vm_insn_count; #endif extern bool rb_free_at_exit; @@ -99,8 +101,6 @@ const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo /* vm_method.c */ int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv); -void rb_clear_constant_cache(void); - /* vm_dump.c */ void rb_print_backtrace(FILE *); |
