1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Simplify known class check for singletons

Singleton classes should only ever be attached to one object. This means
that checking for the object should be the same as checking for the
class. This should be slightly faster by avoiding one memory acccess as
well as allowing us to skip checking if the receiver is a heap object.

This will be most common for calling class methods.
This commit is contained in:
John Hawthorn 2021-06-17 11:29:28 -07:00 committed by Alan Wu
parent 8c68f112d8
commit 7d252186fe
2 changed files with 50 additions and 16 deletions

View file

@ -1153,3 +1153,34 @@ assert_equal '7', %q{
foo(5,2)
foo(5,2)
}
# Call to object with singleton
assert_equal '123', %q{
obj = Object.new
def obj.foo
123
end
def foo(obj)
obj.foo()
end
foo(obj)
foo(obj)
}
# Call to singleton class
assert_equal '123', %q{
class Foo
def self.foo
123
end
end
def foo(obj)
obj.foo()
end
foo(Foo)
foo(Foo)
}

View file

@ -2172,6 +2172,7 @@ static bool
jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_t insn_opnd, const int max_chain_depth, uint8_t *side_exit)
{
val_type_t val_type = ctx_get_opnd_type(ctx, insn_opnd);
bool singleton_klass = FL_TEST(known_klass, FL_SINGLETON);
if (known_klass == rb_cNilClass) {
if (val_type.type != ETYPE_NIL) {
@ -2190,7 +2191,6 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_
ctx_set_opnd_type(ctx, insn_opnd, TYPE_TRUE);
}
}
else if (known_klass == rb_cFalseClass) {
if (val_type.type != ETYPE_FALSE) {
@ -2202,15 +2202,26 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_
ctx_set_opnd_type(ctx, insn_opnd, TYPE_FALSE);
}
}
else {
// Can't guard for for these classes because some of they are sometimes immediate (special const).
// Can remove this by adding appropriate dynamic checks.
if (known_klass == rb_cInteger ||
else if (known_klass == rb_cInteger ||
known_klass == rb_cSymbol ||
known_klass == rb_cFloat) {
// Can't guard for for these classes because some of they are sometimes
// immediate (special const). Can remove this by adding appropriate
// dynamic checks.
return false;
}
else if (singleton_klass) {
// Singleton classes are attached to one specific object, so we can
// avoid one memory access (and potentially the is_heap check) by
// looking for the expected object directly.
ADD_COMMENT(cb, "guard known object with singleton class");
VALUE known_obj = rb_attr_get(known_klass, id__attached__);
// TODO: jit_mov_gc_ptr keeps a strong reference, which leaks the object.
jit_mov_gc_ptr(jit, cb, REG1, known_obj);
cmp(cb, REG0, REG1);
jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
}
else {
// Check that the receiver is a heap object
// Note: if we get here, the class doesn't have immediate instances.
if (!val_type.is_heap) {
@ -2234,14 +2245,6 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_
jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
}
// Pointer to the klass field of the receiver &(recv->klass)
x86opnd_t klass_opnd = mem_opnd(64, REG0, offsetof(struct RBasic, klass));
// Bail if receiver class is different from known_klass
// TODO: jit_mov_gc_ptr keeps a strong reference, which leaks the class.
jit_mov_gc_ptr(jit, cb, REG1, known_klass);
cmp(cb, klass_opnd, REG1);
jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
return true;
}