diff --git a/gc.c b/gc.c index 6e4c7ff74be1b9..e7251727a1c766 100644 --- a/gc.c +++ b/gc.c @@ -1064,7 +1064,7 @@ rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FU { RUBY_ASSERT_ALWAYS(dfree != (RUBY_DATA_FUNC)1); if (klass) rb_data_object_check(klass); - return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, !dmark, sizeof(struct RTypedData)); + return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)datap, (VALUE)dfree, !dmark, sizeof(struct RTypedData)); } VALUE @@ -1081,7 +1081,7 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_ RBIMPL_NONNULL_ARG(type); if (klass) rb_data_object_check(klass); bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark; - return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)type, 1 | typed_flag, (VALUE)datap, wb_protected, size); + return newobj_of(GET_RACTOR(), klass, T_DATA, ((VALUE)type) | IS_TYPED_DATA | typed_flag, (VALUE)datap, 0, wb_protected, size); } VALUE @@ -1177,8 +1177,8 @@ rb_data_free(void *objspace, VALUE obj) void (*dfree)(void *); if (RTYPEDDATA_P(obj)) { - free_immediately = (RTYPEDDATA(obj)->type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0; - dfree = RTYPEDDATA(obj)->type->function.dfree; + free_immediately = (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0; + dfree = RTYPEDDATA_TYPE(obj)->function.dfree; } else { dfree = RDATA(obj)->dfree; @@ -2660,7 +2660,7 @@ rb_gc_mark_roots(void *objspace, const char **categoryp) #undef MARK_CHECKPOINT } -#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA(d)->type->function.dmark +#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark void rb_gc_mark_children(void *objspace, VALUE obj) @@ -2780,7 +2780,7 @@ rb_gc_mark_children(void *objspace, VALUE obj) void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj); if (ptr) { - if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) { + if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj); for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) { @@ -2789,7 +2789,7 @@ rb_gc_mark_children(void *objspace, VALUE obj) } else { RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ? - RTYPEDDATA(obj)->type->function.dmark : + RTYPEDDATA_TYPE(obj)->function.dmark : RDATA(obj)->dmark; if (mark_func) (*mark_func)(ptr); } @@ -3717,7 +3717,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj) { void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj); if (ptr) { - if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) { + if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) { size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj); for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) { @@ -3726,7 +3726,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj) } } else if (RTYPEDDATA_P(obj)) { - RUBY_DATA_FUNC compact_func = RTYPEDDATA(obj)->type->function.dcompact; + RUBY_DATA_FUNC compact_func = RTYPEDDATA_TYPE(obj)->function.dcompact; if (compact_func) (*compact_func)(ptr); } } diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h index e4c146a716a8bb..cab412af7229b9 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -133,6 +133,12 @@ struct RData { */ RUBY_DATA_FUNC dmark; + /** Pointer to the actual C level struct that you want to wrap. + * This is in between dmark and dfree to allow DATA_PTR to continue + * to work for both RData and non-embedded RTypedData. + */ + void *data; + /** * This function is called when the object is no longer used. You need to * do whatever necessary to avoid memory leaks. @@ -141,9 +147,6 @@ struct RData { * 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() diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index 6c19576c2007e6..b576be779fb539 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -114,7 +114,10 @@ #define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1 /** @endcond */ -#define TYPED_DATA_EMBEDDED 2 +#define IS_TYPED_DATA ((VALUE)1) +#define TYPED_DATA_EMBEDDED ((VALUE)2) +#define TYPED_DATA_PTR_FLAGS ((VALUE)3) +#define TYPED_DATA_PTR_MASK (~TYPED_DATA_PTR_FLAGS) /** * @private @@ -353,18 +356,16 @@ struct RTypedData { struct RBasic basic; /** + * This is a `const rb_data_type_t *const` value, with the low bits set: + * + * 1: Always set, to differentiate RTypedData from RData. + * 2: 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; @@ -525,7 +526,7 @@ RTYPEDDATA_EMBEDDED_P(VALUE obj) } #endif - return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED; + return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED; } static inline void * @@ -561,8 +562,7 @@ RBIMPL_ATTR_ARTIFICIAL() static inline bool rbimpl_rtypeddata_p(VALUE obj) { - VALUE typed_flag = RTYPEDDATA(obj)->typed_flag; - return typed_flag != 0 && typed_flag <= 3; + return RTYPEDDATA(obj)->type & IS_TYPED_DATA; } RBIMPL_ATTR_PURE_UNLESS_DEBUG() @@ -608,7 +608,7 @@ RTYPEDDATA_TYPE(VALUE obj) } #endif - return RTYPEDDATA(obj)->type; + return (const struct rb_data_type_struct *)(RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK); } /**