Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions benchmark/object_class.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
prelude: |
def get_class(obj)
i = 10_000
while i > 0
i -= 1
# 100 times per loop
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class;
end
end
class Obj
end
obj = Obj.new
singleton = Obj.new
def singleton.bar
end
extended = Obj.new
2.times do
extended.extend Module.new
end
immediate = 1.4
benchmark:
obj: get_class(obj)
extended: get_class(extended)
singleton: get_class(singleton)
immediate: get_class(immediate)
loop_count: 1000
6 changes: 4 additions & 2 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,17 @@
* 0: RCLASS_IS_ROOT
* The class has been added to the VM roots. Will always be marked and pinned.
* This is done for classes defined from C to allow storing them in global variables.
* 1: RMODULE_IS_REFINEMENT
* Module is used for refinements.
* 1: <reserved>
* Ensures that RUBY_FL_SINGLETON is never set on a T_MODULE. See `rb_class_real`.
* 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
* This module's prime classext is the only classext and writable from any namespaces.
* If unset, the prime classext is writable only from the root namespace.
* 3: RCLASS_IS_INITIALIZED
* Module has been initialized.
* 4: RCLASS_NAMESPACEABLE
* Is a builtin class that may be namespaced. It larger than a normal class.
* 5: RMODULE_IS_REFINEMENT
* Module is used for refinements.
*/

#define METACLASS_OF(k) RBASIC(k)->klass
Expand Down
2 changes: 1 addition & 1 deletion kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Kernel
#
def class
Primitive.attr! :leaf
Primitive.cexpr! 'rb_obj_class(self)'
Primitive.cexpr! 'rb_obj_class_must(self)'
end

#
Expand Down
38 changes: 34 additions & 4 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,20 +278,50 @@ rb_obj_not_equal(VALUE obj1, VALUE obj2)
return rb_obj_not(result);
}

static inline VALUE
fake_class_p(VALUE klass)
{
RUBY_ASSERT(klass);
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
STATIC_ASSERT(t_iclass_overlap_t_class, !(T_CLASS & T_ICLASS));
STATIC_ASSERT(t_iclass_overlap_t_module, !(T_MODULE & T_ICLASS));

return FL_TEST_RAW(klass, T_ICLASS | FL_SINGLETON);
}

static inline VALUE
class_real(VALUE cl)
{
RUBY_ASSERT(cl);
while (RB_UNLIKELY(fake_class_p(cl))) {
cl = RCLASS_SUPER(cl);
}
return cl;
}

VALUE
rb_class_real(VALUE cl)
{
while (cl &&
(RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) {
cl = RCLASS_SUPER(cl);
if (cl) {
cl = class_real(cl);
}
return cl;
}

VALUE
rb_obj_class(VALUE obj)
{
return rb_class_real(CLASS_OF(obj));
VALUE cl = CLASS_OF(obj);
if (cl) {
cl = class_real(cl);
}
return cl;
}

static inline VALUE
rb_obj_class_must(VALUE obj)
{
return class_real(CLASS_OF(obj));
}

/*
Expand Down