[前][次][番号順一覧][スレッド一覧]

ruby-changes:72089

From: Noah <ko1@a...>
Date: Wed, 8 Jun 2022 00:21:11 +0900 (JST)
Subject: [ruby-changes:72089] 1598c9458a (master): Add special-case code for the String unary plus operator (#5982)

https://git.ruby-lang.org/ruby.git/commit/?id=1598c9458a

From 1598c9458a3ac8e0e4c179317a4e5bba506e3367 Mon Sep 17 00:00:00 2001
From: Noah Gibbs <noah.gibbs@s...>
Date: Tue, 7 Jun 2022 16:20:57 +0100
Subject: Add special-case code for the String unary plus operator (#5982)

---
 bootstraptest/test_yjit.rb     | 27 +++++++++++++++++++++++++++
 yjit/bindgen/src/main.rs       |  1 +
 yjit/src/codegen.rs            | 38 ++++++++++++++++++++++++++++++++++++++
 yjit/src/cruby_bindings.inc.rs |  3 +++
 4 files changed, 69 insertions(+)

diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 503af1ab80..3ae0cdb33a 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1393,6 +1393,33 @@ assert_equal 'foo', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_yjit.rb#L1393
   make_str("foo")
 }
 
+# Test that String unary plus returns the same object ID for an unfrozen string.
+assert_equal '', %q{
+  str = "bar"
+
+  old_obj_id = str.object_id
+  uplus_str = +str
+
+  if uplus_str.object_id != old_obj_id
+    raise "String unary plus on unfrozen should return the string exactly, not a duplicate"
+  end
+
+  ''
+}
+
+# Test that String unary plus returns a different unfrozen string when given a frozen string
+assert_equal 'false', %q{
+  frozen_str = "foo".freeze
+
+  old_obj_id = frozen_str.object_id
+  uplus_str = +frozen_str
+
+  if uplus_str.object_id == old_obj_id
+    raise "String unary plus on frozen should return a new duplicated string"
+  end
+
+  uplus_str.frozen?
+}
 
 # test invokebuiltin as used in struct assignment
 assert_equal '123', %q{
diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs
index 6ccdbc0cc5..c3a18c9c6f 100644
--- a/yjit/bindgen/src/main.rs
+++ b/yjit/bindgen/src/main.rs
@@ -62,6 +62,7 @@ fn main() { https://github.com/ruby/ruby/blob/trunk/yjit/bindgen/src/main.rs#L62
         // From include/ruby/internal/intern/string.h
         .allowlist_function("rb_utf8_str_new")
         .allowlist_function("rb_str_append")
+        .allowlist_function("rb_str_dup")
 
         // This struct is public to Ruby C extensions
         // From include/ruby/internal/core/rbasic.h
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index b15d87cac6..4203196e34 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -3599,6 +3599,43 @@ fn jit_rb_obj_equal( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3599
     true
 }
 
+/// If string is frozen, duplicate it to get a non-frozen string. Otherwise, return it.
+fn jit_rb_str_uplus(
+    _jit: &mut JITState,
+    ctx: &mut Context,
+    cb: &mut CodeBlock,
+    _ocb: &mut OutlinedCb,
+    _ci: *const rb_callinfo,
+    _cme: *const rb_callable_method_entry_t,
+    _block: Option<IseqPtr>,
+    _argc: i32,
+    _known_recv_class: *const VALUE,
+) -> bool
+{
+    let recv = ctx.stack_pop(1);
+
+    add_comment(cb, "Unary plus on string");
+    mov(cb, REG0, recv);
+    mov(cb, REG1, mem_opnd(64, REG0, RUBY_OFFSET_RBASIC_FLAGS));
+    test(cb, REG1, imm_opnd(RUBY_FL_FREEZE as i64));
+
+    let ret_label = cb.new_label("stack_ret".to_string());
+    // If the string isn't frozen, we just return it. It's already in REG0.
+    jz_label(cb, ret_label);
+
+    // Str is frozen - duplicate
+    mov(cb, C_ARG_REGS[0], REG0);
+    call_ptr(cb, REG0, rb_str_dup as *const u8);
+    // Return value is in REG0, drop through and return it.
+
+    cb.write_label(ret_label);
+    let stack_ret = ctx.stack_push(Type::String);
+    mov(cb, stack_ret, REG0);
+
+    cb.link_labels();
+    true
+}
+
 fn jit_rb_str_bytesize(
     _jit: &mut JITState,
     ctx: &mut Context,
@@ -6045,6 +6082,7 @@ impl CodegenGlobals { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L6082
             self.yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s);
             self.yjit_reg_method(rb_cString, "bytesize", jit_rb_str_bytesize);
             self.yjit_reg_method(rb_cString, "<<", jit_rb_str_concat);
+            self.yjit_reg_method(rb_cString, "+@", jit_rb_str_uplus);
 
             // Thread.current
             self.yjit_reg_method(
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 0bd18ea68c..758a8de2fd 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -223,6 +223,9 @@ extern "C" { https://github.com/ruby/ruby/blob/trunk/yjit/src/cruby_bindings.inc.rs#L223
         len: ::std::os::raw::c_long,
     ) -> VALUE;
 }
+extern "C" {
+    pub fn rb_str_dup(str_: VALUE) -> VALUE;
+}
 extern "C" {
     pub fn rb_str_append(dst: VALUE, src: VALUE) -> VALUE;
 }
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]