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
67 changes: 65 additions & 2 deletions benchmark/vm_ivar_get.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,75 @@
prelude: |
class Example
def initialize
@levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
end

def get_value_loop
sum = 0

i = 0
while i < 100_000
# 10 times to de-emphasize loop overhead
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
i += 1
end

return sum
end

@levar = 1
@v0 = 1
@v1 = 2
@v3 = 3

def self.get_value_loop
sum = 0

i = 0
while i < 100_000
# 10 times to de-emphasize loop overhead
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
sum += @levar
i += 1
end

return sum
end
end

class GenExample < Time
def initialize
@levar = 1
@v0 = 1
@v1 = 2
@v3 = 3
end

def get_value_loop
sum = 0

i = 0
while i < 1000000
while i < 100_000
# 10 times to de-emphasize loop overhead
sum += @levar
sum += @levar
Expand All @@ -31,7 +89,12 @@ prelude: |
end

obj = Example.new
gen = GenExample.new
benchmark:
vm_ivar_get: |
vm_ivar_get_on_obj: |
obj.get_value_loop
vm_ivar_get_on_class: |
Example.get_value_loop
vm_ivar_get_on_generic: |
gen.get_value_loop
loop_count: 100
2 changes: 2 additions & 0 deletions internal/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ VALUE rb_obj_field_get(VALUE obj, shape_id_t target_shape_id);
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
attr_index_t rb_ivar_set_index(VALUE obj, ID id, VALUE val);
attr_index_t rb_obj_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE val);
VALUE rb_ivar_get_at(VALUE obj, attr_index_t index, ID id);
VALUE rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index);

RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
Expand Down
1 change: 1 addition & 0 deletions shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ STATIC_ASSERT(shape_id_num_bits, SHAPE_ID_NUM_BITS == sizeof(shape_id_t) * CHAR_
// index in rb_shape_tree.shape_list. Allow to access `rb_shape_t *`.
// 19-21 SHAPE_ID_HEAP_INDEX_MASK
// index in rb_shape_tree.capacities. Allow to access slot size.
// Always 0 except for T_OBJECT.
// 22 SHAPE_ID_FL_FROZEN
// Whether the object is frozen or not.
// 23 SHAPE_ID_FL_HAS_OBJECT_ID
Expand Down
6 changes: 3 additions & 3 deletions test/ruby/test_gc_compact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def test_moving_arrays_up_heaps
}.resume

stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)
assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, ARY_COUNT - 10)
assert_operator(stats.dig(:moved_up, :T_ARRAY) || 0, :>=, ARY_COUNT - 15)
refute_empty($arys.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
Expand Down Expand Up @@ -356,7 +356,7 @@ def add_ivars

stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)

assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT - 10)
assert_operator(stats.dig(:moved_up, :T_OBJECT) || 0, :>=, OBJ_COUNT - 15)
refute_empty($ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
Expand All @@ -377,7 +377,7 @@ def test_moving_strings_up_heaps

stats = GC.verify_compaction_references(expand_heap: true, toward: :empty)

assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT - 10)
assert_operator(stats[:moved_up][:T_STRING], :>=, STR_COUNT - 15)
refute_empty($ary.keep_if { |o| ObjectSpace.dump(o).include?('"embedded":true') })
end;
end
Expand Down
23 changes: 18 additions & 5 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,6 @@ def test_nested_local_access
end

def test_read_local_written_by_children_iseqs
omit "This test fails right now because Send doesn't compile."

assert_compiles '[1, 2]', %q{
def test
l1 = nil
Expand Down Expand Up @@ -1369,15 +1367,13 @@ def test_defined_yield_from_block
# This will do some EP hopping to find the local EP,
# so it's slightly different than doing it outside of a block.

omit 'Test fails at the moment due to missing Send codegen'

assert_compiles '[nil, nil, "yield"]', %q{
def test
yield_self { yield_self { defined?(yield) } }
end

[test, test, test{}]
}, call_threshold: 2, insns: [:defined]
}, call_threshold: 2
end

def test_invokeblock_without_block_after_jit_call
Expand Down Expand Up @@ -1669,6 +1665,23 @@ def foo
}, call_threshold: 2
end

def test_method_redefinition_with_module
assert_runs '["original", "redefined"]', %q{
module Foo
def self.foo = "original"
end

def test = Foo.foo
test
result1 = test

def Foo.foo = "redefined"
result2 = test

[result1, result2]
}, call_threshold: 2
end

def test_module_name_with_guard_passes
assert_compiles '"Integer"', %q{
def test(mod)
Expand Down
50 changes: 50 additions & 0 deletions variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,56 @@ rb_ivar_get(VALUE obj, ID id)
return iv;
}

VALUE
rb_ivar_get_at(VALUE obj, attr_index_t index, ID id)
{
RUBY_ASSERT(rb_is_instance_id(id));
// Used by JITs, but never for T_OBJECT.

switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
UNREACHABLE_RETURN(Qundef);
case T_CLASS:
case T_MODULE:
{
VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
VALUE val = rb_imemo_fields_ptr(fields_obj)[index];

if (UNLIKELY(!rb_ractor_main_p()) && !rb_ractor_shareable_p(val)) {
rb_raise(rb_eRactorIsolationError,
"can not get unshareable values from instance variables of classes/modules from non-main Ractors");
}

return val;
}
default:
{
VALUE fields_obj = rb_obj_fields(obj, id);
return rb_imemo_fields_ptr(fields_obj)[index];
}
}
}

VALUE
rb_ivar_get_at_no_ractor_check(VALUE obj, attr_index_t index)
{
// Used by JITs, but never for T_OBJECT.

VALUE fields_obj;
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
UNREACHABLE_RETURN(Qundef);
case T_CLASS:
case T_MODULE:
fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
break;
default:
fields_obj = rb_obj_fields_no_ractor_check(obj);
break;
}
return rb_imemo_fields_ptr(fields_obj)[index];
}

VALUE
rb_attr_get(VALUE obj, ID id)
{
Expand Down
11 changes: 5 additions & 6 deletions vm_method.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ invalidate_method_cache_in_cc_table(VALUE tbl, ID mid)
if (tbl && rb_managed_id_table_lookup(tbl, mid, &ccs_data)) {
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
rb_zjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid);
rb_vm_ccs_invalidate_and_free(ccs);
rb_managed_id_table_delete(tbl, mid);
Expand All @@ -367,9 +368,8 @@ invalidate_callable_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID
{
VALUE cme;
if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
if (rb_yjit_enabled_p) {
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
}
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
rb_id_table_delete(tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
}
Expand Down Expand Up @@ -413,9 +413,8 @@ invalidate_complemented_method_entry_in_callable_m_table(struct rb_id_table *tbl
{
VALUE cme;
if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
if (rb_yjit_enabled_p) {
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
}
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
rb_zjit_cme_invalidate((rb_callable_method_entry_t *)cme);
rb_id_table_delete(tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
}
Expand Down
2 changes: 2 additions & 0 deletions yjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ fn main() {

// From yjit.c
.allowlist_function("rb_object_shape_count")
.allowlist_function("rb_ivar_get_at")
.allowlist_function("rb_ivar_get_at_no_ractor_check")
.allowlist_function("rb_iseq_(get|set)_yjit_payload")
.allowlist_function("rb_iseq_pc_at_idx")
.allowlist_function("rb_iseq_opcode_at_pc")
Expand Down
Loading