Skip to content

Commit e7103f0

Browse files
committed
[GR-37533] Backports for 24.0 batch 1
PullRequest: truffleruby/4170
2 parents 8e1f1e9 + 7017629 commit e7103f0

File tree

85 files changed

+951
-671
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+951
-671
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
New features:
44

55
* C/C++ extensions are now compiled using the system toolchain and executed natively instead of using GraalVM LLVM (Sulong). This leads to faster startup, no warmup, better compatibility, smaller distribution and faster installation for C/C++ extensions (#3118, @eregon).
6-
* Full suport for the Ruby 3.2 and Ruby 3.3 syntax by adopting the [Prism](https://github.com/ruby/prism) parser, which is about twice as fast as the old parser (#3117, #3038, #3039, @andrykonchin, @eregon).
7-
* Pattern matching is now fully supported, with the exception of Find pattern (`in [*, a, *]`) (#3332, #2683, @eregon, @razetime).
6+
* Full support for the Ruby 3.2 and Ruby 3.3 syntax by adopting the [Prism](https://github.com/ruby/prism) parser, which is about twice as fast as the old parser (#3117, #3038, #3039, @andrykonchin, @eregon).
7+
* Pattern matching is now fully supported (#3332, #2683, @eregon, @razetime).
88

99
Bug fixes:
1010

@@ -21,6 +21,7 @@ Bug fixes:
2121
* Fix using the `--cpusampler` profiler when there are custom unblock functions for `rb_thread_call_without_gvl()` (#3013, @eregon).
2222
* Fix recursive raising `FrozenError` exception when redefined `#inspect` modifies an object (#3388, @andrykonchin).
2323
* Fix `Integer#div` returning the wrong object type when the divisor is a `Rational` (@simonlevasseur, @nirvdrum).
24+
* Remove constant `Random::DEFAULT` (#3039, @patricklinpl)
2425

2526
Compatibility:
2627

@@ -45,6 +46,14 @@ Compatibility:
4546
* Support passing anonymous * and ** parameters as method call arguments (#3039, @andrykonchin).
4647
* Handle either positional or keywords arguments by default in `Struct.new` (#3039, @rwstauner).
4748
* Promote `Set` class to core library (#3039, @andrykonchin).
49+
* Support `connect_timeout` keyword argument to `TCPSocket.{new,open}` (#3421, @manefz, @patricklinpl, @nirvdrum, @rwstauner).
50+
* Add `File.lutime` and `Pathname#lutime` methods (#3039, @andrykonchin).
51+
* Add a deprecation warning for `Encoding#replicate` (#3039, @patricklinpl, @manefz, @nirvdrum).
52+
* Change `UnboundMethod#{==,inspect}` to use the owner module rather than the origin (#3039, @rwstauner, @manefz, @patricklinpl)
53+
* Support `lambda` keyword argument in `Proc#parameters` (#3039, @thomasmarshall, @goyox86).
54+
* Limit maximum encoding set size by 256 (#3039, @thomasmarshall, @goyox86).
55+
* Remove deprecated methods `Dir.exists?`, `File.exists?`, and `Kernel#=~` (#3039, @patricklinpl, @nirvdrum).
56+
* Remove deprecated `FileTest.exists?` method (#3039, @andrykonchin).
4857

4958
Performance:
5059

doc/user/compatibility.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ The JVM enforces a maximum array size of 2<sup>31</sup>-1 (by storing the size i
121121
That is, Strings must be smaller than 2GB. This is the same restriction as JRuby.
122122
A possible workaround could be to use natively-allocated strings, but it would be a large effort to support every Ruby String operation on native strings.
123123

124+
### Strings in UTF-16 and UTF-32 encoding
125+
126+
TruffleRuby does not support UTF-16 strings with an odd number of bytes (in native endianness). Similarly, with UTF-32 it needs to be a multiple of 4. This is necessary for optimizations, compression, invariants, etc.
127+
124128
### Threads detect interrupts at different points
125129

126130
TruffleRuby threads may detect that they have been interrupted at different points in the program compared to where they would on MRI.

lib/truffle/pathname.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,10 @@ def truncate(length) File.truncate(@path, length) end
896896
# See <tt>File.utime</tt>. Update the access and modification times.
897897
def utime(atime, mtime) File.utime(atime, mtime, @path) end
898898

899+
# See <tt>File.lutime</tt>. Update the access and modification times.
900+
# Same as Pathname#utime, but does not follow symbolic links.
901+
def lutime(atime, mtime) File.lutime(atime, mtime, @path) end
902+
899903
# See <tt>File.basename</tt>. Returns the last component of the path.
900904
def basename(*args) self.class.new(File.basename(@path, *args)) end
901905

@@ -1084,10 +1088,6 @@ def unlink()
10841088
alias delete unlink
10851089
end
10861090

1087-
class Pathname
1088-
undef =~
1089-
end
1090-
10911091
module Kernel
10921092
# create a pathname object.
10931093
#

lib/truffle/socket/tcp_socket.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def self.gethostbyname(hostname)
4444
[hostname, alternatives, family, *addresses]
4545
end
4646

47-
def initialize(host, service, local_host = nil, local_service = nil)
47+
def initialize(host, service, local_host = nil, local_service = nil, connect_timeout: nil)
4848
@no_reverse_lookup = Primitive.class(self).do_not_reverse_lookup
4949

5050
if host
@@ -108,7 +108,7 @@ def initialize(host, service, local_host = nil, local_service = nil)
108108
end
109109

110110
connect_status = Truffle::Socket::Foreign
111-
.connect(descriptor, Socket.sockaddr_in(port, address))
111+
.connect(descriptor, Socket.sockaddr_in(port, address), connect_timeout)
112112

113113
break if connect_status >= 0
114114
end

lib/truffle/socket/truffle/foreign.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2828
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

30+
require 'timeout'
31+
3032
module Truffle
3133
module Socket
3234
module Foreign
@@ -107,14 +109,23 @@ def self.bind(descriptor, sockaddr)
107109
end
108110
end
109111

110-
def self.connect(descriptor, sockaddr)
112+
def self.connect(descriptor, sockaddr, connect_timeout = nil)
111113
sockaddr = Socket.coerce_to_string(sockaddr)
112114

113115
sockaddr_p = Primitive.io_thread_buffer_allocate(sockaddr.bytesize)
114116
begin
115117
sockaddr_p.write_bytes(sockaddr)
116118

117-
_connect(descriptor, sockaddr_p, sockaddr.bytesize)
119+
if Primitive.nil?(connect_timeout)
120+
_connect(descriptor, sockaddr_p, sockaddr.bytesize)
121+
else
122+
# In CRuby a connect_timeout of 0 fires immediately whereas a 0 for
123+
# Timeout.timeout means "no timeout", so we change 0 to 1ns
124+
# (the smallest time interval for clock_gettime).
125+
Timeout.timeout(connect_timeout == 0 ? 0.000000001 : connect_timeout, IO::TimeoutError) do
126+
_connect(descriptor, sockaddr_p, sockaddr.bytesize)
127+
end
128+
end
118129
ensure
119130
Primitive.io_thread_buffer_free(sockaddr_p)
120131
end

spec/ruby/core/encoding/replicate_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
Encoding::US_ASCII.replicate('MY-US-ASCII')
7474
}.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
7575
end
76+
77+
it "raises EncodingError if too many encodings" do
78+
code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
79+
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
80+
end
7681
end
7782

7883
ruby_version_is "3.3" do

spec/ruby/core/file/lutime_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
require_relative '../../spec_helper'
2+
require_relative 'shared/update_time'
3+
4+
describe "File.lutime" do
5+
it_behaves_like :update_time, :lutime
6+
end
27

38
describe "File.lutime" do
49
platform_is_not :windows do
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
describe :update_time, shared: true do
2+
before :all do
3+
@time_is_float = platform_is :windows
4+
end
5+
6+
before :each do
7+
@atime = Time.now
8+
@mtime = Time.now
9+
@file1 = tmp("specs_file_utime1")
10+
@file2 = tmp("specs_file_utime2")
11+
touch @file1
12+
touch @file2
13+
end
14+
15+
after :each do
16+
rm_r @file1, @file2
17+
end
18+
19+
it "sets the access and modification time of each file" do
20+
File.send(@method, @atime, @mtime, @file1, @file2)
21+
22+
if @time_is_float
23+
File.atime(@file1).should be_close(@atime, 0.0001)
24+
File.mtime(@file1).should be_close(@mtime, 0.0001)
25+
File.atime(@file2).should be_close(@atime, 0.0001)
26+
File.mtime(@file2).should be_close(@mtime, 0.0001)
27+
else
28+
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
29+
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
30+
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
31+
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
32+
end
33+
end
34+
35+
it "uses the current times if two nil values are passed" do
36+
tn = Time.now
37+
File.send(@method, nil, nil, @file1, @file2)
38+
39+
if @time_is_float
40+
File.atime(@file1).should be_close(tn, 0.050)
41+
File.mtime(@file1).should be_close(tn, 0.050)
42+
File.atime(@file2).should be_close(tn, 0.050)
43+
File.mtime(@file2).should be_close(tn, 0.050)
44+
else
45+
File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
46+
File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
47+
File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
48+
File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
49+
end
50+
end
51+
52+
it "accepts an object that has a #to_path method" do
53+
File.send(@method, @atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
54+
end
55+
56+
it "accepts numeric atime and mtime arguments" do
57+
if @time_is_float
58+
File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2)
59+
60+
File.atime(@file1).should be_close(@atime, 0.0001)
61+
File.mtime(@file1).should be_close(@mtime, 0.0001)
62+
File.atime(@file2).should be_close(@atime, 0.0001)
63+
File.mtime(@file2).should be_close(@mtime, 0.0001)
64+
else
65+
File.send(@method, @atime.to_i, @mtime.to_i, @file1, @file2)
66+
67+
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
68+
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
69+
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
70+
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
71+
end
72+
end
73+
74+
it "may set nanosecond precision" do
75+
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
76+
File.send(@method, t, t, @file1)
77+
78+
File.atime(@file1).nsec.should.between?(0, 123500000)
79+
File.mtime(@file1).nsec.should.between?(0, 123500000)
80+
end
81+
82+
it "returns the number of filenames in the arguments" do
83+
File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2).should == 2
84+
end
85+
86+
platform_is :linux do
87+
platform_is wordsize: 64 do
88+
it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
89+
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
90+
# "Therefore, timestamps should not overflow until May 2446."
91+
# https://lwn.net/Articles/804382/
92+
# "On-disk timestamps hitting the y2038 limit..."
93+
# The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
94+
# https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
95+
# Amazon Linux 2023 returns 2486-07-02 in this example
96+
# http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
97+
time = Time.at(1<<44)
98+
File.send(@method, time, time, @file1)
99+
100+
[559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
101+
[559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
102+
end
103+
end
104+
end
105+
end

spec/ruby/core/file/utime_spec.rb

Lines changed: 2 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,6 @@
11
require_relative '../../spec_helper'
2+
require_relative 'shared/update_time'
23

34
describe "File.utime" do
4-
5-
before :all do
6-
@time_is_float = platform_is :windows
7-
end
8-
9-
before :each do
10-
@atime = Time.now
11-
@mtime = Time.now
12-
@file1 = tmp("specs_file_utime1")
13-
@file2 = tmp("specs_file_utime2")
14-
touch @file1
15-
touch @file2
16-
end
17-
18-
after :each do
19-
rm_r @file1, @file2
20-
end
21-
22-
it "sets the access and modification time of each file" do
23-
File.utime(@atime, @mtime, @file1, @file2)
24-
if @time_is_float
25-
File.atime(@file1).should be_close(@atime, 0.0001)
26-
File.mtime(@file1).should be_close(@mtime, 0.0001)
27-
File.atime(@file2).should be_close(@atime, 0.0001)
28-
File.mtime(@file2).should be_close(@mtime, 0.0001)
29-
else
30-
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
31-
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
32-
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
33-
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
34-
end
35-
end
36-
37-
it "uses the current times if two nil values are passed" do
38-
tn = Time.now
39-
File.utime(nil, nil, @file1, @file2)
40-
if @time_is_float
41-
File.atime(@file1).should be_close(tn, 0.050)
42-
File.mtime(@file1).should be_close(tn, 0.050)
43-
File.atime(@file2).should be_close(tn, 0.050)
44-
File.mtime(@file2).should be_close(tn, 0.050)
45-
else
46-
File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
47-
File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
48-
File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
49-
File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
50-
end
51-
end
52-
53-
it "accepts an object that has a #to_path method" do
54-
File.utime(@atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
55-
end
56-
57-
it "accepts numeric atime and mtime arguments" do
58-
if @time_is_float
59-
File.utime(@atime.to_f, @mtime.to_f, @file1, @file2)
60-
File.atime(@file1).should be_close(@atime, 0.0001)
61-
File.mtime(@file1).should be_close(@mtime, 0.0001)
62-
File.atime(@file2).should be_close(@atime, 0.0001)
63-
File.mtime(@file2).should be_close(@mtime, 0.0001)
64-
else
65-
File.utime(@atime.to_i, @mtime.to_i, @file1, @file2)
66-
File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
67-
File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
68-
File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
69-
File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
70-
end
71-
end
72-
73-
it "may set nanosecond precision" do
74-
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
75-
File.utime(t, t, @file1)
76-
File.atime(@file1).nsec.should.between?(0, 123500000)
77-
File.mtime(@file1).nsec.should.between?(0, 123500000)
78-
end
79-
80-
it "returns the number of filenames in the arguments" do
81-
File.utime(@atime.to_f, @mtime.to_f, @file1, @file2).should == 2
82-
end
83-
84-
platform_is :linux do
85-
platform_is wordsize: 64 do
86-
it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
87-
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
88-
# "Therefore, timestamps should not overflow until May 2446."
89-
# https://lwn.net/Articles/804382/
90-
# "On-disk timestamps hitting the y2038 limit..."
91-
# The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
92-
# https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
93-
# Amazon Linux 2023 returns 2486-07-02 in this example
94-
# http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
95-
time = Time.at(1<<44)
96-
File.utime(time, time, @file1)
97-
[559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
98-
[559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
99-
end
100-
end
101-
end
5+
it_behaves_like :update_time, :utime
1026
end

spec/ruby/core/filetest/exist_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@
44
describe "FileTest.exist?" do
55
it_behaves_like :file_exist, :exist?, FileTest
66
end
7+
8+
ruby_version_is "3.2" do
9+
describe "FileTest.exists?" do
10+
it "has been removed" do
11+
FileTest.should_not.respond_to?(:exists?)
12+
end
13+
end
14+
end

spec/ruby/core/kernel/not_match_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ def !~(obj)
1414
(obj !~ :foo).should == false
1515
end
1616

17+
ruby_version_is ""..."3.2" do
18+
it "returns true if self does not respond to #=~" do
19+
suppress_warning do
20+
(Object.new !~ :foo).should == true
21+
end
22+
end
23+
end
24+
25+
ruby_version_is "3.2" do
26+
it "raises NoMethodError if self does not respond to #=~" do
27+
-> { Object.new !~ :foo }.should raise_error(NoMethodError)
28+
end
29+
end
30+
1731
it 'can be overridden in subclasses' do
1832
obj = KernelSpecs::NotMatch.new
1933
(obj !~ :bar).should == :foo

0 commit comments

Comments
 (0)