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
1 change: 0 additions & 1 deletion .github/auto_request_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ files:
'zjit/src/cruby_bindings.inc.rs': []
'doc/zjit*': [team:jit]
'test/ruby/test_zjit*': [team:jit]
'test/.excludes-zjit/*': [team:jit]
'defs/jit.mk': [team:jit]
options:
ignore_draft: true
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,13 @@ jobs:
RUN_OPTS="$RUN_OPTS"
SPECOPTS="$SPECOPTS"
TESTOPTS="$TESTOPTS"
TEST_EXCLUDES="$TEST_EXCLUDES"
timeout-minutes: 60
env:
RUBY_TESTOPTS: '-q --tty=no'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
SYNTAX_SUGGEST_TIMEOUT: '5'
PRECHECK_BUNDLED_GEMS: 'no'
TESTS: ${{ matrix.tests }}
TEST_EXCLUDES: '--excludes-dir=../src/test/.excludes-zjit --name=!/memory_leak/'
continue-on-error: ${{ matrix.continue-on-test_task || false }}

result:
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,12 @@ jobs:
run: >-
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS"
TESTOPTS="$TESTOPTS" TEST_EXCLUDES="$TEST_EXCLUDES"
TESTOPTS="$TESTOPTS"
ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
timeout-minutes: 90
env:
RUBY_TESTOPTS: '-q --tty=no'
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
TEST_EXCLUDES: '--excludes-dir=../src/test/.excludes-zjit --name=!/memory_leak/'
PRECHECK_BUNDLED_GEMS: 'no'
SYNTAX_SUGGEST_TIMEOUT: '5'
ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'
Expand Down
10 changes: 0 additions & 10 deletions doc/zjit.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,6 @@ use `make`.

</details>

### make zjit-test-all

```
make zjit-test-all
```

This command runs all Ruby tests under `/test/ruby/` with ZJIT enabled.

Certain tests are excluded under `/test/.excludes-zjit`.

### test/ruby/test\_zjit.rb

This command runs Ruby execution tests.
Expand Down
2 changes: 1 addition & 1 deletion include/ruby/internal/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
#define RUBY_ABI_VERSION 3
#define RUBY_ABI_VERSION 4

/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
Expand Down
4 changes: 1 addition & 3 deletions lib/rubygems/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ def initialize(unknown_command)
end

def self.attach_correctable
return if defined?(@attached)
return if method_defined?(:corrections)

if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
end

@attached = true
end
end

Expand Down
10 changes: 10 additions & 0 deletions spec/ruby/language/fixtures/send.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ def to_proc
end
end

class RawToProc
def initialize(to_proc)
@to_proc = to_proc
end

def to_proc
@to_proc
end
end

class ToAry
def initialize(obj)
@obj = obj
Expand Down
18 changes: 18 additions & 0 deletions spec/ruby/language/send_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@
specs.yield_now(&o).should == :from_to_proc
end

ruby_version_is "3.5" do
it "raises TypeError if 'to_proc' doesn't return a Proc" do
o = LangSendSpecs::RawToProc.new(42)

-> {
specs.makeproc(&o)
}.should raise_error(TypeError, "can't convert LangSendSpecs::RawToProc to Proc (LangSendSpecs::RawToProc#to_proc gives Integer)")
end

it "raises TypeError if block object isn't a Proc and doesn't respond to `to_proc`" do
o = Object.new

-> {
specs.makeproc(&o)
}.should raise_error(TypeError, "no implicit conversion of Object into Proc")
end
end

it "raises a SyntaxError with both a literal block and an object as block" do
-> {
eval "specs.oneb(10, &l){ 42 }"
Expand Down
1 change: 0 additions & 1 deletion test/.excludes-zjit/TestERBCore.rb

This file was deleted.

1 change: 0 additions & 1 deletion test/.excludes-zjit/TestERBCoreWOStrScan.rb

This file was deleted.

57 changes: 56 additions & 1 deletion test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ def test_stats_enabled
RUBY
end

def test_stats_quiet
# Test that --zjit-stats=quiet collects stats but doesn't print them
script = <<~RUBY
def test = 42
test
test
puts RubyVM::ZJIT.stats_enabled?
RUBY

stats_header = "***ZJIT: Printing ZJIT statistics on exit***"

# With --zjit-stats, stats should be printed to stderr
out, err, status = eval_with_jit(script, stats: true)
assert_success(out, err, status)
assert_includes(err, stats_header)
assert_equal("true\n", out)

# With --zjit-stats=quiet, stats should NOT be printed but still enabled
out, err, status = eval_with_jit(script, stats: :quiet)
assert_success(out, err, status)
refute_includes(err, stats_header)
assert_equal("true\n", out)
end

def test_enable_through_env
child_env = {'RUBY_YJIT_ENABLE' => nil, 'RUBY_ZJIT_ENABLE' => '1'}
assert_in_out_err([child_env, '-v'], '') do |stdout, stderr|
Expand Down Expand Up @@ -742,6 +766,37 @@ def test(a, b) = a >= b
}, insns: [:opt_ge], call_threshold: 2
end

def test_opt_new_does_not_push_frame
assert_compiles 'nil', %q{
class Foo
attr_reader :backtrace

def initialize
@backtrace = caller
end
end
def test = Foo.new

foo = test
foo.backtrace.find do |frame|
frame.include?('Class#new')
end
}, insns: [:opt_new]
end

def test_opt_new_with_redefinition
assert_compiles '"foo"', %q{
class Foo
def self.new = "foo"

def initialize = raise("unreachable")
end
def test = Foo.new

test
}, insns: [:opt_new]
end

def test_new_hash_empty
assert_compiles '{}', %q{
def test = {}
Expand Down Expand Up @@ -2490,7 +2545,7 @@ def eval_with_jit(
if zjit
args << "--zjit-call-threshold=#{call_threshold}"
args << "--zjit-num-profiles=#{num_profiles}"
args << "--zjit-stats" if stats
args << "--zjit-stats#{"=#{stats}" unless stats == true}" if stats
args << "--zjit-debug" if debug
if allowed_iseqs
jitlist = Tempfile.new("jitlist")
Expand Down
2 changes: 1 addition & 1 deletion test/rubygems/test_gem_command_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def test_find_command_unknown_suggestions

message = "Unknown command pish".dup

if defined?(DidYouMean)
if e.respond_to?(:corrections)
message << "\nDid you mean? \"push\""
end

Expand Down
6 changes: 6 additions & 0 deletions vm_insnhelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,12 @@ vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type f
return check_cfunc(cme, func);
}

int
rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
{
return vm_method_cfunc_is(iseq, cd, recv, func);
}

#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
#define vm_method_cfunc_is(iseq, cd, recv, func) vm_method_cfunc_is(iseq, cd, recv, make_cfunc_type(func))

Expand Down
1 change: 1 addition & 0 deletions zjit.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ rb_zjit_insn_leaf(int insn, const VALUE *opes)
VALUE rb_zjit_assert_compiles(rb_execution_context_t *ec, VALUE self);
VALUE rb_zjit_stats(rb_execution_context_t *ec, VALUE self, VALUE target_key);
VALUE rb_zjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self);
VALUE rb_zjit_print_stats_p(rb_execution_context_t *ec, VALUE self);

// Preprocessed zjit.rb generated during build
#include "zjit.rbinc"
2 changes: 1 addition & 1 deletion zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# for which CRuby is built.
module RubyVM::ZJIT
# Avoid calling a Ruby method here to avoid interfering with compilation tests
if Primitive.rb_zjit_stats_enabled_p
if Primitive.rb_zjit_print_stats_p
at_exit { print_stats }
end
end
Expand Down
2 changes: 2 additions & 0 deletions zjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ fn main() {
// From internal/object.h
.allowlist_function("rb_class_allocate_instance")
.allowlist_function("rb_obj_equal")
.allowlist_function("rb_class_new_instance_pass_kw")
.allowlist_function("rb_obj_alloc")

// From gc.h and internal/gc.h
.allowlist_function("rb_obj_info")
Expand Down
14 changes: 14 additions & 0 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
Insn::ObjectAlloc { val, state } => gen_object_alloc(asm, opnd!(val), &function.frame_state(*state)),
Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)),
// concatstrings shouldn't have 0 strings
// If it happens we abort the compilation for now
Expand Down Expand Up @@ -385,6 +386,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::FixnumAnd { left, right } => gen_fixnum_and(asm, opnd!(left), opnd!(right)),
Insn::FixnumOr { left, right } => gen_fixnum_or(asm, opnd!(left), opnd!(right)),
Insn::IsNil { val } => gen_isnil(asm, opnd!(val)),
&Insn::IsMethodCfunc { val, cd, cfunc } => gen_is_method_cfunc(jit, asm, opnd!(val), cd, cfunc),
Insn::Test { val } => gen_test(asm, opnd!(val)),
Insn::GuardType { val, guard_type, state } => gen_guard_type(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state)),
Insn::GuardBitEquals { val, expected, state } => gen_guard_bit_equals(jit, asm, opnd!(val), *expected, &function.frame_state(*state)),
Expand Down Expand Up @@ -1190,6 +1192,11 @@ fn gen_new_range_fixnum(
asm_ccall!(asm, rb_range_new, low, high, (flag as i64).into())
}

fn gen_object_alloc(asm: &mut Assembler, val: lir::Opnd, state: &FrameState) -> lir::Opnd {
gen_prepare_call_with_gc(asm, state);
asm_ccall!(asm, rb_obj_alloc, val)
}

/// Compile code that exits from JIT code with a return value
fn gen_return(asm: &mut Assembler, val: lir::Opnd) {
// Pop the current frame (ec->cfp++)
Expand Down Expand Up @@ -1292,6 +1299,13 @@ fn gen_isnil(asm: &mut Assembler, val: lir::Opnd) -> lir::Opnd {
asm.csel_e(Opnd::Imm(1), Opnd::Imm(0))
}

fn gen_is_method_cfunc(jit: &JITState, asm: &mut Assembler, val: lir::Opnd, cd: *const rb_call_data, cfunc: *const u8) -> lir::Opnd {
unsafe extern "C" {
fn rb_vm_method_cfunc_is(iseq: IseqPtr, cd: *const rb_call_data, recv: VALUE, cfunc: *const u8) -> VALUE;
}
asm_ccall!(asm, rb_vm_method_cfunc_is, VALUE(jit.iseq as usize).into(), (cd as usize).into(), val, (cfunc as usize).into())
}

fn gen_anytostring(asm: &mut Assembler, val: lir::Opnd, str: lir::Opnd, state: &FrameState) -> lir::Opnd {
gen_prepare_call_with_gc(asm, state);

Expand Down
6 changes: 6 additions & 0 deletions zjit/src/cruby_bindings.inc.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading