Skip to content

Commit 866e474

Browse files
authored
ZJIT: Fix backtraces on opt_new (ruby#14461)
1 parent 5ee083c commit 866e474

File tree

13 files changed

+131
-43
lines changed

13 files changed

+131
-43
lines changed

.github/auto_request_review.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ files:
1010
'zjit/src/cruby_bindings.inc.rs': []
1111
'doc/zjit*': [team:jit]
1212
'test/ruby/test_zjit*': [team:jit]
13-
'test/.excludes-zjit/*': [team:jit]
1413
'defs/jit.mk': [team:jit]
1514
options:
1615
ignore_draft: true

.github/workflows/zjit-macos.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,13 @@ jobs:
111111
RUN_OPTS="$RUN_OPTS"
112112
SPECOPTS="$SPECOPTS"
113113
TESTOPTS="$TESTOPTS"
114-
TEST_EXCLUDES="$TEST_EXCLUDES"
115114
timeout-minutes: 60
116115
env:
117116
RUBY_TESTOPTS: '-q --tty=no'
118117
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
119118
SYNTAX_SUGGEST_TIMEOUT: '5'
120119
PRECHECK_BUNDLED_GEMS: 'no'
121120
TESTS: ${{ matrix.tests }}
122-
TEST_EXCLUDES: '--excludes-dir=../src/test/.excludes-zjit --name=!/memory_leak/'
123121
continue-on-error: ${{ matrix.continue-on-test_task || false }}
124122

125123
result:

.github/workflows/zjit-ubuntu.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,12 @@ jobs:
149149
run: >-
150150
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
151151
RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS"
152-
TESTOPTS="$TESTOPTS" TEST_EXCLUDES="$TEST_EXCLUDES"
152+
TESTOPTS="$TESTOPTS"
153153
ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
154154
timeout-minutes: 90
155155
env:
156156
RUBY_TESTOPTS: '-q --tty=no'
157157
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
158-
TEST_EXCLUDES: '--excludes-dir=../src/test/.excludes-zjit --name=!/memory_leak/'
159158
PRECHECK_BUNDLED_GEMS: 'no'
160159
SYNTAX_SUGGEST_TIMEOUT: '5'
161160
ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'

doc/zjit.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,6 @@ use `make`.
9696

9797
</details>
9898

99-
### make zjit-test-all
100-
101-
```
102-
make zjit-test-all
103-
```
104-
105-
This command runs all Ruby tests under `/test/ruby/` with ZJIT enabled.
106-
107-
Certain tests are excluded under `/test/.excludes-zjit`.
108-
10999
### test/ruby/test\_zjit.rb
110100

111101
This command runs Ruby execution tests.

test/.excludes-zjit/TestERBCore.rb

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/.excludes-zjit/TestERBCoreWOStrScan.rb

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/ruby/test_zjit.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,37 @@ def test(a, b) = a >= b
766766
}, insns: [:opt_ge], call_threshold: 2
767767
end
768768

769+
def test_opt_new_does_not_push_frame
770+
assert_compiles 'nil', %q{
771+
class Foo
772+
attr_reader :backtrace
773+
774+
def initialize
775+
@backtrace = caller
776+
end
777+
end
778+
def test = Foo.new
779+
780+
foo = test
781+
foo.backtrace.find do |frame|
782+
frame.include?('Class#new')
783+
end
784+
}, insns: [:opt_new]
785+
end
786+
787+
def test_opt_new_with_redefinition
788+
assert_compiles '"foo"', %q{
789+
class Foo
790+
def self.new = "foo"
791+
792+
def initialize = raise("unreachable")
793+
end
794+
def test = Foo.new
795+
796+
test
797+
}, insns: [:opt_new]
798+
end
799+
769800
def test_new_hash_empty
770801
assert_compiles '{}', %q{
771802
def test = {}

vm_insnhelper.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,12 @@ vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type f
24172417
return check_cfunc(cme, func);
24182418
}
24192419

2420+
int
2421+
rb_vm_method_cfunc_is(const rb_iseq_t *iseq, CALL_DATA cd, VALUE recv, cfunc_type func)
2422+
{
2423+
return vm_method_cfunc_is(iseq, cd, recv, func);
2424+
}
2425+
24202426
#define check_cfunc(me, func) check_cfunc(me, make_cfunc_type(func))
24212427
#define vm_method_cfunc_is(iseq, cd, recv, func) vm_method_cfunc_is(iseq, cd, recv, make_cfunc_type(func))
24222428

zjit/bindgen/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ fn main() {
417417
// From internal/object.h
418418
.allowlist_function("rb_class_allocate_instance")
419419
.allowlist_function("rb_obj_equal")
420+
.allowlist_function("rb_class_new_instance_pass_kw")
421+
.allowlist_function("rb_obj_alloc")
420422

421423
// From gc.h and internal/gc.h
422424
.allowlist_function("rb_obj_info")

zjit/src/codegen.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
349349
Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
350350
Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
351351
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
352+
Insn::ObjectAlloc { val, state } => gen_object_alloc(asm, opnd!(val), &function.frame_state(*state)),
352353
Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)),
353354
// concatstrings shouldn't have 0 strings
354355
// If it happens we abort the compilation for now
@@ -385,6 +386,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
385386
Insn::FixnumAnd { left, right } => gen_fixnum_and(asm, opnd!(left), opnd!(right)),
386387
Insn::FixnumOr { left, right } => gen_fixnum_or(asm, opnd!(left), opnd!(right)),
387388
Insn::IsNil { val } => gen_isnil(asm, opnd!(val)),
389+
&Insn::IsMethodCfunc { val, cd, cfunc } => gen_is_method_cfunc(jit, asm, opnd!(val), cd, cfunc),
388390
Insn::Test { val } => gen_test(asm, opnd!(val)),
389391
Insn::GuardType { val, guard_type, state } => gen_guard_type(jit, asm, opnd!(val), *guard_type, &function.frame_state(*state)),
390392
Insn::GuardBitEquals { val, expected, state } => gen_guard_bit_equals(jit, asm, opnd!(val), *expected, &function.frame_state(*state)),
@@ -1190,6 +1192,11 @@ fn gen_new_range_fixnum(
11901192
asm_ccall!(asm, rb_range_new, low, high, (flag as i64).into())
11911193
}
11921194

1195+
fn gen_object_alloc(asm: &mut Assembler, val: lir::Opnd, state: &FrameState) -> lir::Opnd {
1196+
gen_prepare_call_with_gc(asm, state);
1197+
asm_ccall!(asm, rb_obj_alloc, val)
1198+
}
1199+
11931200
/// Compile code that exits from JIT code with a return value
11941201
fn gen_return(asm: &mut Assembler, val: lir::Opnd) {
11951202
// Pop the current frame (ec->cfp++)
@@ -1292,6 +1299,13 @@ fn gen_isnil(asm: &mut Assembler, val: lir::Opnd) -> lir::Opnd {
12921299
asm.csel_e(Opnd::Imm(1), Opnd::Imm(0))
12931300
}
12941301

1302+
fn gen_is_method_cfunc(jit: &JITState, asm: &mut Assembler, val: lir::Opnd, cd: *const rb_call_data, cfunc: *const u8) -> lir::Opnd {
1303+
unsafe extern "C" {
1304+
fn rb_vm_method_cfunc_is(iseq: IseqPtr, cd: *const rb_call_data, recv: VALUE, cfunc: *const u8) -> VALUE;
1305+
}
1306+
asm_ccall!(asm, rb_vm_method_cfunc_is, VALUE(jit.iseq as usize).into(), (cd as usize).into(), val, (cfunc as usize).into())
1307+
}
1308+
12951309
fn gen_anytostring(asm: &mut Assembler, val: lir::Opnd, str: lir::Opnd, state: &FrameState) -> lir::Opnd {
12961310
gen_prepare_call_with_gc(asm, state);
12971311

0 commit comments

Comments
 (0)