Move `attached_object` into `rb_classext_struct`

Given that signleton classes don't have an allocator,
we can re-use these bytes to store the attached object
in `rb_classext_struct` without making it larger.
This commit is contained in:
Jean Boussier 2023-02-15 15:18:01 +01:00 коммит произвёл Jean Boussier
Родитель 1df75d6586
Коммит 1a4b4cd7f8
9 изменённых файлов: 152 добавлений и 121 удалений

Просмотреть файл

@ -221,7 +221,7 @@ class_alloc(VALUE flags, VALUE klass)
*/
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
RB_OBJ_WRITE(obj, &RCLASS_REFINED_CLASS(obj), Qnil);
RCLASS_ALLOCATOR(obj) = 0;
RCLASS_SET_ALLOCATOR((VALUE)obj, NULL);
return (VALUE)obj;
}
@ -514,7 +514,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
}
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(orig);
RCLASS_SET_ALLOCATOR(clone, RCLASS_ALLOCATOR(orig));
copy_tables(clone, orig);
if (RCLASS_M_TBL(orig)) {
struct clone_method_arg arg;
@ -550,7 +550,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
prev_clone_p = clone_p;
RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
RCLASS_SET_ALLOCATOR(clone_p, RCLASS_ALLOCATOR(p));
if (RB_TYPE_P(clone, T_CLASS)) {
RCLASS_SET_INCLUDER(clone_p, clone);
}
@ -635,7 +635,6 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
}
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
rb_iv_tbl_copy(clone, klass);
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;

Просмотреть файл

@ -25,7 +25,6 @@ firstline, predefined = __LINE__+1, %[\
lambda
send
__send__
__attached__
__recursive_key__
initialize
initialize_copy

8
gc.c
Просмотреть файл

@ -7264,6 +7264,10 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
if (FL_TEST(obj, FL_SINGLETON)) {
gc_mark(objspace, RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER(obj)) {
gc_mark(objspace, RCLASS_SUPER(obj));
@ -10566,6 +10570,10 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
if (FL_TEST(obj, FL_SINGLETON)) {
UPDATE_IF_MOVED(objspace, RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);

Просмотреть файл

@ -53,7 +53,14 @@ struct rb_classext_struct {
struct rb_subclass_entry *module_subclass_entry;
const VALUE origin_;
const VALUE refined_class;
rb_alloc_func_t allocator;
union {
struct {
rb_alloc_func_t allocator;
} class;
struct {
VALUE attached_object;
} singleton_class;
} as;
const VALUE includer;
#if !SHAPE_IN_BASIC_FLAGS
shape_id_t shape_id;
@ -97,11 +104,10 @@ STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
#define RCLASS_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->subclass_entry)
#define RCLASS_MODULE_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->module_subclass_entry)
#define RCLASS_ALLOCATOR(c) (RCLASS_EXT(c)->allocator)
#define RCLASS_SUBCLASSES(c) (RCLASS_EXT(c)->subclasses)
#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT(c)->superclass_depth)
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT(c)->superclasses)
#define RCLASS_ATTACHED_OBJECT(c) (rb_attr_get(c, id__attached__))
#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT(c)->as.singleton_class.attached_object)
#define RICLASS_IS_ORIGIN FL_USER0
#define RCLASS_CLONED FL_USER1
@ -147,6 +153,22 @@ VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
MJIT_SYMBOL_EXPORT_END
static inline rb_alloc_func_t
RCLASS_ALLOCATOR(VALUE klass)
{
if (FL_TEST_RAW(klass, FL_SINGLETON)) {
return NULL;
}
return RCLASS_EXT(klass)->as.class.allocator;
}
static inline void
RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
{
assert(!FL_TEST(klass, FL_SINGLETON));
RCLASS_EXT(klass)->as.class.allocator = allocator;
}
static inline void
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
{
@ -204,9 +226,9 @@ static inline VALUE
RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
{
assert(BUILTIN_TYPE(klass) == T_CLASS);
assert(FL_TEST(klass, FL_SINGLETON));
assert(FL_TEST_RAW(klass, FL_SINGLETON));
rb_class_ivar_set(klass, id__attached__, attached_object);
RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object);
return attached_object;
}

Просмотреть файл

@ -523,7 +523,7 @@ hash_each(VALUE key, VALUE value, VALUE v)
#define SINGLETON_DUMP_UNABLE_P(klass) \
(rb_id_table_size(RCLASS_M_TBL(klass)) > 0 || \
rb_ivar_count(klass) > 1)
rb_ivar_count(klass) > 0)
static void
w_extended(VALUE klass, struct dump_arg *arg, int check)

Просмотреть файл

@ -1151,7 +1151,10 @@ void
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
{
Check_Type(klass, T_CLASS);
RCLASS_ALLOCATOR(klass) = func;
if (FL_TEST_RAW(klass, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't define an allocator for a singleton class");
}
RCLASS_SET_ALLOCATOR(klass, func);
}
void

Просмотреть файл

@ -141,6 +141,7 @@ fn main() {
.allowlist_function("rb_ary_tmp_new_from_values")
// From include/ruby/internal/intern/class.h
.allowlist_function("rb_class_attached_object")
.allowlist_function("rb_singleton_class")
// From include/ruby/internal/core/rclass.h

Просмотреть файл

@ -3863,7 +3863,7 @@ fn jit_guard_known_klass(
}
} else if unsafe {
FL_TEST(known_klass, VALUE(RUBY_FL_SINGLETON as usize)) != VALUE(0)
&& sample_instance == rb_attr_get(known_klass, id__attached__ as ID)
&& sample_instance == rb_class_attached_object(known_klass)
} {
// Singleton classes are attached to one specific object, so we can
// avoid one memory access (and potentially the is_heap check) by

Просмотреть файл

@ -377,66 +377,65 @@ pub const tProc: ruby_method_ids = 190;
pub const tLambda: ruby_method_ids = 191;
pub const tSend: ruby_method_ids = 192;
pub const t__send__: ruby_method_ids = 193;
pub const t__attached__: ruby_method_ids = 194;
pub const t__recursive_key__: ruby_method_ids = 195;
pub const tInitialize: ruby_method_ids = 196;
pub const tInitialize_copy: ruby_method_ids = 197;
pub const tInitialize_clone: ruby_method_ids = 198;
pub const tInitialize_dup: ruby_method_ids = 199;
pub const tTo_int: ruby_method_ids = 200;
pub const tTo_ary: ruby_method_ids = 201;
pub const tTo_str: ruby_method_ids = 202;
pub const tTo_sym: ruby_method_ids = 203;
pub const tTo_hash: ruby_method_ids = 204;
pub const tTo_proc: ruby_method_ids = 205;
pub const tTo_io: ruby_method_ids = 206;
pub const tTo_a: ruby_method_ids = 207;
pub const tTo_s: ruby_method_ids = 208;
pub const tTo_i: ruby_method_ids = 209;
pub const tTo_f: ruby_method_ids = 210;
pub const tTo_r: ruby_method_ids = 211;
pub const tBt: ruby_method_ids = 212;
pub const tBt_locations: ruby_method_ids = 213;
pub const tCall: ruby_method_ids = 214;
pub const tMesg: ruby_method_ids = 215;
pub const tException: ruby_method_ids = 216;
pub const tLocals: ruby_method_ids = 217;
pub const tNOT: ruby_method_ids = 218;
pub const tAND: ruby_method_ids = 219;
pub const tOR: ruby_method_ids = 220;
pub const tDiv: ruby_method_ids = 221;
pub const tDivmod: ruby_method_ids = 222;
pub const tFdiv: ruby_method_ids = 223;
pub const tQuo: ruby_method_ids = 224;
pub const tName: ruby_method_ids = 225;
pub const tNil: ruby_method_ids = 226;
pub const tPath: ruby_method_ids = 227;
pub const tUScore: ruby_method_ids = 228;
pub const tNUMPARAM_1: ruby_method_ids = 229;
pub const tNUMPARAM_2: ruby_method_ids = 230;
pub const tNUMPARAM_3: ruby_method_ids = 231;
pub const tNUMPARAM_4: ruby_method_ids = 232;
pub const tNUMPARAM_5: ruby_method_ids = 233;
pub const tNUMPARAM_6: ruby_method_ids = 234;
pub const tNUMPARAM_7: ruby_method_ids = 235;
pub const tNUMPARAM_8: ruby_method_ids = 236;
pub const tNUMPARAM_9: ruby_method_ids = 237;
pub const tDefault: ruby_method_ids = 238;
pub const tTOKEN_LOCAL_END: ruby_method_ids = 239;
pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 238;
pub const tTOKEN_INSTANCE_END: ruby_method_ids = 239;
pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 238;
pub const tLASTLINE: ruby_method_ids = 239;
pub const tBACKREF: ruby_method_ids = 240;
pub const tERROR_INFO: ruby_method_ids = 241;
pub const tTOKEN_GLOBAL_END: ruby_method_ids = 242;
pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 241;
pub const tTOKEN_CONST_END: ruby_method_ids = 242;
pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 241;
pub const tTOKEN_CLASS_END: ruby_method_ids = 242;
pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 241;
pub const tTOKEN_ATTRSET_END: ruby_method_ids = 242;
pub const tNEXT_ID: ruby_method_ids = 242;
pub const t__recursive_key__: ruby_method_ids = 194;
pub const tInitialize: ruby_method_ids = 195;
pub const tInitialize_copy: ruby_method_ids = 196;
pub const tInitialize_clone: ruby_method_ids = 197;
pub const tInitialize_dup: ruby_method_ids = 198;
pub const tTo_int: ruby_method_ids = 199;
pub const tTo_ary: ruby_method_ids = 200;
pub const tTo_str: ruby_method_ids = 201;
pub const tTo_sym: ruby_method_ids = 202;
pub const tTo_hash: ruby_method_ids = 203;
pub const tTo_proc: ruby_method_ids = 204;
pub const tTo_io: ruby_method_ids = 205;
pub const tTo_a: ruby_method_ids = 206;
pub const tTo_s: ruby_method_ids = 207;
pub const tTo_i: ruby_method_ids = 208;
pub const tTo_f: ruby_method_ids = 209;
pub const tTo_r: ruby_method_ids = 210;
pub const tBt: ruby_method_ids = 211;
pub const tBt_locations: ruby_method_ids = 212;
pub const tCall: ruby_method_ids = 213;
pub const tMesg: ruby_method_ids = 214;
pub const tException: ruby_method_ids = 215;
pub const tLocals: ruby_method_ids = 216;
pub const tNOT: ruby_method_ids = 217;
pub const tAND: ruby_method_ids = 218;
pub const tOR: ruby_method_ids = 219;
pub const tDiv: ruby_method_ids = 220;
pub const tDivmod: ruby_method_ids = 221;
pub const tFdiv: ruby_method_ids = 222;
pub const tQuo: ruby_method_ids = 223;
pub const tName: ruby_method_ids = 224;
pub const tNil: ruby_method_ids = 225;
pub const tPath: ruby_method_ids = 226;
pub const tUScore: ruby_method_ids = 227;
pub const tNUMPARAM_1: ruby_method_ids = 228;
pub const tNUMPARAM_2: ruby_method_ids = 229;
pub const tNUMPARAM_3: ruby_method_ids = 230;
pub const tNUMPARAM_4: ruby_method_ids = 231;
pub const tNUMPARAM_5: ruby_method_ids = 232;
pub const tNUMPARAM_6: ruby_method_ids = 233;
pub const tNUMPARAM_7: ruby_method_ids = 234;
pub const tNUMPARAM_8: ruby_method_ids = 235;
pub const tNUMPARAM_9: ruby_method_ids = 236;
pub const tDefault: ruby_method_ids = 237;
pub const tTOKEN_LOCAL_END: ruby_method_ids = 238;
pub const tTOKEN_INSTANCE_BEGIN: ruby_method_ids = 237;
pub const tTOKEN_INSTANCE_END: ruby_method_ids = 238;
pub const tTOKEN_GLOBAL_BEGIN: ruby_method_ids = 237;
pub const tLASTLINE: ruby_method_ids = 238;
pub const tBACKREF: ruby_method_ids = 239;
pub const tERROR_INFO: ruby_method_ids = 240;
pub const tTOKEN_GLOBAL_END: ruby_method_ids = 241;
pub const tTOKEN_CONST_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_CONST_END: ruby_method_ids = 241;
pub const tTOKEN_CLASS_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_CLASS_END: ruby_method_ids = 241;
pub const tTOKEN_ATTRSET_BEGIN: ruby_method_ids = 240;
pub const tTOKEN_ATTRSET_END: ruby_method_ids = 241;
pub const tNEXT_ID: ruby_method_ids = 241;
pub const idMax: ruby_method_ids = 2721;
pub const idMin: ruby_method_ids = 2737;
pub const idFreeze: ruby_method_ids = 2753;
@ -461,54 +460,53 @@ pub const idProc: ruby_method_ids = 3041;
pub const idLambda: ruby_method_ids = 3057;
pub const idSend: ruby_method_ids = 3073;
pub const id__send__: ruby_method_ids = 3089;
pub const id__attached__: ruby_method_ids = 3105;
pub const id__recursive_key__: ruby_method_ids = 3121;
pub const idInitialize: ruby_method_ids = 3137;
pub const idInitialize_copy: ruby_method_ids = 3153;
pub const idInitialize_clone: ruby_method_ids = 3169;
pub const idInitialize_dup: ruby_method_ids = 3185;
pub const idTo_int: ruby_method_ids = 3201;
pub const idTo_ary: ruby_method_ids = 3217;
pub const idTo_str: ruby_method_ids = 3233;
pub const idTo_sym: ruby_method_ids = 3249;
pub const idTo_hash: ruby_method_ids = 3265;
pub const idTo_proc: ruby_method_ids = 3281;
pub const idTo_io: ruby_method_ids = 3297;
pub const idTo_a: ruby_method_ids = 3313;
pub const idTo_s: ruby_method_ids = 3329;
pub const idTo_i: ruby_method_ids = 3345;
pub const idTo_f: ruby_method_ids = 3361;
pub const idTo_r: ruby_method_ids = 3377;
pub const idBt: ruby_method_ids = 3393;
pub const idBt_locations: ruby_method_ids = 3409;
pub const idCall: ruby_method_ids = 3425;
pub const idMesg: ruby_method_ids = 3441;
pub const idException: ruby_method_ids = 3457;
pub const idLocals: ruby_method_ids = 3473;
pub const idNOT: ruby_method_ids = 3489;
pub const idAND: ruby_method_ids = 3505;
pub const idOR: ruby_method_ids = 3521;
pub const idDiv: ruby_method_ids = 3537;
pub const idDivmod: ruby_method_ids = 3553;
pub const idFdiv: ruby_method_ids = 3569;
pub const idQuo: ruby_method_ids = 3585;
pub const idName: ruby_method_ids = 3601;
pub const idNil: ruby_method_ids = 3617;
pub const idPath: ruby_method_ids = 3633;
pub const idUScore: ruby_method_ids = 3649;
pub const idNUMPARAM_1: ruby_method_ids = 3665;
pub const idNUMPARAM_2: ruby_method_ids = 3681;
pub const idNUMPARAM_3: ruby_method_ids = 3697;
pub const idNUMPARAM_4: ruby_method_ids = 3713;
pub const idNUMPARAM_5: ruby_method_ids = 3729;
pub const idNUMPARAM_6: ruby_method_ids = 3745;
pub const idNUMPARAM_7: ruby_method_ids = 3761;
pub const idNUMPARAM_8: ruby_method_ids = 3777;
pub const idNUMPARAM_9: ruby_method_ids = 3793;
pub const idDefault: ruby_method_ids = 3809;
pub const idLASTLINE: ruby_method_ids = 3831;
pub const idBACKREF: ruby_method_ids = 3847;
pub const idERROR_INFO: ruby_method_ids = 3863;
pub const id__recursive_key__: ruby_method_ids = 3105;
pub const idInitialize: ruby_method_ids = 3121;
pub const idInitialize_copy: ruby_method_ids = 3137;
pub const idInitialize_clone: ruby_method_ids = 3153;
pub const idInitialize_dup: ruby_method_ids = 3169;
pub const idTo_int: ruby_method_ids = 3185;
pub const idTo_ary: ruby_method_ids = 3201;
pub const idTo_str: ruby_method_ids = 3217;
pub const idTo_sym: ruby_method_ids = 3233;
pub const idTo_hash: ruby_method_ids = 3249;
pub const idTo_proc: ruby_method_ids = 3265;
pub const idTo_io: ruby_method_ids = 3281;
pub const idTo_a: ruby_method_ids = 3297;
pub const idTo_s: ruby_method_ids = 3313;
pub const idTo_i: ruby_method_ids = 3329;
pub const idTo_f: ruby_method_ids = 3345;
pub const idTo_r: ruby_method_ids = 3361;
pub const idBt: ruby_method_ids = 3377;
pub const idBt_locations: ruby_method_ids = 3393;
pub const idCall: ruby_method_ids = 3409;
pub const idMesg: ruby_method_ids = 3425;
pub const idException: ruby_method_ids = 3441;
pub const idLocals: ruby_method_ids = 3457;
pub const idNOT: ruby_method_ids = 3473;
pub const idAND: ruby_method_ids = 3489;
pub const idOR: ruby_method_ids = 3505;
pub const idDiv: ruby_method_ids = 3521;
pub const idDivmod: ruby_method_ids = 3537;
pub const idFdiv: ruby_method_ids = 3553;
pub const idQuo: ruby_method_ids = 3569;
pub const idName: ruby_method_ids = 3585;
pub const idNil: ruby_method_ids = 3601;
pub const idPath: ruby_method_ids = 3617;
pub const idUScore: ruby_method_ids = 3633;
pub const idNUMPARAM_1: ruby_method_ids = 3649;
pub const idNUMPARAM_2: ruby_method_ids = 3665;
pub const idNUMPARAM_3: ruby_method_ids = 3681;
pub const idNUMPARAM_4: ruby_method_ids = 3697;
pub const idNUMPARAM_5: ruby_method_ids = 3713;
pub const idNUMPARAM_6: ruby_method_ids = 3729;
pub const idNUMPARAM_7: ruby_method_ids = 3745;
pub const idNUMPARAM_8: ruby_method_ids = 3761;
pub const idNUMPARAM_9: ruby_method_ids = 3777;
pub const idDefault: ruby_method_ids = 3793;
pub const idLASTLINE: ruby_method_ids = 3815;
pub const idBACKREF: ruby_method_ids = 3831;
pub const idERROR_INFO: ruby_method_ids = 3847;
pub const tLAST_OP_ID: ruby_method_ids = 169;
pub const idLAST_OP_ID: ruby_method_ids = 10;
pub type ruby_method_ids = u32;
@ -1071,6 +1069,7 @@ pub const RUBY_OFFSET_RSTRING_EMBED_LEN: rstring_offsets = 16;
pub type rstring_offsets = u32;
pub type rb_seq_param_keyword_struct = rb_iseq_constant_body__bindgen_ty_1_rb_iseq_param_keyword;
extern "C" {
pub fn rb_class_attached_object(klass: VALUE) -> VALUE;
pub fn rb_singleton_class(obj: VALUE) -> VALUE;
pub fn rb_get_alloc_func(klass: VALUE) -> rb_alloc_func_t;
pub fn rb_method_basic_definition_p(klass: VALUE, mid: ID) -> ::std::os::raw::c_int;