diff options
Diffstat (limited to 'include/ruby/internal/core')
| -rw-r--r-- | include/ruby/internal/core/rarray.h | 4 | ||||
| -rw-r--r-- | include/ruby/internal/core/rbasic.h | 34 | ||||
| -rw-r--r-- | include/ruby/internal/core/rclass.h | 2 | ||||
| -rw-r--r-- | include/ruby/internal/core/rdata.h | 35 | ||||
| -rw-r--r-- | include/ruby/internal/core/robject.h | 40 | ||||
| -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 | 257 |
8 files changed, 263 insertions, 178 deletions
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index 90690fe794..73cc0f5dd9 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -80,6 +80,8 @@ * here is at least incomplete. */ enum ruby_rarray_flags { + /* RUBY_FL_USER0 is for ELTS_SHARED */ + /** * This flag has something to do with memory footprint. If the array is * "small" enough, ruby tries to be creative to abuse padding bits of @@ -99,8 +101,6 @@ enum ruby_rarray_flags { */ RARRAY_EMBED_FLAG = RUBY_FL_USER1, - /* RUBY_FL_USER2 is for ELTS_SHARED */ - /** * When an array employs embedded strategy (see ::RARRAY_EMBED_FLAG), these * bits are used to store the number of elements actually filled into diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h index 4617f743a7..63cdff8e09 100644 --- a/include/ruby/internal/core/rbasic.h +++ b/include/ruby/internal/core/rbasic.h @@ -55,23 +55,27 @@ 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's object's, base components. Every single ruby objects have them in - * common. + * Ruby object's base components. All Ruby objects have them in common. */ struct RUBY_ALIGNAS(SIZEOF_VALUE) RBasic { /** - * Per-object flags. Each ruby objects have their own characteristics - * apart from their classes. For instance whether an object is frozen or - * not is not controlled by its class. This is where such properties are - * stored. + * Per-object flags. Each Ruby object has its own characteristics apart + * from its class. For instance, whether an object is frozen or not is not + * controlled by its class. This is where such properties are stored. * * @see enum ::ruby_fl_type * - * @note This is ::VALUE rather than an enum for alignment purpose. Back + * @note This is ::VALUE rather than an enum for alignment purposes. Back * in the 1990s there were no such thing like `_Alignas` in C. */ VALUE flags; @@ -79,14 +83,18 @@ RBasic { /** * Class of an object. Every object has its class. Also, everything is an * object in Ruby. This means classes are also objects. Classes have - * their own classes, classes of classes have their classes, too ... and - * it recursively continues forever. + * their own classes, classes of classes have their classes too, and it + * recursively continues forever. * - * Also note the `const` qualifier. In ruby an object cannot "change" its + * Also note the `const` qualifier. In Ruby, an object cannot "change" its * class. */ const VALUE klass; +#if RBASIC_SHAPE_ID_FIELD + VALUE shape_id; +#endif + #ifdef __cplusplus public: RBIMPL_ATTR_CONSTEXPR(CXX11) @@ -102,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 43ab3c01e7..cee5e7b5ea 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -37,12 +37,8 @@ #include "ruby/defines.h" /** @cond INTERNAL_MACRO */ -#ifdef RUBY_UNTYPED_DATA_WARNING -# /* Take that. */ -#elif defined(RUBY_EXPORT) -# define RUBY_UNTYPED_DATA_WARNING 1 -#else -# define RUBY_UNTYPED_DATA_WARNING 0 +#ifndef RUBY_UNTYPED_DATA_WARNING +#define RUBY_UNTYPED_DATA_WARNING 1 #endif #define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f)) @@ -146,7 +142,10 @@ struct RData { */ RUBY_DATA_FUNC dfree; - /** Pointer to the actual C level struct that you want to wrap. */ + /** Pointer to the actual C level struct that you want to wrap. + * This is after dmark and dfree to allow DATA_PTR to continue to work for + * both RData and non-embedded RTypedData. + */ void *data; }; @@ -181,11 +180,6 @@ VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_D */ 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() /** @@ -331,15 +325,6 @@ rb_data_object_get_warning(VALUE obj) return rb_data_object_get(obj); } -#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P) -# define rb_data_object_wrap_warning(klass, ptr, mark, free) \ - RB_GNUC_EXTENSION( \ - __builtin_choose_expr( \ - __builtin_constant_p(klass) && !(klass), \ - rb_data_object_wrap(klass, ptr, mark, free), \ - (rb_data_object_wrap_warning)(klass, ptr, mark, free))) -#endif - /** * This is an implementation detail of #Data_Make_Struct. People don't use it * directly. @@ -361,14 +346,6 @@ rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_f 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 diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index c2bcae6306..99f6470ac1 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,17 +96,7 @@ struct RObject { */ struct { /** Pointer to a C array that holds instance variables. */ - VALUE *ivptr; - - /** - * This is a table that holds instance variable name to index - * mapping. Used when accessing instance variables using names. - * - * @internal - * - * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`. - */ - struct rb_id_table *iv_index_tbl; + VALUE *fields; } heap; /* Embedded instance variables. When an object is small enough, it @@ -133,17 +125,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 c7904746fd..ec0794e387 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -37,6 +37,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" @@ -108,11 +109,17 @@ /** @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_PROMOTED1 RUBY_TYPED_PROMOTED1 -/** @endcond */ /** * @private @@ -137,6 +144,8 @@ rbimpl_typeddata_flags { */ RUBY_TYPED_FREE_IMMEDIATELY = 1, + RUBY_TYPED_EMBEDDABLE = 2, + /** * This flag has something to do with Ractor. Multiple Ractors run without * protecting each other. Sharing an object among Ractors is basically @@ -151,6 +160,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 @@ -173,9 +188,9 @@ rbimpl_typeddata_flags { RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */ /** - * This flag no longer in use + * This flag is used to distinguish RTypedData from deprecated RData objects. */ - RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6, + RUBY_TYPED_FL_IS_TYPED_DATA = RUBY_FL_USERPRIV0, /** * This flag determines whether marking and compaction should be carried out @@ -247,10 +262,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; @@ -348,24 +368,28 @@ 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(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data)); +#endif + RBIMPL_SYMBOL_EXPORT_BEGIN() RBIMPL_ATTR_NONNULL((3)) /** @@ -380,6 +404,7 @@ 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 @@ -395,6 +420,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. * @@ -409,6 +435,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. * @@ -419,6 +446,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. @@ -430,8 +458,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. * @@ -460,14 +529,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) = RBIMPL_CAST((type *)RTYPEDDATA_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. @@ -498,18 +566,37 @@ 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) +{ + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false)); + + return rbimpl_typeddata_embedded_p(obj); +} + +static inline void * +rbimpl_typeddata_get_data(VALUE obj) +{ + /* We reuse the data pointer in embedded TypedData. */ + return rbimpl_typeddata_embedded_p(obj) ? + RBIMPL_CAST((void *)&RTYPEDDATA_DATA(obj)) : + RTYPEDDATA_DATA(obj); +} + +static inline void * +RTYPEDDATA_GET_DATA(VALUE obj) +{ + RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL)); + + return rbimpl_typeddata_get_data(obj); +} RBIMPL_ATTR_PURE() RBIMPL_ATTR_ARTIFICIAL() @@ -527,7 +614,28 @@ RBIMPL_ATTR_ARTIFICIAL() static inline bool rbimpl_rtypeddata_p(VALUE obj) { - return RTYPEDDATA(obj)->typed_flag == 1; + return FL_TEST_RAW(obj, RUBY_TYPED_FL_IS_TYPED_DATA); +} + +RBIMPL_ATTR_PURE() +RBIMPL_ATTR_ARTIFICIAL() +/** + * @private + * + * Identical to rbimpl_rtypeddata_p(), except it is allowed to call on non-data + * objects. + * + * 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 not an instance of ::RTypedData + */ +static inline bool +rbimpl_obj_typeddata_p(VALUE obj) +{ + return RB_TYPE_P(obj, RUBY_T_DATA) && rbimpl_rtypeddata_p(obj); } RBIMPL_ATTR_PURE_UNLESS_DEBUG() @@ -543,19 +651,14 @@ RBIMPL_ATTR_ARTIFICIAL() 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); } 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. * @@ -563,19 +666,77 @@ 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); } -#endif - return RTYPEDDATA(obj)->type; + 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); + } + + return RTYPEDDATA_GET_DATA(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 @@ -597,12 +758,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 */ |
