diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03227bcd7234fd..3caeee9a3b8796 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,9 +49,9 @@ jobs: - name: Create a release on GitHub run: | - RELEASE_TAG=$(echo v${{ env.RUBY_VERSION }} | sed 's/\./_/g') + RELEASE_TAG=$(ruby tool/ruby-version.rb tag "${{ env.RUBY_VERSION }}") echo $RELEASE_TAG - PREVIOUS_RELEASE_TAG=$(echo $RELEASE_TAG | awk 'BEGIN {FS="_"; OFS="_"}{ $NF=$NF-1; print }') + PREVIOUS_RELEASE_TAG=$(ruby tool/ruby-version.rb previous-tag "${{ env.RUBY_VERSION }}") echo $PREVIOUS_RELEASE_TAG tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run env: diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 8d9f9ddd80be6b..ae11a61481e74e 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -262,7 +262,6 @@ struct ifaddrs { #endif extern void rb_w32_sysinit(int *, char ***); -extern DWORD rb_w32_osid(void); extern int flock(int fd, int oper); extern int rb_w32_io_cancelable_p(int); extern int rb_w32_is_socket(int); @@ -306,7 +305,11 @@ extern void rb_w32_free_environ(char **); extern int rb_w32_map_errno(DWORD); extern const char *WSAAPI rb_w32_inet_ntop(int,const void *,char *,size_t); extern int WSAAPI rb_w32_inet_pton(int,const char *,void *); -extern DWORD rb_w32_osver(void); + +RBIMPL_ATTR_DEPRECATED(("as Windows 9x is not supported already")) +static inline DWORD rb_w32_osid(void) {return VER_PLATFORM_WIN32_NT;} +RBIMPL_ATTR_DEPRECATED(("by Windows Version Helper APIs")) +extern DWORD rb_w32_osver(void); extern int rb_w32_uchown(const char *, int, int); extern int rb_w32_ulink(const char *, const char *); diff --git a/proc.c b/proc.c index 2df8fbee5e23a9..1a57757d846ceb 100644 --- a/proc.c +++ b/proc.c @@ -640,6 +640,10 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym) const rb_env_t *env; if (!lid) return Qfalse; + if (rb_numparam_id_p(lid)) { + rb_name_err_raise("numbered parameter '%1$s' is not a local variable", + bindval, ID2SYM(lid)); + } GetBindingPtr(bindval, bind); env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block)); diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index 2cd97ca32464ab..2eeb7a94ebb706 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -1659,29 +1659,35 @@ def test_numparam_is_not_local_variables assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } "bar".tap do assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } end assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } end "foo".tap do assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } "bar".tap do _9 and flunk assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } end assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:_9) } assert_raise(NameError) { binding.local_variable_set(:_9, 1) } + assert_raise(NameError) { binding.local_variable_defined?(:_9) } end end @@ -1690,31 +1696,39 @@ def test_it_is_not_local_variable it assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) "bar".tap do assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) end assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) "bar".tap do it assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) end assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) end "foo".tap do assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) "bar".tap do it assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) end assert_equal([], binding.local_variables) assert_raise(NameError) { binding.local_variable_get(:it) } + assert_equal(false, binding.local_variable_defined?(:it)) end end diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index 49b3616425ecd3..232c46079f5b38 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -626,6 +626,15 @@ def entry = test(e: :e, d: :d, c: :c, a: :a, b: :b) }, call_threshold: 2 end + def test_send_kwsplat + assert_compiles '3', %q{ + def test(a:) = a + def entry = test(**{a: 3}) + entry + entry + }, call_threshold: 2 + end + def test_send_kwrest assert_compiles '{a: 3}', %q{ def test(**kwargs) = kwargs diff --git a/thread_pthread_mn.c b/thread_pthread_mn.c index 2211d4d1067c39..ad4d0915e790b2 100644 --- a/thread_pthread_mn.c +++ b/thread_pthread_mn.c @@ -1078,12 +1078,12 @@ timer_thread_polling(rb_vm_t *vm) switch (r) { case 0: // timeout - rb_native_mutex_lock(&vm->ractor.sched.lock); + ractor_sched_lock(vm, NULL); { // (1-1) timeslice timer_thread_check_timeslice(vm); } - rb_native_mutex_unlock(&vm->ractor.sched.lock); + ractor_sched_unlock(vm, NULL); break; case -1: // error diff --git a/tool/format-release b/tool/format-release index b38263f9f4fb05..8bb61542433fb2 100755 --- a/tool/format-release +++ b/tool/format-release @@ -9,6 +9,7 @@ end require "open-uri" require "yaml" +require_relative "./ruby-version" Diffy::Diff.default_options.merge!( include_diff_info: true, @@ -54,30 +55,10 @@ eom unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version raise "unexpected version string '#{version}'" end - x = $1.to_i - y = $2.to_i - z = $3.to_i - # previous tag for git diff --shortstat - # It's only for x.y.0 release - if z != 0 - prev_tag = nil - elsif y != 0 - prev_ver = "#{x}.#{y-1}.0" - prev_tag = version_tag(prev_ver) - else # y == 0 && z == 0 - case x - when 3 - prev_ver = "2.7.0" - when 4 - prev_ver = "3.4.0" - else - raise "it doesn't know what is the previous version of '#{version}'" - end - prev_tag = version_tag(prev_ver) - end + teeny = Integer($3) uri = "https://cache.ruby-lang.org/pub/tmp/ruby-info-#{version}-draft.yml" - info = YAML.load(URI(uri).read) + info = YAML.unsafe_load(URI(uri).read) if info.size != 1 raise "unexpected info.yml '#{uri}'" end @@ -92,9 +73,10 @@ eom tarballs << tarball end - if prev_tag + if teeny == 0 # show diff shortstat - tag = version_tag(version) + tag = RubyVersion.tag(version) + prev_tag = RubyVersion.tag(RubyVersion.previous(version)) stat = `git -C #{rubydir} diff -l0 --shortstat #{prev_tag}..#{tag}` files_changed, insertions, deletions = stat.scan(/\d+/) end @@ -188,7 +170,7 @@ eom if /\.0(?:-\w+)?\z/ =~ ver # preview, rc, or first release entry <<= <= 4 - "v#{version}" - else - "v#{version.tr('.-', '_')}" - end - end end def main diff --git a/tool/make-snapshot b/tool/make-snapshot index 041b1a0f2aba6d..4af6a855ebb793 100755 --- a/tool/make-snapshot +++ b/tool/make-snapshot @@ -272,10 +272,18 @@ def package(vcs, rev, destdir, tmp = nil) when /\A(\d+)\.(\d+)\.(\d+)-(preview|rc)(\d+)/ prerelease = true tag = "#{$4}#{$5}" - url = vcs.tag("v#{$1}_#{$2}_#{$3}_#{$4}#{$5}") + if Integer($1) >= 4 + url = vcs.tag("v#{rev}") + else + url = vcs.tag("v#{$1}_#{$2}_#{$3}_#{$4}#{$5}") + end when /\A(\d+)\.(\d+)\.(\d+)\z/ tag = "" - url = vcs.tag("v#{$1}_#{$2}_#{$3}") + if Integer($1) >= 4 + url = vcs.tag("v#{rev}") + else + url = vcs.tag("v#{$1}_#{$2}_#{$3}") + end when /\A(\d+)\.(\d+)\z/ url = vcs.branch("ruby_#{rev.tr('.', '_')}") else diff --git a/tool/releng/update-www-meta.rb b/tool/releng/update-www-meta.rb index 100f0bee181806..0dd5b2563122e7 100755 --- a/tool/releng/update-www-meta.rb +++ b/tool/releng/update-www-meta.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require "open-uri" require "yaml" +require_relative "../ruby-version" class Tarball attr_reader :version, :size, :sha1, :sha256, :sha512 @@ -41,27 +42,7 @@ def self.parse(wwwdir, version) unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version raise "unexpected version string '#{version}'" end - x = $1.to_i - y = $2.to_i - z = $3.to_i - # previous tag for git diff --shortstat - # It's only for x.y.0 release - if z != 0 - prev_tag = nil - elsif y != 0 - prev_ver = "#{x}.#{y-1}.0" - prev_tag = version_tag(prev_ver) - else # y == 0 && z == 0 - case x - when 3 - prev_ver = "2.7.0" - when 4 - prev_ver = "3.4.0" - else - raise "it doesn't know what is the previous version of '#{version}'" - end - prev_tag = version_tag(prev_ver) - end + teeny = Integer($3) uri = "https://cache.ruby-lang.org/pub/tmp/ruby-info-#{version}-draft.yml" info = YAML.load(URI(uri).read) @@ -79,9 +60,10 @@ def self.parse(wwwdir, version) tarballs << tarball end - if prev_tag + if teeny == 0 # show diff shortstat - tag = version_tag(version) + tag = RubyVersion.tag(version) + prev_tag = RubyVersion.tag(RubyVersion.previous(version)) rubydir = File.expand_path(File.join(__FILE__, '../../../')) puts %`git -C #{rubydir} diff --shortstat #{prev_tag}..#{tag}` stat = `git -C #{rubydir} diff --shortstat #{prev_tag}..#{tag}` @@ -160,7 +142,7 @@ def self.update_releases_yml(ver, xy, ary, wwwdir, files_changed, insertions, de date = Time.now.utc # use utc to use previous day in midnight entry = <= 4 - "v#{version}" - else - "v#{version.tr('.-', '_')}" - end - end end # Confirm current directory is www.ruby-lang.org's working directory diff --git a/tool/ruby-version.rb b/tool/ruby-version.rb new file mode 100755 index 00000000000000..3bbec576e13ad4 --- /dev/null +++ b/tool/ruby-version.rb @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby + +module RubyVersion + def self.tag(version) + major_version = Integer(version.split('.', 2)[0]) + if major_version >= 4 + "v#{version}" + else + "v#{version.tr('.-', '_')}" + end + end + + # Return the previous version to be used for release diff links. + # For a ".0" version, it returns the previous ".0" version. + # For a non-".0" version, it returns the previous teeny version. + def self.previous(version) + unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version + raise "unexpected version string '#{version}'" + end + major = Integer($1) + minor = Integer($2) + teeny = Integer($3) + + if teeny != 0 + "#{major}.#{minor}.#{teeny-1}" + elsif minor != 0 # && teeny == 0 + "#{major}.#{minor-1}.#{teeny}" + else # minor == 0 && teeny == 0 + case major + when 3 + "2.7.0" + when 4 + "3.4.0" + else + raise "it doesn't know what is the previous version of '#{version}'" + end + end + end +end + +if __FILE__ == $0 + case ARGV[0] + when "tag" + print RubyVersion.tag(ARGV[1]) + when "previous" + print RubyVersion.previous(ARGV[1]) + when "previous-tag" + print RubyVersion.tag(RubyVersion.previous(ARGV[1])) + else + "#{$0}: unexpected command #{ARGV[0].inspect}" + end +end diff --git a/win32/win32.c b/win32/win32.c index 66ce195092f5e5..97dc7148085c55 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -314,15 +314,6 @@ get_version(void) GetVersionEx(&osver); } -#ifdef _M_IX86 -/* License: Artistic or GPL */ -DWORD -rb_w32_osid(void) -{ - return osver.dwPlatformId; -} -#endif - /* License: Artistic or GPL */ DWORD rb_w32_osver(void) @@ -7223,9 +7214,6 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset) size_t len; size_t ret; OVERLAPPED ol; - BOOL isconsole; - BOOL islineinput = FALSE; - int start = 0; if (is_socket(sock)) return rb_w32_recv(fd, buf, size, 0); @@ -7248,25 +7236,8 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset) } ret = 0; - isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2)); - if (isconsole) { - DWORD mode; - GetConsoleMode((HANDLE)_osfhnd(fd),&mode); - islineinput = (mode & ENABLE_LINE_INPUT) != 0; - } retry: - /* get rid of console reading bug */ - if (isconsole) { - constat_reset((HANDLE)_osfhnd(fd)); - if (start) - len = 1; - else { - len = 0; - start = 1; - } - } - else - len = size; + len = size; size -= len; if (setup_overlapped(&ol, fd, FALSE, offset)) { @@ -7337,8 +7308,7 @@ rb_w32_read_internal(int fd, void *buf, size_t size, rb_off_t *offset) ret += read; if (read >= len) { buf = (char *)buf + read; - if (err != ERROR_OPERATION_ABORTED && - !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0) + if (err != ERROR_OPERATION_ABORTED && size > 0) goto retry; } if (read == 0) diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 4992f177991d47..1cdc5e003a7cf2 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -5229,6 +5229,7 @@ fn unspecializable_c_call_type(flags: u32) -> bool { /// If a given call uses overly complex arguments, then we won't specialize. fn unspecializable_call_type(flags: u32) -> bool { ((flags & VM_CALL_ARGS_SPLAT) != 0) || + ((flags & VM_CALL_KW_SPLAT) != 0) || ((flags & VM_CALL_ARGS_BLOCKARG) != 0) } diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index a602121a0cc51d..3946c9d03c0714 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -2993,6 +2993,33 @@ mod hir_opt_tests { "); } + #[test] + fn dont_specialize_call_to_iseq_with_call_kwsplat() { + eval(" + def foo(a:) = a + def test = foo(**{a: 1}) + test + test + "); + assert_snapshot!(hir_string("test"), @r" + fn test@:3: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + Jump bb2(v1) + bb1(v4:BasicObject): + EntryPoint JIT(0) + Jump bb2(v4) + bb2(v6:BasicObject): + v11:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v12:HashExact = HashDup v11 + IncrCounter complex_arg_pass_caller_kw_splat + v14:BasicObject = SendWithoutBlock v6, :foo, v12 # SendFallbackReason: Complex argument passing + CheckInterrupts + Return v14 + "); + } + #[test] fn dont_specialize_call_to_iseq_with_param_kwrest() { eval("