From b89e6ef51789dfd6b1b3555246db228dda6dd428 Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Thu, 25 Dec 2025 17:53:24 -0500 Subject: [PATCH 1/3] Stop locking frozen strings Locking a frozen string now raises an exception: https://bugs.ruby-lang.org/issues/20998 Locking should not be necessary: we know for a fact a frozen string can't be modified, so let's just not lock. --- ext/src/helpers/tmplock.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ext/src/helpers/tmplock.rs b/ext/src/helpers/tmplock.rs index 5d6a5c6f..301c959b 100644 --- a/ext/src/helpers/tmplock.rs +++ b/ext/src/helpers/tmplock.rs @@ -1,11 +1,12 @@ use magnus::{ rb_sys::{protect, AsRawValue}, + value::ReprValue, RString, }; pub trait Tmplock { - fn as_locked_slice(&self) -> Result<(&[u8], TmplockGuard), magnus::Error>; - fn as_locked_str(&self) -> Result<(&str, TmplockGuard), magnus::Error>; + fn as_locked_slice(&self) -> Result<(&[u8], Option), magnus::Error>; + fn as_locked_str(&self) -> Result<(&str, Option), magnus::Error>; } #[derive(Debug)] @@ -25,20 +26,28 @@ impl Drop for TmplockGuard { } impl Tmplock for RString { - fn as_locked_slice(&self) -> Result<(&[u8], TmplockGuard), magnus::Error> { + fn as_locked_slice(&self) -> Result<(&[u8], Option), magnus::Error> { let raw = self.as_raw(); let slice = unsafe { self.as_slice() }; - let raw = protect(|| unsafe { rb_sys::rb_str_locktmp(raw) })?; - let guard = TmplockGuard { raw }; + let guard = if self.is_frozen() { + None + } else { + let raw = protect(|| unsafe { rb_sys::rb_str_locktmp(raw) })?; + Some(TmplockGuard { raw }) + }; Ok((slice, guard)) } - fn as_locked_str(&self) -> Result<(&str, TmplockGuard), magnus::Error> { + fn as_locked_str(&self) -> Result<(&str, Option), magnus::Error> { let str_result = unsafe { self.as_str()? }; - let raw = self.as_raw(); - let raw = protect(|| unsafe { rb_sys::rb_str_locktmp(raw) })?; - let guard = TmplockGuard { raw }; + let guard = if self.is_frozen() { + None + } else { + let raw = self.as_raw(); + let raw = protect(|| unsafe { rb_sys::rb_str_locktmp(raw) })?; + Some(TmplockGuard { raw }) + }; Ok((str_result, guard)) } From 38c072030b212c70145638826149c00b21e02ba4 Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Thu, 25 Dec 2025 17:57:37 -0500 Subject: [PATCH 2/3] Use Ruby 4.0 for all workflows --- .github/workflows/build-docs.yml | 2 +- .github/workflows/build-gems.yml | 4 ++-- .github/workflows/memcheck.yml | 5 +++-- .github/workflows/release.yml | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index cd572bbd..84a01a76 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -26,7 +26,7 @@ jobs: - uses: oxidize-rb/actions/setup-ruby-and-rust@v1 with: - ruby-version: "3.4" + ruby-version: "4.0" rustup-toolchain: "${{ env.NIGHTLY_VERSION }}" bundler-cache: true cargo-cache: true diff --git a/.github/workflows/build-gems.yml b/.github/workflows/build-gems.yml index b117a0b6..f97df94b 100644 --- a/.github/workflows/build-gems.yml +++ b/.github/workflows/build-gems.yml @@ -42,7 +42,7 @@ jobs: - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.4" + ruby-version: "4.0" - uses: oxidize-rb/actions/cross-gem@v1 id: cross-gem @@ -66,7 +66,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest"] - ruby: ["3.4"] + ruby: ["4.0"] steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/memcheck.yml b/.github/workflows/memcheck.yml index 66c769d7..af9e6eb3 100644 --- a/.github/workflows/memcheck.yml +++ b/.github/workflows/memcheck.yml @@ -7,10 +7,11 @@ on: ruby-version: description: "Ruby version to memcheck" required: true - default: "3.4" + default: "4.0" type: choice options: - "head" + - "4.0" - "3.4" - "3.3" - "3.2" @@ -38,7 +39,7 @@ jobs: - uses: oxidize-rb/actions/setup-ruby-and-rust@v1 with: - ruby-version: ${{ inputs.ruby-version || '3.4' }} + ruby-version: ${{ inputs.ruby-version || '4.0' }} bundler-cache: true cargo-cache: true cache-version: v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e53a7c96..b5e19d40 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.4" + ruby-version: "4.0" - uses: oxidize-rb/actions/cross-gem@v1 id: cross-gem @@ -73,7 +73,7 @@ jobs: - uses: oxidize-rb/actions/setup-ruby-and-rust@v1 with: - ruby-version: "3.4" + ruby-version: "4.0" bundler-cache: true cargo-cache: true cache-version: v1 From cf27359d2d340831fe60e6a428c05f0ad6ce3e85 Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Thu, 25 Dec 2025 18:09:49 -0500 Subject: [PATCH 3/3] Adapt Ractor spec for Ruby 4.0 --- spec/integration/ractor_spec.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/integration/ractor_spec.rb b/spec/integration/ractor_spec.rb index 5ae9b5e0..e61727c6 100644 --- a/spec/integration/ractor_spec.rb +++ b/spec/integration/ractor_spec.rb @@ -21,7 +21,7 @@ Wasmtime::Instance.new(store, mod).invoke("hello") end - result = r.take + result = value(r) expect(result).to eq([1, 2, 3.0, 4.0]) end @@ -42,7 +42,13 @@ end ractors.each do |ractor| - expect(ractor.take).to eq([1, 2, 3.0, 4.0]) + expect(value(ractor)).to eq([1, 2, 3.0, 4.0]) end end + + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("4.0") + def value(ractor) = ractor.value + else + def value(ractor) = ractor.take + end end