Skip to content

Commit 65b8c69

Browse files
committed
Merge remote-tracking branch 'refs/remotes/gh/master' into zjit-stack-overflow
2 parents 54e71e5 + 8d05669 commit 65b8c69

37 files changed

Lines changed: 668 additions & 257 deletions

‎.github/workflows/zjit-macos.yml‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
configure: '--enable-zjit=dev'
3737
run_opts: '--zjit-call-threshold=1'
3838
specopts: '-T --zjit-call-threshold=1'
39+
test_all_opts: '--seed=46450'
3940

4041
- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
4142
configure: '--enable-yjit=dev --enable-zjit'
@@ -50,6 +51,7 @@ jobs:
5051
RUN_OPTS: ${{ matrix.run_opts }}
5152
SPECOPTS: ${{ matrix.specopts }}
5253
TESTOPTS: ${{ matrix.testopts }}
54+
ZJIT_RB_BUG: 1
5355

5456
runs-on: macos-14
5557

@@ -117,9 +119,15 @@ jobs:
117119
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
118120
SYNTAX_SUGGEST_TIMEOUT: '5'
119121
PRECHECK_BUNDLED_GEMS: 'no'
120-
TESTS: ${{ matrix.tests }}
122+
TESTS: ${{ matrix.test_all_opts }}
121123
continue-on-error: ${{ matrix.continue-on-test_task || false }}
122124

125+
- uses: ./.github/actions/slack
126+
with:
127+
label: ${{ matrix.test_task }} ${{ matrix.configure }}
128+
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
129+
if: ${{ failure() }}
130+
123131
result:
124132
if: ${{ always() }}
125133
name: ${{ github.workflow }} result

‎.github/workflows/zjit-ubuntu.yml‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ jobs:
5555
configure: '--enable-zjit=dev'
5656
run_opts: '--zjit-call-threshold=1'
5757
specopts: '-T --zjit-call-threshold=1'
58+
test_all_opts: '--seed=39471'
5859

5960
- test_task: 'zjit-check' # zjit-test + quick feedback of test_zjit.rb
6061
configure: '--enable-yjit --enable-zjit=dev'
@@ -74,6 +75,7 @@ jobs:
7475
RUBY_DEBUG: ci
7576
BUNDLE_JOBS: 8 # for yjit-bench
7677
RUST_BACKTRACE: 1
78+
ZJIT_RB_BUG: 1
7779

7880
runs-on: ubuntu-22.04
7981

@@ -159,9 +161,15 @@ jobs:
159161
SYNTAX_SUGGEST_TIMEOUT: '5'
160162
ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'
161163
LIBCLANG_PATH: ${{ matrix.libclang_path }}
162-
TESTS: ${{ matrix.tests }}
164+
TESTS: ${{ matrix.test_all_opts }}
163165
continue-on-error: ${{ matrix.continue-on-test_task || false }}
164166

167+
- uses: ./.github/actions/slack
168+
with:
169+
label: ${{ matrix.test_task }} ${{ matrix.configure }}
170+
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
171+
if: ${{ failure() }}
172+
165173
result:
166174
if: ${{ always() }}
167175
name: ${{ github.workflow }} result

‎NEWS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ The following default gems are updated.
161161
* bundler 2.8.0.dev
162162
* erb 5.0.2
163163
* etc 1.4.6
164+
* fcntl 1.3.0
164165
* io-console 0.8.1
165166
* io-nonblock 0.3.2
166167
* io-wait 0.3.2

‎concurrent_set.c‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,26 @@ concurrent_set_size(const void *ptr)
4040
(set->capacity * sizeof(struct concurrent_set_entry));
4141
}
4242

43+
/* Hack: Though it would be trivial, we're intentionally avoiding WB-protecting
44+
* this object. This prevents the object from aging and ensures it can always be
45+
* collected in a minor GC.
46+
* Longer term this deserves a better way to reclaim memory promptly.
47+
*/
48+
static void
49+
concurrent_set_mark(void *ptr)
50+
{
51+
(void)ptr;
52+
}
53+
4354
static const rb_data_type_t concurrent_set_type = {
4455
.wrap_struct_name = "VM/concurrent_set",
4556
.function = {
46-
.dmark = NULL,
57+
.dmark = concurrent_set_mark,
4758
.dfree = concurrent_set_free,
4859
.dsize = concurrent_set_size,
4960
},
50-
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
61+
/* Hack: NOT WB_PROTECTED on purpose (see above) */
62+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
5163
};
5264

5365
VALUE

‎doc/yjit/yjit.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ There are multiple test suites:
388388
- `make test-all`
389389
- `make test-spec`
390390
- `make check` runs all of the above
391-
- `make yjit-smoke-test` runs quick checks to see that YJIT is working correctly
391+
- `make yjit-check` runs quick checks to see that YJIT is working correctly
392392

393393
The tests can be run in parallel like this:
394394

‎doc/zjit.md‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,49 @@ You can also run a single test case by matching the method name:
110110
make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
111111
```
112112

113+
## Statistics Collection
114+
115+
ZJIT provides detailed statistics about JIT compilation and execution behavior.
116+
117+
### Basic Stats
118+
119+
Run with basic statistics printed on exit:
120+
121+
```bash
122+
./miniruby --zjit-stats script.rb
123+
```
124+
125+
Collect stats without printing (access via `RubyVM::ZJIT.stats` in Ruby):
126+
127+
```bash
128+
./miniruby --zjit-stats=quiet script.rb
129+
```
130+
131+
### Accessing Stats in Ruby
132+
133+
```ruby
134+
# Check if stats are enabled
135+
if RubyVM::ZJIT.stats_enabled?
136+
stats = RubyVM::ZJIT.stats
137+
puts "Compiled ISEQs: #{stats[:compiled_iseq_count]}"
138+
puts "Failed ISEQs: #{stats[:failed_iseq_count]}"
139+
140+
# You can also reset stats during execution
141+
RubyVM::ZJIT.reset_stats!
142+
end
143+
```
144+
145+
### Performance Ratio
146+
147+
The `ratio_in_zjit` stat shows the percentage of Ruby instructions executed in JIT code vs interpreter. This metric only appears when ZJIT is built with `--enable-zjit=stats` (which enables `rb_vm_insn_count` tracking) and represents a key performance indicator for ZJIT effectiveness.
148+
149+
To build with stats support:
150+
151+
```bash
152+
./configure --enable-zjit=stats
153+
make -j
154+
```
155+
113156
## ZJIT Glossary
114157

115158
This glossary contains terms that are helpful for understanding ZJIT.

‎ext/fcntl/fcntl.c‎

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pack up your own arguments to pass as args for locking functions, etc.
6565
*
6666
*/
6767

68-
#define FCNTL_VERSION "1.2.0"
68+
#define FCNTL_VERSION "1.3.0"
6969

7070
void
7171
Init_fcntl(void)
@@ -251,4 +251,50 @@ Init_fcntl(void)
251251
*/
252252
rb_define_const(mFcntl, "F_DUP2FD_CLOEXEC", INT2NUM(F_DUP2FD_CLOEXEC));
253253
#endif
254+
255+
#ifdef F_PREALLOCATE
256+
/*
257+
* macOS specific flag used for preallocating file space.
258+
*/
259+
rb_define_const(mFcntl, "F_PREALLOCATE", INT2NUM(F_PREALLOCATE));
260+
#endif
261+
262+
#ifdef F_ALLOCATECONTIG
263+
/*
264+
* macOS specific flag used with F_PREALLOCATE for allocating contiguous
265+
* space.
266+
*/
267+
rb_define_const(mFcntl, "F_ALLOCATECONTIG", INT2NUM(F_ALLOCATECONTIG));
268+
#endif
269+
270+
#ifdef F_ALLOCATEALL
271+
/*
272+
* macOS specific flag used with F_PREALLOCATE for allocating all contiguous
273+
* space or no space.
274+
*/
275+
rb_define_const(mFcntl, "F_ALLOCATEALL", INT2NUM(F_ALLOCATEALL));
276+
#endif
277+
278+
#ifdef F_ALLOCATEPERSIST
279+
/*
280+
* macOS specific flag used with F_PREALLOCATE. Allocate space that is not
281+
* freed when close is called.
282+
*/
283+
rb_define_const(mFcntl, "F_ALLOCATEPERSIST", INT2NUM(F_ALLOCATEPERSIST));
284+
#endif
285+
286+
#ifdef F_PEOFPOSMODE
287+
/*
288+
* macOS specific flag used with F_PREALLOCATE. Allocate from the physical
289+
* end of file
290+
*/
291+
rb_define_const(mFcntl, "F_PEOFPOSMODE", INT2NUM(F_PEOFPOSMODE));
292+
#endif
293+
294+
#ifdef F_VOLPOSMODE
295+
/*
296+
* macOS specific flag used with F_PREALLOCATE. Allocate from the volume offset.
297+
*/
298+
rb_define_const(mFcntl, "F_VOLPOSMODE", INT2NUM(F_VOLPOSMODE));
299+
#endif
254300
}

‎load.c‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,11 @@ get_loaded_features_index(vm_ns_t *vm_ns)
447447
VALUE previous_realpath_map = rb_hash_dup(realpath_map);
448448
rb_hash_clear(realpaths);
449449
rb_hash_clear(realpath_map);
450+
451+
/* We have to make a copy of features here because the StringValue call
452+
* below could call a Ruby method, which could modify $LOADED_FEATURES
453+
* and cause it to be corrupt. */
454+
features = rb_ary_resurrect(features);
450455
for (i = 0; i < RARRAY_LEN(features); i++) {
451456
VALUE entry, as_str;
452457
as_str = entry = rb_ary_entry(features, i);
@@ -456,6 +461,10 @@ get_loaded_features_index(vm_ns_t *vm_ns)
456461
rb_ary_store(features, i, as_str);
457462
features_index_add(vm_ns, as_str, INT2FIX(i));
458463
}
464+
/* The user modified $LOADED_FEATURES, so we should restore the changes. */
465+
if (!rb_ary_shared_with_p(features, CURRENT_NS_LOADED_FEATURES(vm_ns))) {
466+
rb_ary_replace(CURRENT_NS_LOADED_FEATURES(vm_ns), features);
467+
}
459468
reset_loaded_features_snapshot(vm_ns);
460469

461470
features = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);

0 commit comments

Comments
 (0)