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
2 changes: 1 addition & 1 deletion array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def fetch_values(*indexes, &block)
indexes
end

with_yjit do
with_jit do
if Primitive.rb_builtin_basic_definition_p(:each)
undef :each

Expand Down
85 changes: 0 additions & 85 deletions bootstraptest/test_yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -468,91 +468,6 @@ def getter
end
}

assert_equal '0', %q{
# This is a regression test for incomplete invalidation from
# opt_setinlinecache. This test might be brittle, so
# feel free to remove it in the future if it's too annoying.
# This test assumes --yjit-call-threshold=2.
module M
Foo = 1
def foo
Foo
end

def pin_self_type_then_foo
_ = @foo
foo
end

def only_ints
1 + self
foo
end
end

class Integer
include M
end

class Sub
include M
end

foo_method = M.instance_method(:foo)

dbg = ->(message) do
return # comment this out to get printouts

$stderr.puts RubyVM::YJIT.disasm(foo_method)
$stderr.puts message
end

2.times { 42.only_ints }

dbg["There should be two versions of getinlineache"]

module M
remove_const(:Foo)
end

dbg["There should be no getinlinecaches"]

2.times do
42.only_ints
rescue NameError => err
_ = "caught name error #{err}"
end

dbg["There should be one version of getinlineache"]

2.times do
Sub.new.pin_self_type_then_foo
rescue NameError
_ = 'second specialization'
end

dbg["There should be two versions of getinlineache"]

module M
Foo = 1
end

dbg["There should still be two versions of getinlineache"]

42.only_ints

dbg["There should be no getinlinecaches"]

# Find name of the first VM instruction in M#foo.
insns = RubyVM::InstructionSequence.of(foo_method).to_a
if defined?(RubyVM::YJIT.blocks_for) && (insns.last.find { Array === _1 }&.first == :opt_getinlinecache)
RubyVM::YJIT.blocks_for(RubyVM::InstructionSequence.of(foo_method))
.filter { _1.iseq_start_index == 0 }.count
else
0 # skip the test
end
}

# Check that frozen objects are respected
assert_equal 'great', %q{
class Foo
Expand Down
3 changes: 2 additions & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1236,8 +1236,9 @@ BUILTIN_RB_SRCS = \
$(srcdir)/nilclass.rb \
$(srcdir)/prelude.rb \
$(srcdir)/gem_prelude.rb \
$(srcdir)/jit_hook.rb \
$(srcdir)/jit_undef.rb \
$(srcdir)/yjit.rb \
$(srcdir)/yjit_hook.rb \
$(srcdir)/zjit.rb \
$(empty)
BUILTIN_RB_INCS = $(BUILTIN_RB_SRCS:.rb=.rbinc)
Expand Down
6 changes: 4 additions & 2 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -9196,6 +9196,8 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
miniinit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
miniinit.$(OBJEXT): {$(VPATH)}io.rb
miniinit.$(OBJEXT): {$(VPATH)}iseq.h
miniinit.$(OBJEXT): {$(VPATH)}jit_hook.rb
miniinit.$(OBJEXT): {$(VPATH)}jit_undef.rb
miniinit.$(OBJEXT): {$(VPATH)}kernel.rb
miniinit.$(OBJEXT): {$(VPATH)}marshal.rb
miniinit.$(OBJEXT): {$(VPATH)}method.h
Expand Down Expand Up @@ -9232,7 +9234,6 @@ miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
miniinit.$(OBJEXT): {$(VPATH)}warning.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit_hook.rb
miniinit.$(OBJEXT): {$(VPATH)}zjit.rb
namespace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
namespace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
Expand Down Expand Up @@ -18755,6 +18756,8 @@ vm.$(OBJEXT): {$(VPATH)}internal/variable.h
vm.$(OBJEXT): {$(VPATH)}internal/warning_push.h
vm.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm.$(OBJEXT): {$(VPATH)}iseq.h
vm.$(OBJEXT): {$(VPATH)}jit_hook.rbinc
vm.$(OBJEXT): {$(VPATH)}jit_undef.rbinc
vm.$(OBJEXT): {$(VPATH)}method.h
vm.$(OBJEXT): {$(VPATH)}missing.h
vm.$(OBJEXT): {$(VPATH)}node.h
Expand Down Expand Up @@ -18797,7 +18800,6 @@ vm.$(OBJEXT): {$(VPATH)}vm_opts.h
vm.$(OBJEXT): {$(VPATH)}vm_sync.h
vm.$(OBJEXT): {$(VPATH)}vmtc.inc
vm.$(OBJEXT): {$(VPATH)}yjit.h
vm.$(OBJEXT): {$(VPATH)}yjit_hook.rbinc
vm.$(OBJEXT): {$(VPATH)}zjit.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
Expand Down
5 changes: 0 additions & 5 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,6 @@ rb_gc_shutdown_call_finalizer_p(VALUE obj)
return true;

case T_SYMBOL:
if (RSYMBOL(obj)->fstr &&
(BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_NONE ||
BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_ZOMBIE)) {
RSYMBOL(obj)->fstr = 0;
}
return true;

case T_NONE:
Expand Down
9 changes: 9 additions & 0 deletions gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ rb_mmtk_update_global_tables(int table)
rb_gc_vm_weak_table_foreach(rb_mmtk_update_table_i, NULL, NULL, true, (enum rb_gc_vm_weak_tables)table);
}

static bool
rb_mmtk_special_const_p(MMTk_ObjectReference object)
{
VALUE obj = (VALUE)object;

return RB_SPECIAL_CONST_P(obj);
}

// Bootup
MMTk_RubyUpcalls ruby_upcalls = {
rb_mmtk_init_gc_worker_thread,
Expand All @@ -360,6 +368,7 @@ MMTk_RubyUpcalls ruby_upcalls = {
rb_mmtk_update_global_tables,
rb_mmtk_global_tables_count,
rb_mmtk_update_finalizer_table,
rb_mmtk_special_const_p,
};

// Use max 80% of the available memory by default for MMTk
Expand Down
1 change: 1 addition & 0 deletions gc/mmtk/mmtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct MMTk_RubyUpcalls {
void (*update_global_tables)(int tbl_idx);
int (*global_tables_count)(void);
void (*update_finalizer_table)(void);
bool (*special_const_p)(MMTk_ObjectReference object);
} MMTk_RubyUpcalls;

typedef struct MMTk_RawVecOfObjRef {
Expand Down
1 change: 1 addition & 0 deletions gc/mmtk/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ pub struct RubyUpcalls {
pub update_global_tables: extern "C" fn(tbl_idx: c_int),
pub global_tables_count: extern "C" fn() -> c_int,
pub update_finalizer_table: extern "C" fn(),
pub special_const_p: extern "C" fn(object: ObjectReference) -> bool,
}

unsafe impl Sync for RubyUpcalls {}
Expand Down
4 changes: 4 additions & 0 deletions gc/mmtk/src/weak_proc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ impl GCWork<Ruby> for ProcessWeakReferences {
.expect("Mutators should not be holding the lock.");

for ptr_ptr in weak_references.iter_mut() {
if (upcalls().special_const_p)(**ptr_ptr) {
continue;
}

if !(**ptr_ptr).is_reachable() {
**ptr_ptr = crate::binding().weak_reference_dead_value;
}
Expand Down
7 changes: 4 additions & 3 deletions inits.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ void
rb_call_builtin_inits(void)
{
#define BUILTIN(n) CALL(builtin_##n)
BUILTIN(kernel);
BUILTIN(jit_hook);
BUILTIN(yjit);
BUILTIN(zjit);
BUILTIN(kernel);
BUILTIN(gc);
BUILTIN(ractor);
BUILTIN(numeric);
Expand All @@ -107,8 +109,7 @@ rb_call_builtin_inits(void)
BUILTIN(thread_sync);
BUILTIN(nilclass);
BUILTIN(marshal);
BUILTIN(zjit);
BUILTIN(yjit_hook);
BUILTIN(jit_undef);
Init_builtin_prelude();
}
#undef CALL
6 changes: 3 additions & 3 deletions internal/cmdlineopt.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ typedef struct ruby_cmdline_options {
ruby_features_t warn;
unsigned int dump;
long backtrace_length_limit;
#if USE_ZJIT
void *zjit;
#endif

const char *crash_report;

Expand All @@ -42,6 +39,9 @@ typedef struct ruby_cmdline_options {
#if USE_YJIT
unsigned int yjit: 1;
#endif
#if USE_ZJIT
unsigned int zjit: 1;
#endif
} ruby_cmdline_options_t;

struct ruby_opt_message {
Expand Down
13 changes: 13 additions & 0 deletions jit_hook.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Module
# Internal helper for built-in initializations to define methods only when JIT is enabled.
# This method is removed in jit_undef.rb.
private def with_jit(&block) # :nodoc:
# ZJIT currently doesn't compile Array#each properly, so it's disabled for now.
if defined?(RubyVM::ZJIT) && Primitive.rb_zjit_option_enabled_p && false # TODO: remove `&& false` (Shopify/ruby#667)
# We don't support lazily enabling ZJIT yet, so we can call the block right away.
block.call
elsif defined?(RubyVM::YJIT)
RubyVM::YJIT.send(:add_jit_hook, block)
end
end
end
4 changes: 4 additions & 0 deletions jit_undef.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Remove the helper defined in jit_hook.rb
class Module
undef :with_jit
end
10 changes: 0 additions & 10 deletions kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,3 @@ def Integer(arg, base = 0, exception: true)
end
end
end

class Module
# Internal helper for built-in initializations to define methods only when YJIT is enabled.
# This method is removed in yjit_hook.rb.
private def with_yjit(&block) # :nodoc:
if defined?(RubyVM::YJIT)
RubyVM::YJIT.send(:add_yjit_hook, block)
end
end
end
2 changes: 1 addition & 1 deletion numeric.rb
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ def denominator
1
end

with_yjit do
with_jit do
if Primitive.rb_builtin_basic_definition_p(:downto)
undef :downto

Expand Down
22 changes: 10 additions & 12 deletions ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -2267,26 +2267,24 @@ struct cross_ractor_require {
bool silent;
};

static void
cross_ractor_require_mark(void *ptr)
{
struct cross_ractor_require *crr = (struct cross_ractor_require *)ptr;
rb_gc_mark(crr->port);
rb_gc_mark(crr->result);
rb_gc_mark(crr->exception);
rb_gc_mark(crr->feature);
rb_gc_mark(crr->module);
}
RUBY_REFERENCES(cross_ractor_require_refs) = {
RUBY_REF_EDGE(struct cross_ractor_require, port),
RUBY_REF_EDGE(struct cross_ractor_require, result),
RUBY_REF_EDGE(struct cross_ractor_require, exception),
RUBY_REF_EDGE(struct cross_ractor_require, feature),
RUBY_REF_EDGE(struct cross_ractor_require, module),
RUBY_REF_END
};

static const rb_data_type_t cross_ractor_require_data_type = {
"ractor/cross_ractor_require",
{
cross_ractor_require_mark,
RUBY_REFS_LIST_PTR(cross_ractor_require_refs),
RUBY_DEFAULT_FREE,
NULL, // memsize
NULL, // compact
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
};

static VALUE
Expand Down
19 changes: 9 additions & 10 deletions ruby.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,14 +1196,12 @@ setup_yjit_options(const char *s)

#if USE_ZJIT
static void
setup_zjit_options(ruby_cmdline_options_t *opt, const char *s)
setup_zjit_options(const char *s)
{
// The option parsing is done in zjit/src/options.rs
extern void *rb_zjit_init_options(void);
extern bool rb_zjit_parse_option(void *options, const char *s);
extern bool rb_zjit_parse_option(const char *s);

if (!opt->zjit) opt->zjit = rb_zjit_init_options();
if (!rb_zjit_parse_option(opt->zjit, s)) {
if (!rb_zjit_parse_option(s)) {
rb_raise(rb_eRuntimeError, "invalid ZJIT option '%s' (--help will show valid zjit options)", s);
}
}
Expand Down Expand Up @@ -1481,7 +1479,7 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **
else if (is_option_with_optarg("zjit", '-', true, false, false)) {
#if USE_ZJIT
FEATURE_SET(opt->features, FEATURE_BIT(zjit));
setup_zjit_options(opt, s);
setup_zjit_options(s);
#else
rb_warn("Ruby was built without ZJIT support."
" You may need to install rustc to build Ruby with ZJIT.");
Expand Down Expand Up @@ -1828,8 +1826,8 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
#endif
#if USE_ZJIT
if (opt->zjit) {
extern void rb_zjit_init(void *options);
rb_zjit_init(opt->zjit);
extern void rb_zjit_init(void);
rb_zjit_init();
}
#endif

Expand Down Expand Up @@ -2370,8 +2368,9 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#endif
#if USE_ZJIT
if (FEATURE_SET_P(opt->features, zjit) && !opt->zjit) {
extern void *rb_zjit_init_options(void);
opt->zjit = rb_zjit_init_options();
extern void rb_zjit_prepare_options(void);
rb_zjit_prepare_options();
opt->zjit = true;
}
#endif

Expand Down
7 changes: 7 additions & 0 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,13 @@ def test_require_rubygems_with_auto_compact
}, call_threshold: 2
end

def test_zjit_option_uses_array_each_in_ruby
omit 'ZJIT wrongly compiles Array#each, so it is disabled for now'
assert_runs '"<internal:array>"', %q{
Array.instance_method(:each).source_location&.first
}
end

def test_profile_under_nested_jit_call
assert_compiles '[nil, nil, 3]', %q{
def profile
Expand Down
Loading