Skip to content

Commit 9d14209

Browse files
authored
Merge branch 'master' into zjit-value-fmt-debug
2 parents d32cf30 + c30d74b commit 9d14209

File tree

15 files changed

+167
-63
lines changed

15 files changed

+167
-63
lines changed

.github/workflows/pr-playground.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
&& github.event.workflow_run.event == 'pull_request')
3030
}}
3131
steps:
32-
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
32+
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
3333
with:
3434
github-token: ${{ secrets.GITHUB_TOKEN }}
3535
script: |

.github/workflows/zjit-macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
rustup install ${{ matrix.rust_version }} --profile minimal
9494
rustup default ${{ matrix.rust_version }}
9595
96-
- uses: taiki-e/install-action@80e6af7a2ec7f280fffe2d0a9d3a12a9d11d86e9 # v2.75.1
96+
- uses: taiki-e/install-action@b8be7f5e140177087325943c4a8e169d01c59b3d # v2.75.3
9797
with:
9898
tool: nextest@0.9
9999
if: ${{ matrix.test_task == 'zjit-check' }}

.github/workflows/zjit-ubuntu.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ jobs:
119119
ruby-version: '3.1'
120120
bundler: none
121121

122-
- uses: taiki-e/install-action@80e6af7a2ec7f280fffe2d0a9d3a12a9d11d86e9 # v2.75.1
122+
- uses: taiki-e/install-action@b8be7f5e140177087325943c4a8e169d01c59b3d # v2.75.3
123123
with:
124124
tool: nextest@0.9
125125
if: ${{ matrix.test_task == 'zjit-check' }}

benchmark/dir_pwd.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
benchmark:
2+
pwd: Dir.pwd

benchmark/file_expand_path.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
prelude: |
2+
# frozen_string_literal: true
3+
benchmark:
4+
expand_path: File.expand_path("../../foo.txt", __FILE__)

compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12167,7 +12167,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
1216712167
case TS_CDHASH:
1216812168
{
1216912169
int i;
12170-
VALUE map = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(op)/2);
12170+
VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
1217112171

1217212172
RHASH_TBL_RAW(map)->type = &cdhash_type;
1217312173
op = rb_to_array_type(op);
@@ -12179,7 +12179,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
1217912179
rb_hash_aset(map, key, (VALUE)label | 1);
1218012180
}
1218112181
RB_GC_GUARD(op);
12182-
RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12182+
RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
1218312183
argv[j] = map;
1218412184
RB_OBJ_WRITTEN(iseq, Qundef, map);
1218512185
}

dir.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,8 @@ dir_chdir(VALUE dir)
15851585
#endif
15861586
}
15871587

1588+
static VALUE last_cwd;
1589+
15881590
#ifndef _WIN32
15891591
static VALUE
15901592
getcwd_to_str(VALUE arg)
@@ -1604,20 +1606,43 @@ getcwd_xfree(VALUE arg)
16041606
return Qnil;
16051607
}
16061608

1607-
VALUE
1608-
rb_dir_getwd_ospath(void)
1609+
static VALUE
1610+
rb_dir_getwd_ospath_slowpath(void)
16091611
{
16101612
char *path = ruby_getcwd();
16111613
return rb_ensure(getcwd_to_str, (VALUE)path, getcwd_xfree, (VALUE)path);
16121614
}
1615+
1616+
VALUE
1617+
rb_dir_getwd_ospath(void)
1618+
{
1619+
char buf[PATH_MAX];
1620+
char *path = getcwd(buf, PATH_MAX);
1621+
if (!path) {
1622+
return rb_dir_getwd_ospath_slowpath();
1623+
}
1624+
1625+
VALUE cached_cwd = RUBY_ATOMIC_VALUE_LOAD(last_cwd);
1626+
1627+
if (!cached_cwd || strcmp(RSTRING_PTR(cached_cwd), path) != 0) {
1628+
#ifdef __APPLE__
1629+
cached_cwd = rb_str_normalize_ospath(path, strlen(path));
1630+
#else
1631+
cached_cwd = rb_str_new2(path);
1632+
#endif
1633+
rb_str_freeze(cached_cwd);
1634+
RUBY_ATOMIC_VALUE_SET(last_cwd, cached_cwd);
1635+
}
1636+
return cached_cwd;
1637+
}
16131638
#endif
16141639

16151640
VALUE
16161641
rb_dir_getwd(void)
16171642
{
16181643
rb_encoding *fs = rb_filesystem_encoding();
16191644
int fsenc = rb_enc_to_index(fs);
1620-
VALUE cwd = rb_dir_getwd_ospath();
1645+
VALUE cwd = rb_str_new_shared(rb_dir_getwd_ospath());
16211646

16221647
switch (fsenc) {
16231648
case ENCINDEX_US_ASCII:
@@ -4008,6 +4033,7 @@ Init_Dir(void)
40084033

40094034
rb_gc_register_address(&chdir_lock.path);
40104035
rb_gc_register_address(&chdir_lock.thread);
4036+
rb_gc_register_address(&last_cwd);
40114037

40124038
rb_cDir = rb_define_class("Dir", rb_cObject);
40134039

file.c

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,15 @@ rb_str_normalize_ospath(const char *ptr, long len)
380380
const char *p = ptr;
381381
const char *e = ptr + len;
382382
const char *p1 = p;
383-
VALUE str = rb_str_buf_new(len);
384383
rb_encoding *enc = rb_utf8_encoding();
385-
rb_enc_associate(str, enc);
384+
VALUE str = rb_utf8_str_new(ptr, len);
385+
if (RB_LIKELY(rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT)) {
386+
return str;
387+
}
388+
else {
389+
str = rb_str_buf_new(len);
390+
rb_enc_associate(str, enc);
391+
}
386392

387393
while (p < e) {
388394
int l, c;
@@ -1095,12 +1101,26 @@ static VALUE statx_birthtime(const rb_io_stat_data *st);
10951101

10961102
/*
10971103
* call-seq:
1098-
* stat.atime -> time
1099-
*
1100-
* Returns the last access time for this file as an object of class
1101-
* Time.
1102-
*
1103-
* File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
1104+
* atime -> new_time
1105+
*
1106+
* Returns a new Time object containing the access time
1107+
* of the object represented by +self+
1108+
* at the time +self+ was created;
1109+
* see {Snapshot}[rdoc-ref:File::Stat@Snapshot]:
1110+
*
1111+
* filepath = 't.tmp'
1112+
* File.write(filepath, 'foo')
1113+
* file = File.new(filepath, 'w')
1114+
* stat = File::Stat.new(filepath)
1115+
* file.atime # => 2026-03-31 16:26:39.5913207 -0500
1116+
* stat.atime # => 2026-03-31 16:26:39.5913207 -0500
1117+
* File.write(filepath, 'bar')
1118+
* file.atime # => 2026-03-31 16:27:01.4981624 -0500 # Changed by access.
1119+
* stat.atime # => 2026-03-31 16:26:39.5913207 -0500 # Unchanged by access.
1120+
* stat = File::Stat.new(filepath)
1121+
* stat.atime # => 2026-03-31 16:27:01.4981624 -0500 # New access time.
1122+
* file.close
1123+
* File.delete(filepath)
11041124
*
11051125
*/
11061126

@@ -2446,13 +2466,23 @@ rb_file_s_ftype(VALUE klass, VALUE fname)
24462466

24472467
/*
24482468
* call-seq:
2449-
* File.atime(file_name) -> time
2469+
* File.atime(object) -> new_time
24502470
*
2451-
* Returns the last access time for the named file as a Time object.
2471+
* Returns a new Time object containing the time of the most recent
2472+
* access (read or write) to the object,
2473+
* which may be a string filepath or dirpath, or a File or Dir object:
24522474
*
2453-
* _file_name_ can be an IO object.
2475+
* filepath = 't.tmp'
2476+
* File.exist?(filepath) # => false
2477+
* File.atime(filepath) # Raises Errno::ENOENT.
2478+
* File.write(filepath, 'foo')
2479+
* File.atime(filepath) # => 2026-03-31 16:39:37.9290772 -0500
2480+
* File.write(filepath, 'bar')
2481+
* File.atime(filepath) # => 2026-03-31 16:39:57.7710876 -0500
24542482
*
2455-
* File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
2483+
* File.atime('.') # => 2026-03-31 16:47:49.0970483 -0500
2484+
* File.atime(File.new('README.md')) # => 2026-03-31 11:15:27.8215934 -0500
2485+
* File.atime(Dir.new('.')) # => 2026-03-31 12:39:45.5910591 -0500
24562486
*
24572487
*/
24582488

@@ -2471,12 +2501,20 @@ rb_file_s_atime(VALUE klass, VALUE fname)
24712501

24722502
/*
24732503
* call-seq:
2474-
* file.atime -> time
2504+
* atime -> new_time
24752505
*
2476-
* Returns the last access time (a Time object) for <i>file</i>, or
2477-
* epoch if <i>file</i> has not been accessed.
2506+
* Returns a new Time object containing the time of the most recent
2507+
* access (read or write) to the file represented by +self+:
24782508
*
2479-
* File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
2509+
* filepath = 't.tmp'
2510+
* file = File.new(filepath, 'a+')
2511+
* file.atime # => 2026-03-31 17:11:27.7285397 -0500
2512+
* file.write('foo')
2513+
* file.atime # => 2026-03-31 17:11:27.7285397 -0500 # Unchanged; not yet written.
2514+
* file.flush
2515+
* file.atime # => 2026-03-31 17:12:11.3408054 -0500 # Changed; now written.
2516+
* file.close
2517+
* File.delete(filename)
24802518
*
24812519
*/
24822520

@@ -3707,8 +3745,9 @@ skipprefixroot(const char *path, const char *end, rb_encoding *enc)
37073745
#endif
37083746
}
37093747

3710-
char *
3711-
rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
3748+
3749+
static char *
3750+
enc_path_last_separator(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
37123751
{
37133752
char *last = NULL;
37143753
while (path < end) {
@@ -3719,17 +3758,22 @@ rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
37193758
last = (char *)tmp;
37203759
}
37213760
else {
3722-
Inc(path, end, true, enc);
3761+
Inc(path, end, mb_enc, enc);
37233762
}
37243763
}
37253764
return last;
37263765
}
3766+
char *
3767+
rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
3768+
{
3769+
return enc_path_last_separator(path, end, true, enc);
3770+
}
37273771

37283772
static inline char *
37293773
strrdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
37303774
{
37313775
if (RB_UNLIKELY(mb_enc)) {
3732-
return rb_enc_path_last_separator(path, end, enc);
3776+
return enc_path_last_separator(path, end, mb_enc, enc);
37333777
}
37343778

37353779
const char *cursor = end - 1;
@@ -4021,7 +4065,12 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
40214065

40224066
s = StringValuePtr(fname);
40234067
fend = s + RSTRING_LEN(fname);
4024-
enc = rb_enc_get(fname);
4068+
enc = rb_str_enc_get(fname);
4069+
bool mb_enc = !rb_str_encindex_fastpath(rb_enc_to_index(enc));
4070+
if (!mb_enc && RTEST(dname)) {
4071+
mb_enc = !rb_str_encindex_fastpath(rb_enc_to_index(rb_str_enc_get(dname)));
4072+
}
4073+
40254074
BUFINIT();
40264075

40274076
if (s < fend && s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
@@ -4115,7 +4164,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41154164
}
41164165
else
41174166
#endif /* defined DOSISH || defined __CYGWIN__ */
4118-
p = chompdirsep(skiproot(buf, p), p, true, enc);
4167+
p = chompdirsep(skiproot(buf, p), p, mb_enc, enc);
41194168
}
41204169
else {
41214170
size_t len;
@@ -4139,7 +4188,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41394188
rb_str_set_len(result, p-buf+1);
41404189
BUFCHECK(bdiff + 1 >= buflen);
41414190
p[1] = 0;
4142-
root = skipprefix(buf, p+1, true, enc);
4191+
root = skipprefix(buf, p+1, mb_enc, enc);
41434192

41444193
b = s;
41454194
while (s < fend) {
@@ -4156,7 +4205,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41564205
/* We must go back to the parent */
41574206
char *n;
41584207
*p = '\0';
4159-
if (!(n = strrdirsep(root, p, true, enc))) {
4208+
if (!(n = strrdirsep(root, p, mb_enc, enc))) {
41604209
*p = '/';
41614210
}
41624211
else {
@@ -4219,7 +4268,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
42194268
}
42204269
}
42214270
#endif /* __APPLE__ */
4222-
Inc(s, fend, true, enc);
4271+
Inc(s, fend, mb_enc, enc);
42234272
break;
42244273
}
42254274
}

hash.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ RHASH_AR_TABLE_SIZE_DEC(VALUE h)
604604
static inline void
605605
RHASH_AR_TABLE_CLEAR(VALUE h)
606606
{
607+
RUBY_ASSERT(rb_gc_obj_slot_size(h) >= sizeof(struct RHash) + sizeof(ar_table));
607608
RBASIC(h)->flags &= ~RHASH_AR_TABLE_SIZE_MASK;
608609
RBASIC(h)->flags &= ~RHASH_AR_TABLE_BOUND_MASK;
609610

@@ -719,6 +720,8 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
719720
st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
720721
unsigned int bound, size;
721722

723+
RUBY_ASSERT(rb_gc_obj_slot_size(hash) >= sizeof(struct RHash) + sizeof(ar_table));
724+
722725
// prepare hash values
723726
do {
724727
st_data_t keys[RHASH_AR_TABLE_MAX_SIZE];

internal/object.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass)
6464
static inline size_t
6565
rb_obj_embedded_size(uint32_t fields_count)
6666
{
67-
#if (defined(RACTOR_CHECK_MODE) && RACTOR_CHECK_MODE) || (defined(GC_DEBUG) && GC_DEBUG)
68-
if (fields_count < 1) fields_count = 1;
69-
#endif
70-
return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
67+
size_t size = offsetof(struct RObject, as.ary) + (sizeof(VALUE) * fields_count);
68+
// Ensure enough room for the heap pointer if this expands
69+
if (size < sizeof(struct RObject)) size = sizeof(struct RObject);
70+
return size;
7171
}
7272
#endif /* INTERNAL_OBJECT_H */

0 commit comments

Comments
 (0)