diff options
Diffstat (limited to 'include/ruby/internal/core')
| -rw-r--r-- | include/ruby/internal/core/rarray.h | 2 | ||||
| -rw-r--r-- | include/ruby/internal/core/rbasic.h | 16 | ||||
| -rw-r--r-- | include/ruby/internal/core/rclass.h | 2 | ||||
| -rw-r--r-- | include/ruby/internal/core/rdata.h | 297 | ||||
| -rw-r--r-- | include/ruby/internal/core/rmatch.h | 55 | ||||
| -rw-r--r-- | include/ruby/internal/core/robject.h | 35 | ||||
| -rw-r--r-- | include/ruby/internal/core/rstring.h | 57 | ||||
| -rw-r--r-- | include/ruby/internal/core/rstruct.h | 12 | ||||
| -rw-r--r-- | include/ruby/internal/core/rtypeddata.h | 317 |
9 files changed, 316 insertions, 477 deletions
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index 73cc0f5dd9..b47b63d51b 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -367,7 +367,7 @@ RARRAY_PTR(VALUE ary) { RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); - VALUE tmp = RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary); + VALUE tmp = RB_OBJ_WB_UNPROTECT(ary); return RBIMPL_CAST((VALUE *)RARRAY_CONST_PTR(tmp)); } diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h index a1477e2600..63cdff8e09 100644 --- a/include/ruby/internal/core/rbasic.h +++ b/include/ruby/internal/core/rbasic.h @@ -55,6 +55,12 @@ enum ruby_rvalue_flags { RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX }; +#if (SIZEOF_VALUE < SIZEOF_UINT64_T) +#define RBASIC_SHAPE_ID_FIELD 1 +#else +#define RBASIC_SHAPE_ID_FIELD 0 +#endif + /** * Ruby object's base components. All Ruby objects have them in common. */ @@ -85,6 +91,10 @@ RBasic { */ const VALUE klass; +#if RBASIC_SHAPE_ID_FIELD + VALUE shape_id; +#endif + #ifdef __cplusplus public: RBIMPL_ATTR_CONSTEXPR(CXX11) @@ -100,8 +110,14 @@ RBasic { RBasic() : flags(RBIMPL_VALUE_NULL), klass(RBIMPL_VALUE_NULL) +#if RBASIC_SHAPE_ID_FIELD + , shape_id(RBIMPL_VALUE_NULL) +#endif { } +# define RBASIC_INIT RBasic() +#else +# define RBASIC_INIT {RBIMPL_VALUE_NULL} #endif }; diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h index b0b6bfc80c..6f78cc569b 100644 --- a/include/ruby/internal/core/rclass.h +++ b/include/ruby/internal/core/rclass.h @@ -58,7 +58,7 @@ enum ruby_rmodule_flags { * rb_mod_refine() has this flag set. This is the bit which controls * difference between normal inclusion versus refinements. */ - RMODULE_IS_REFINEMENT = RUBY_FL_USER3 + RMODULE_IS_REFINEMENT = RUBY_FL_USER1 }; struct RClass; /* Opaque, declared here for RCLASS() macro. */ diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h index e4c146a716..d0a4dc7c83 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -42,31 +42,9 @@ #endif #define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f)) -#define RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() \ - RBIMPL_ATTR_WARNING(("untyped Data is unsafe; use TypedData instead")) \ - RBIMPL_ATTR_DEPRECATED(("by TypedData")) - -#define RBIMPL_MACRO_SELECT(x, y) x ## y -#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y) /** @endcond */ /** - * Convenient casting macro. - * - * @param obj An object, which is in fact an ::RData. - * @return The passed object casted to ::RData. - */ -#define RDATA(obj) RBIMPL_CAST((struct RData *)(obj)) - -/** - * Convenient getter macro. - * - * @param obj An object, which is in fact an ::RData. - * @return The passed object's ::RData::data field. - */ -#define DATA_PTR(obj) RDATA(obj)->data - -/** * This is a value you can set to ::RData::dfree. Setting this means the data * was allocated using ::ruby_xmalloc() (or variants), and shall be freed using * ::ruby_xfree(). @@ -85,19 +63,6 @@ #define RUBY_NEVER_FREE RBIMPL_DATA_FUNC(0) /** - * @private - * - * @deprecated This macro once was a thing in the old days, but makes no sense - * any longer today. Exists here for backwards compatibility - * only. You can safely forget about it. - */ -#define RUBY_UNTYPED_DATA_FUNC(f) f RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() - -/* -#define RUBY_DATA_FUNC(func) ((void (*)(void*))(func)) -*/ - -/** * This is the type of callbacks registered to ::RData. The argument is the * `data` field. */ @@ -106,268 +71,16 @@ typedef void (*RUBY_DATA_FUNC)(void*); /** * @deprecated * - * Old "untyped" user data. It has roughly the same usage as struct - * ::RTypedData, but lacked several features such as support for compaction GC. - * Use of this struct is not recommended any longer. If it is dead necessary, - * please inform the core devs about your usage. - * - * @internal - * - * @shyouhei tried to add RBIMPL_ATTR_DEPRECATED for this type but that yielded - * too many warnings in the core. Maybe we want to retry later... Just add - * deprecated document for now. + * DO NOT USE: Obsolete "untyped" user data, that is remained only for + * the backward compatibility for some wrapper generator gems. */ struct RData { - - /** Basic part, including flags and class. */ struct RBasic basic; - - /** - * This function is called when the object is experiencing GC marks. If it - * contains references to other Ruby objects, you need to mark them also. - * Otherwise GC will smash your data. - * - * @see rb_gc_mark() - * @warning This is called during GC runs. Object allocations are - * impossible at that moment (that is why GC runs). - */ + VALUE fields_obj; + VALUE _reserved; + void *data; RUBY_DATA_FUNC dmark; - - /** - * This function is called when the object is no longer used. You need to - * do whatever necessary to avoid memory leaks. - * - * @warning This is called during GC runs. Object allocations are - * impossible at that moment (that is why GC runs). - */ RUBY_DATA_FUNC dfree; - - /** Pointer to the actual C level struct that you want to wrap. */ - void *data; }; -RBIMPL_SYMBOL_EXPORT_BEGIN() - -/** - * This is the primitive way to wrap an existing C struct into ::RData. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] datap Pointer to the target C struct. - * @param[in] dmark Mark function. - * @param[in] dfree Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps `datap`. - */ -VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); - -/** - * Identical to rb_data_object_wrap(), except it allocates a new data region - * internally instead of taking an existing one. The allocation is done using - * ruby_calloc(). Hence it makes no sense to pass anything other than - * ::RUBY_DEFAULT_FREE to the last argument. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] size Requested size of memory to allocate. - * @param[in] dmark Mark function. - * @param[in] dfree Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps a new `size` byte region. - */ -VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); - -/** - * @private - * Documented in include/ruby/internal/globals.h - */ -RUBY_EXTERN VALUE rb_cObject; -RBIMPL_SYMBOL_EXPORT_END() - -/** - * Converts sval, a pointer to your struct, into a Ruby object. - * - * @param klass A ruby level class. - * @param mark Mark function. - * @param free Free function. - * @param sval A pointer to your struct. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - */ -#define Data_Wrap_Struct(klass, mark, free, sval) \ - rb_data_object_wrap( \ - (klass), \ - (sval), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free)) - -/** - * @private - * - * This is an implementation detail of #Data_Make_Struct. People don't use it - * directly. - * - * @param result Variable name of created Ruby object. - * @param klass Ruby level class of the object. - * @param type Type name of the C struct. - * @param size Size of the C struct. - * @param mark Mark function. - * @param free Free function. - * @param sval Variable name of created C struct. - */ -#define Data_Make_Struct0(result, klass, type, size, mark, free, sval) \ - VALUE result = rb_data_object_zalloc( \ - (klass), \ - (size), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free)); \ - (sval) = RBIMPL_CAST((type *)DATA_PTR(result)); \ - RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval)) - -/** - * Identical to #Data_Wrap_Struct, except it allocates a new data region - * internally instead of taking an existing one. The allocation is done using - * ruby_calloc(). Hence it makes no sense to pass anything other than - * ::RUBY_DEFAULT_FREE to the `free` argument. - * - * @param klass Ruby level class of the returning object. - * @param type Type name of the C struct. - * @param mark Mark function. - * @param free Free function. - * @param sval Variable name of created C struct. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - */ -#ifdef HAVE_STMT_AND_DECL_IN_EXPR -#define Data_Make_Struct(klass, type, mark, free, sval) \ - RB_GNUC_EXTENSION({ \ - Data_Make_Struct0( \ - data_struct_obj, \ - klass, \ - type, \ - sizeof(type), \ - mark, \ - free, \ - sval); \ - data_struct_obj; \ - }) -#else -#define Data_Make_Struct(klass, type, mark, free, sval) \ - rb_data_object_make( \ - (klass), \ - RBIMPL_DATA_FUNC(mark), \ - RBIMPL_DATA_FUNC(free), \ - RBIMPL_CAST((void **)&(sval)), \ - sizeof(type)) -#endif - -/** - * Obtains a C struct from inside of a wrapper Ruby object. - * - * @param obj An instance of ::RData. - * @param type Type name of the C struct. - * @param sval Variable name of obtained C struct. - * @return Unwrapped C struct that `obj` holds. - */ -#define Data_Get_Struct(obj, type, sval) \ - ((sval) = RBIMPL_CAST((type*)rb_data_object_get(obj))) - -RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() -/** - * @private - * - * This is an implementation detail of rb_data_object_wrap(). People don't use - * it directly. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] ptr Pointer to the target C struct. - * @param[in] mark Mark function. - * @param[in] free Free function. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return An allocated object that wraps `datap`. - */ -static inline VALUE -rb_data_object_wrap_warning(VALUE klass, void *ptr, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free) -{ - return rb_data_object_wrap(klass, ptr, mark, free); -} - -/** - * @private - * - * This is an implementation detail of #Data_Get_Struct. People don't use it - * directly. - * - * @param[in] obj An instance of ::RData. - * @return Unwrapped C struct that `obj` holds. - */ -static inline void * -rb_data_object_get(VALUE obj) -{ - Check_Type(obj, RUBY_T_DATA); - return DATA_PTR(obj); -} - -RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() -/** - * @private - * - * This is an implementation detail of #Data_Get_Struct. People don't use it - * directly. - * - * @param[in] obj An instance of ::RData. - * @return Unwrapped C struct that `obj` holds. - */ -static inline void * -rb_data_object_get_warning(VALUE obj) -{ - return rb_data_object_get(obj); -} - -/** - * This is an implementation detail of #Data_Make_Struct. People don't use it - * directly. - * - * @param[in] klass Ruby level class of the returning object. - * @param[in] mark_func Mark function. - * @param[in] free_func Free function. - * @param[in] datap Variable of created C struct. - * @param[in] size Requested size of allocation. - * @exception rb_eTypeError `klass` is not a class. - * @exception rb_eNoMemError Out of memory. - * @return A created Ruby object. - * @post `*datap` holds the created C struct. - */ -static inline VALUE -rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_func, void **datap, size_t size) -{ - Data_Make_Struct0(result, klass, void, size, mark_func, free_func, *datap); - return result; -} - -RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap")) -/** @deprecated This function was renamed to rb_data_object_wrap(). */ -static inline VALUE -rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree) -{ - return rb_data_object_wrap(klass, data, dmark, dfree); -} - -/** @cond INTERNAL_MACRO */ -#define rb_data_object_wrap_0 rb_data_object_wrap -#define rb_data_object_wrap_1 rb_data_object_wrap_warning -#define rb_data_object_wrap_2 rb_data_object_wrap_ /* Used here vvvv */ -#define rb_data_object_wrap RUBY_MACRO_SELECT(rb_data_object_wrap_2, RUBY_UNTYPED_DATA_WARNING) -#define rb_data_object_get_0 rb_data_object_get -#define rb_data_object_get_1 rb_data_object_get_warning -#define rb_data_object_get_2 rb_data_object_get_ /* Used here vvvv */ -#define rb_data_object_get RUBY_MACRO_SELECT(rb_data_object_get_2, RUBY_UNTYPED_DATA_WARNING) -#define rb_data_object_make_0 rb_data_object_make -#define rb_data_object_make_1 rb_data_object_make_warning -#define rb_data_object_make_2 rb_data_object_make_ /* Used here vvvv */ -#define rb_data_object_make RUBY_MACRO_SELECT(rb_data_object_make_2, RUBY_UNTYPED_DATA_WARNING) -/** @endcond */ #endif /* RBIMPL_RDATA_H */ diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h index a528c2999e..ae93755531 100644 --- a/include/ruby/internal/core/rmatch.h +++ b/include/ruby/internal/core/rmatch.h @@ -67,23 +67,6 @@ struct rmatch_offset { long end; /**< End of a group. */ }; -/** Represents a match. */ -struct rb_matchext_struct { - /** - * "Registers" of a match. This is a quasi-opaque struct that holds - * execution result of a match. Roughly resembles `&~`. - */ - struct re_registers regs; - - /** Capture group offsets, in C array. */ - struct rmatch_offset *char_offset; - - /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */ - int char_offset_num_allocated; -}; - -typedef struct rb_matchext_struct rb_matchext_t; - /** * Regular expression execution context. When a regular expression "matches" * to a string, it generates capture groups etc. This struct holds that info. @@ -107,12 +90,41 @@ struct RMatch { * The expression of this match. */ VALUE regexp; /* RRegexp */ + + /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */ + int char_offset_num_allocated; + + /** Capture group offsets, in C array. */ + struct rmatch_offset *char_offset; + + /** Number of capture-group registers. */ + int num_regs; + + /** Capacity of `as.embed`, in OnigPosition slots. */ + int capa; + + /** + * "Registers" of a match. This is a quasi-opaque struct that holds + * execution result of a match. Roughly resembles `$~`. + */ + union { + OnigPosition embed[1]; + struct re_registers onig; + } as; }; -#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch))) +RBIMPL_SYMBOL_EXPORT_BEGIN() +/** + * @private + * + * Converts an embedded match to onig form. This is an implementation + * detail of #RMATCH_REGS. People don't use it directly. + * + * @param[out] match A match object, possibly in embedded form. + */ +void rb_match_ensure_onig(VALUE match); +RBIMPL_SYMBOL_EXPORT_END() -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() /** * Queries the raw ::re_registers. * @@ -138,7 +150,8 @@ static inline struct re_registers * RMATCH_REGS(VALUE match) { RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH); - return &RMATCH_EXT(match)->regs; + rb_match_ensure_onig(match); + return &RMATCH(match)->as.onig; } #endif /* RBIMPL_RMATCH_H */ diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index 1f2b7168b8..df1901eb1e 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -42,10 +42,10 @@ */ #define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj)) /** @cond INTERNAL_MACRO */ -#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX -#define ROBJECT_EMBED ROBJECT_EMBED -#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY -#define ROBJECT_IVPTR ROBJECT_IVPTR +#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX +#define ROBJECT_HEAP ROBJECT_HEAP +#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY +#define ROBJECT_FIELDS ROBJECT_FIELDS /** @endcond */ /** @@ -55,10 +55,12 @@ */ enum ruby_robject_flags { /** - * This flag has something to do with memory footprint. If the object is - * "small" enough, ruby tries to be creative to abuse padding bits of - * struct ::RObject for storing instance variables. This flag denotes that - * situation. + * This flag marks that the object's instance variables are stored in an + * external heap buffer. + * Normally, instance variable references are stored inside the object slot, + * but if it overflow, Ruby may have to allocate a separate buffer and spills + * the instance variables there. + * This flag denotes that situation. * * @warning This bit has to be considered read-only. Setting/clearing * this bit without corresponding fix up must cause immediate @@ -71,7 +73,7 @@ enum ruby_robject_flags { * 3rd parties must not be aware that there even is more than one way to * store instance variables. Might better be hidden. */ - ROBJECT_EMBED = RUBY_FL_USER1 + ROBJECT_HEAP = RUBY_FL_USER4 }; struct st_table; @@ -94,9 +96,14 @@ struct RObject { */ struct { /** Pointer to a C array that holds instance variables. */ - VALUE *ivptr; + VALUE *fields; } heap; + /* When an object is too complex, it uses a st_table to store instance + * variable name to value mappings. + */ + st_table *hash; + /* Embedded instance variables. When an object is small enough, it * uses this area to store the instance variables. * @@ -123,17 +130,17 @@ RBIMPL_ATTR_ARTIFICIAL() * @shyouhei finds no reason for this to be visible from extension libraries. */ static inline VALUE * -ROBJECT_IVPTR(VALUE obj) +ROBJECT_FIELDS(VALUE obj) { RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); struct RObject *const ptr = ROBJECT(obj); - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - return ptr->as.ary; + if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) { + return ptr->as.heap.fields; } else { - return ptr->as.heap.ivptr; + return ptr->as.ary; } } diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h index 0bca74e688..35175ea94a 100644 --- a/include/ruby/internal/core/rstring.h +++ b/include/ruby/internal/core/rstring.h @@ -369,41 +369,6 @@ RSTRING_LEN(VALUE str) return RSTRING(str)->len; } -RBIMPL_WARNING_PUSH() -#if RBIMPL_COMPILER_IS(Intel) -RBIMPL_WARNING_IGNORED(413) -#endif - -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -/** - * @private - * - * "Expands" an embedded string into an ordinal one. This is a function that - * returns aggregated type. The returned struct always has its `as.heap.len` - * an `as.heap.ptr` fields set appropriately. - * - * This is an implementation detail that 3rd parties should never bother. - */ -static inline struct RString -rbimpl_rstring_getmem(VALUE str) -{ - RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING); - - if (RB_FL_ANY_RAW(str, RSTRING_NOEMBED)) { - return *RSTRING(str); - } - else { - /* Expecting compilers to optimize this on-stack struct away. */ - struct RString retval; - retval.len = RSTRING_LEN(str); - retval.as.heap.ptr = RSTRING(str)->as.embed.ary; - return retval; - } -} - -RBIMPL_WARNING_POP() - RBIMPL_ATTR_ARTIFICIAL() /** * Queries the contents pointer of the string. @@ -415,7 +380,9 @@ RBIMPL_ATTR_ARTIFICIAL() static inline char * RSTRING_PTR(VALUE str) { - char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr; + char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ? + RSTRING(str)->as.heap.ptr : + RSTRING(str)->as.embed.ary; if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) { /* :BEWARE: @shyouhei thinks that currently, there are rooms for this @@ -441,14 +408,17 @@ RBIMPL_ATTR_ARTIFICIAL() static inline char * RSTRING_END(VALUE str) { - struct RString buf = rbimpl_rstring_getmem(str); + char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ? + RSTRING(str)->as.heap.ptr : + RSTRING(str)->as.embed.ary; + long len = RSTRING_LEN(str); - if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) { + if (RUBY_DEBUG && RB_UNLIKELY(!ptr)) { /* Ditto. */ rb_debug_rstring_null_ptr("RSTRING_END"); } - return &buf.as.heap.ptr[buf.len]; + return &ptr[len]; } RBIMPL_ATTR_ARTIFICIAL() @@ -477,16 +447,7 @@ RSTRING_LENINT(VALUE str) * @param ptrvar Variable where its contents is stored. * @param lenvar Variable where its length is stored. */ -#ifdef HAVE_STMT_AND_DECL_IN_EXPR -# define RSTRING_GETMEM(str, ptrvar, lenvar) \ - __extension__ ({ \ - struct RString rbimpl_str = rbimpl_rstring_getmem(str); \ - (ptrvar) = rbimpl_str.as.heap.ptr; \ - (lenvar) = rbimpl_str.len; \ - }) -#else # define RSTRING_GETMEM(str, ptrvar, lenvar) \ ((ptrvar) = RSTRING_PTR(str), \ (lenvar) = RSTRING_LEN(str)) -#endif /* HAVE_STMT_AND_DECL_IN_EXPR */ #endif /* RBIMPL_RSTRING_H */ diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h index 69be487b59..0028a1bdcd 100644 --- a/include/ruby/internal/core/rstruct.h +++ b/include/ruby/internal/core/rstruct.h @@ -31,18 +31,6 @@ # include "ruby/backward.h" #endif -/** - * @private - * - * @deprecated This macro once was a thing in the old days, but makes no sense - * any longer today. Exists here for backwards compatibility - * only. You can safely forget about it. - * - * @internal - * - * Declaration of rb_struct_ptr() is at include/ruby/backward.h. - */ -#define RSTRUCT_PTR(st) rb_struct_ptr(st) /** @cond INTERNAL_MACRO */ #define RSTRUCT_LEN RSTRUCT_LEN #define RSTRUCT_SET RSTRUCT_SET diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index 6c19576c20..eb8313f180 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -26,6 +26,7 @@ # include <stddef.h> #endif +#include "ruby/assert.h" #include "ruby/internal/assume.h" #include "ruby/internal/attr/artificial.h" #include "ruby/internal/attr/flag_enum.h" @@ -37,6 +38,7 @@ #include "ruby/internal/dllexport.h" #include "ruby/internal/error.h" #include "ruby/internal/fl_type.h" +#include "ruby/internal/static_assert.h" #include "ruby/internal/stdbool.h" #include "ruby/internal/value_type.h" @@ -93,13 +95,15 @@ */ #define RTYPEDDATA(obj) RBIMPL_CAST((struct RTypedData *)(obj)) +static inline VALUE rbimpl_check_external_typeddata(VALUE obj); + /** * Convenient getter macro. * * @param v An object, which is in fact an ::RTypedData. * @return The passed object's ::RTypedData::data field. */ -#define RTYPEDDATA_DATA(v) (RTYPEDDATA(v)->data) +#define RTYPEDDATA_DATA(v) (RTYPEDDATA(rbimpl_check_external_typeddata(v))->data) /** @old{rb_check_typeddata} */ #define Check_TypedStruct(v, t) \ @@ -108,13 +112,18 @@ /** @cond INTERNAL_MACRO */ #define RTYPEDDATA_P RTYPEDDATA_P #define RTYPEDDATA_TYPE RTYPEDDATA_TYPE +#define TYPED_DATA_EMBEDDED ((VALUE)1) +#define TYPED_DATA_PTR_MASK (~(TYPED_DATA_EMBEDDED)) +/** @endcond */ + +/** + * Macros to see if each corresponding flag is defined. + */ #define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY #define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE #define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED +#define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE #define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1 -/** @endcond */ - -#define TYPED_DATA_EMBEDDED 2 /** * @private @@ -139,6 +148,20 @@ rbimpl_typeddata_flags { */ RUBY_TYPED_FREE_IMMEDIATELY = 1, + /** + * This flag indicate to Ruby that the associated C struct may be embedded + * inside the object slot, instead of being externally allocated + * with +malloc+. + * + * Embeddable types MUST NOT be accessed using the +DATA_PTR+ macro, only + * with +TypedData_Get_Struct+ or +RTYPEDDATA_GET_DATA+. + * + * Embeddable types MUST NOT free the associated C struct. + * + * Pointers into the associated C struct MUST NOT be used after the ruby + * object is not longer on the stack, as they become invalid when GC + * compaction occurs + */ RUBY_TYPED_EMBEDDABLE = 2, /** @@ -155,6 +178,12 @@ rbimpl_typeddata_flags { */ RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE, + // experimental flag + // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable + // reachable objects from this T_DATA object on the Ractor.make_shareable. + // If it refers to unshareable objects, simply raise an error. + // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE, + /** * This flag has something to do with our garbage collector. These days * ruby objects are "generational". There are those who are young and @@ -177,11 +206,6 @@ rbimpl_typeddata_flags { RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */ /** - * This flag no longer in use - */ - RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6, - - /** * This flag determines whether marking and compaction should be carried out * using the dmark/dcompact callback functions or whether we should mark * declaratively using a list of references defined inside the data struct we're wrapping @@ -251,10 +275,15 @@ struct rb_data_type_struct { RUBY_DATA_FUNC dcompact; /** - * This field is reserved for future extension. For now, it must be - * filled with zeros. + * @internal */ - void *reserved[1]; /* For future extension. + void (*handle_weak_references)(void *); + + /** + * This field is reserved for future extension. For now, it must be + * filled with zeros. + */ + void *reserved[7]; /* For future extension. This array *must* be filled with ZERO. */ } function; @@ -352,24 +381,45 @@ struct RTypedData { /** The part that all ruby objects have in common. */ struct RBasic basic; + /** Direct reference to the slots that holds instance variables, if any **/ + VALUE fields_obj; + /** + * This is a `const rb_data_type_t *const` value, with the low bits set: + * + * 1: Set if object is embedded. + * * This field stores various information about how Ruby should handle a * data. This roughly resembles a Ruby level class (apart from method * definition etc.) */ - const rb_data_type_t *const type; - - /** - * This has to be always 1. - * - * @internal - */ - const VALUE typed_flag; + const VALUE type; /** Pointer to the actual C level struct that you want to wrap. */ void *data; }; +#if !defined(__cplusplus) || __cplusplus >= 201103L +RBIMPL_STATIC_ASSERT(fields_obj_in_rdata, offsetof(struct RData, fields_obj) == offsetof(struct RTypedData, fields_obj)); +RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data)); +#endif + +/** + * Convenient casting macro for backward compatibility. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object casted to ::RData. + */ +#define RDATA(obj) RTYPEDDATA(obj) + +/** + * Convenient casting macro for backward compatibility. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object's ::RTypedData::data field. + */ +#define DATA_PTR(obj) RTYPEDDATA_DATA(obj) + RBIMPL_SYMBOL_EXPORT_BEGIN() RBIMPL_ATTR_NONNULL((3)) /** @@ -384,11 +434,11 @@ RBIMPL_ATTR_NONNULL((3)) */ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type); +RBIMPL_ATTR_NONNULL((3)) /** * Identical to rb_data_typed_object_wrap(), except it allocates a new data * region internally instead of taking an existing one. The allocation is done - * using ruby_calloc(). Hence it makes no sense for `type->function.dfree` to - * be anything other than ::RUBY_TYPED_DEFAULT_FREE. + * using ruby_calloc(). * * @param[in] klass Ruby level class of the returning object. * @param[in] size Requested size of memory to allocate. @@ -399,6 +449,7 @@ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t * */ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type); +RBIMPL_ATTR_NONNULL(()) /** * Checks for the domestic relationship between the two. * @@ -413,6 +464,7 @@ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t */ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent); +RBIMPL_ATTR_NONNULL((2)) /** * Checks if the given object is of given kind. * @@ -423,6 +475,7 @@ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t * */ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type); +RBIMPL_ATTR_NONNULL((2)) /** * Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead * of returning false. @@ -434,8 +487,49 @@ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type); * @post Upon successful return `obj`'s type is guaranteed `data_type`. */ void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type); + +RBIMPL_ATTR_NORETURN() +RBIMPL_ATTR_NONNULL((2)) +/** + * @private + * + * Fails with the given object's type incompatibility to the type. + * + * This is an implementation detail of Check_Type. People don't use it + * directly. + * + * @param[in] obj The object in question. + * @param[in] expected Name of expected data type of `obj`. + */ +void rb_unexpected_object_type(VALUE obj, const char *expected); + +RBIMPL_ATTR_NORETURN() +RBIMPL_ATTR_NONNULL(()) +/** + * @private + * + * Fails with the given object's type incompatibility to the type. + * + * This is an implementation detail of #TypedData_Make_Struct. People don't + * use it directly. + * + * @param[in] actual Actual data type. + * @param[in] expected Expected data type. + */ +void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected); RBIMPL_SYMBOL_EXPORT_END() +#if RUBY_DEBUG +# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \ + while (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { \ + rb_unexpected_object_type(obj, "Data"); \ + unreachable; \ + } +#else +# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \ + RBIMPL_ASSERT_NOTHING +#endif + /** * Converts sval, a pointer to your struct, into a Ruby object. * @@ -464,14 +558,13 @@ RBIMPL_SYMBOL_EXPORT_END() */ #define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \ VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \ - (sval) = (type *)RTYPEDDATA_GET_DATA(result); \ + (sval) = RBIMPL_CAST((type *)rbimpl_typeddata_get_data(result)); \ RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval)) /** * Identical to #TypedData_Wrap_Struct, except it allocates a new data region * internally instead of taking an existing one. The allocation is done using - * ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to - * be anything other than ::RUBY_TYPED_DEFAULT_FREE. + * ruby_calloc(). * * @param klass Ruby level class of the object. * @param type Type name of the C struct. @@ -502,47 +595,36 @@ RBIMPL_SYMBOL_EXPORT_END() sizeof(type)) #endif -/** - * Obtains a C struct from inside of a wrapper Ruby object. - * - * @param obj An instance of ::RTypedData. - * @param type Type name of the C struct. - * @param data_type The data type describing `type`. - * @param sval Variable name of obtained C struct. - * @exception rb_eTypeError `obj` is not a kind of `data_type`. - * @return Unwrapped C struct that `obj` holds. - */ -#define TypedData_Get_Struct(obj,type,data_type,sval) \ - ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type)))) +static inline bool +rbimpl_typeddata_embedded_p(VALUE obj) +{ + return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED; +} +RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() static inline bool RTYPEDDATA_EMBEDDED_P(VALUE obj) { -#if RUBY_DEBUG - if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { - Check_Type(obj, RUBY_T_DATA); - RBIMPL_UNREACHABLE_RETURN(false); - } -#endif + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); - return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED; + return rbimpl_typeddata_embedded_p(obj); } static inline void * -RTYPEDDATA_GET_DATA(VALUE obj) +rbimpl_typeddata_get_data(VALUE obj) { -#if RUBY_DEBUG - if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { - Check_Type(obj, RUBY_T_DATA); - RBIMPL_UNREACHABLE_RETURN(false); - } -#endif + /* We reuse the data pointer in embedded TypedData. */ + return rbimpl_typeddata_embedded_p(obj) ? + RBIMPL_CAST((void *)&RTYPEDDATA(obj)->data) : + RTYPEDDATA_DATA(obj); +} - /* We reuse the data pointer in embedded TypedData. We can't use offsetof - * since RTypedData a non-POD type in C++. */ - const size_t embedded_typed_data_size = sizeof(struct RTypedData) - sizeof(void *); +static inline void * +RTYPEDDATA_GET_DATA(VALUE obj) +{ + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL)); - return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data; + return rbimpl_typeddata_get_data(obj); } RBIMPL_ATTR_PURE() @@ -550,47 +632,41 @@ RBIMPL_ATTR_ARTIFICIAL() /** * @private * - * This is an implementation detail of Check_Type(). People don't use it - * directly. + * Checks whether the passed object is ::RTypedData. + * + * This is an implementation detail of inline functions defined in this file. + * People don't use it directly. * * @param[in] obj Object in question * @retval true `obj` is an instance of ::RTypedData. - * @retval false `obj` is an instance of ::RData. - * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. + * @retval false `obj` is not an instance of ::RTypedData */ static inline bool -rbimpl_rtypeddata_p(VALUE obj) +rbimpl_obj_typeddata_p(VALUE obj) { - VALUE typed_flag = RTYPEDDATA(obj)->typed_flag; - return typed_flag != 0 && typed_flag <= 3; + return RB_TYPE_P(obj, RUBY_T_DATA); } RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() /** - * Checks whether the passed object is ::RTypedData or ::RData. + * Checks whether the passed object is ::RTypedData. * * @param[in] obj Object in question - * @retval true `obj` is an instance of ::RTypedData. - * @retval false `obj` is an instance of ::RData. + * @retval true * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. */ static inline bool RTYPEDDATA_P(VALUE obj) { -#if RUBY_DEBUG - if (RB_UNLIKELY(! RB_TYPE_P(obj, RUBY_T_DATA))) { - Check_Type(obj, RUBY_T_DATA); - RBIMPL_UNREACHABLE_RETURN(false); - } -#endif + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); - return rbimpl_rtypeddata_p(obj); + return true; } RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() -/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */ +RBIMPL_ATTR_RETURNS_NONNULL() /** * Queries for the type of given object. * @@ -598,20 +674,93 @@ RBIMPL_ATTR_ARTIFICIAL() * @return Data type struct that corresponds to `obj`. * @pre `obj` must be an instance of ::RTypedData. */ -static inline const struct rb_data_type_struct * +static inline const rb_data_type_t * RTYPEDDATA_TYPE(VALUE obj) { -#if RUBY_DEBUG - if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) { - rb_unexpected_type(obj, RUBY_T_DATA); - RBIMPL_UNREACHABLE_RETURN(NULL); + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL)); + + VALUE type = RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK; + const rb_data_type_t *ptr = RBIMPL_CAST((const rb_data_type_t *)type); + RBIMPL_ASSERT_OR_ASSUME(ptr); + return ptr; +} + +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL(()) +static inline bool +rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent) +{ + do { + if (RB_LIKELY(child == parent)) return true; + } while ((child = child->parent) != NULL); + return false; +} +#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline + +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL((2)) +static inline bool +rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type) +{ + if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false; + return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type); +} +#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline + +RBIMPL_ATTR_ARTIFICIAL() +RBIMPL_ATTR_NONNULL((2)) +/** + * @private + * + * This is an implementation detail of TypedData_Get_Struct(). Don't use it + * directly. + */ +static inline void * +rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type) +{ + if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) { + rb_unexpected_object_type(obj, expected_type->wrap_struct_name); + } + + const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj); + if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){ + rb_unexpected_typeddata(actual_type, expected_type); } -#endif - return RTYPEDDATA(obj)->type; + return RTYPEDDATA_GET_DATA(obj); +} + +RBIMPL_ATTR_PURE_UNLESS_DEBUG() +RBIMPL_ATTR_ARTIFICIAL() +/** + * @private + * + * This is an implementation detail of RTYPEDDATA_DATA(). Don't use it + * directly. + */ +static inline VALUE +rbimpl_check_external_typeddata(VALUE obj) +{ + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); + RUBY_ASSERT(!rbimpl_typeddata_embedded_p(obj)); + return obj; } /** + * Obtains a C struct from inside of a wrapper Ruby object. + * + * @param obj An instance of ::RTypedData. + * @param type Type name of the C struct. + * @param data_type The data type describing `type`. + * @param sval Variable name of obtained C struct. + * @exception rb_eTypeError `obj` is not a kind of `data_type`. + * @return Unwrapped C struct that `obj` holds. + */ +#define TypedData_Get_Struct(obj,type,data_type,sval) \ + ((sval) = RBIMPL_CAST((type *)rbimpl_check_typeddata((obj), (data_type)))) + +RBIMPL_ATTR_NONNULL((2)) +/** * While we don't stop you from using this function, it seems to be an * implementation detail of #TypedData_Make_Struct, which is preferred over * this one. @@ -632,12 +781,4 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap, return result; } -RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap")) -/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */ -static inline VALUE -rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type) -{ - return rb_data_typed_object_wrap(klass, datap, type); -} - #endif /* RBIMPL_RTYPEDDATA_H */ |
