Skip to content

Commit

Permalink
merge revision(s) c178926,a4b7ec12298c78392797e5ba7704076550e4f100: […
Browse files Browse the repository at this point in the history
…Backport #19444]

	YJIT: jit_prepare_routine_call() for String#+@ missing

	We saw SEGVs due to this when running with StackProf, which needs a
	correct PC for RUBY_INTERNAL_EVENT_NEWOBJ, the same event used for
	ObjectSpace allocation tracing.

	[Bug #19444]
	---
	 test/ruby/test_yjit.rb | 27 +++++++++++++++++++++++++++
	 yjit/src/codegen.rs    |  5 ++++-
	 2 files changed, 31 insertions(+), 1 deletion(-)

	YJIT: Fix false assumption that String#+@ => ::String

	Could return a subclass.

	[Bug #19444]
	---
	 test/ruby/test_yjit.rb | 17 +++++++++++++++++
	 yjit/src/codegen.rs    | 10 +++++++---
	 2 files changed, 24 insertions(+), 3 deletions(-)
  • Loading branch information
nurse committed Mar 7, 2023
1 parent f1cde05 commit 4d75035
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
44 changes: 44 additions & 0 deletions test/ruby/test_yjit.rb
Expand Up @@ -1077,6 +1077,50 @@ def foo(_, a, b, c)
RUBY
end

def test_tracing_str_uplus
assert_compiles(<<~RUBY, frozen_string_literal: true, result: :ok)
def str_uplus
_ = 1
_ = 2
ret = [+"frfr", __LINE__]
_ = 3
_ = 4
ret
end
str_uplus
require 'objspace'
ObjectSpace.trace_object_allocations_start
str, expected_line = str_uplus
alloc_line = ObjectSpace.allocation_sourceline(str)
if expected_line == alloc_line
:ok
else
[expected_line, alloc_line]
end
RUBY
end

def test_str_uplus_subclass
assert_compiles(<<~RUBY, frozen_string_literal: true, result: :subclass)
class S < String
def encoding
:subclass
end
end
def test(str)
(+str).encoding
end
test ""
test S.new
RUBY
end

private

def code_gc_helpers
Expand Down
2 changes: 1 addition & 1 deletion version.h
Expand Up @@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 35
#define RUBY_PATCHLEVEL 36

#include "ruby/version.h"
#include "ruby/internal/abi.h"
Expand Down
15 changes: 11 additions & 4 deletions yjit/src/codegen.rs
Expand Up @@ -4047,26 +4047,33 @@ fn jit_rb_int_equal(

/// If string is frozen, duplicate it to get a non-frozen string. Otherwise, return it.
fn jit_rb_str_uplus(
_jit: &mut JITState,
jit: &mut JITState,
ctx: &mut Context,
asm: &mut Assembler,
_ocb: &mut OutlinedCb,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<IseqPtr>,
_argc: i32,
argc: i32,
_known_recv_class: *const VALUE,
) -> bool
{
if argc != 0 {
return false;
}

// We allocate when we dup the string
jit_prepare_routine_call(jit, ctx, asm);

asm.comment("Unary plus on string");
let recv_opnd = asm.load(ctx.stack_pop(1));
let flags_opnd = asm.load(Opnd::mem(64, recv_opnd, RUBY_OFFSET_RBASIC_FLAGS));
asm.test(flags_opnd, Opnd::Imm(RUBY_FL_FREEZE as i64));

let ret_label = asm.new_label("stack_ret");

// We guard for the receiver being a ::String, so the return value is too
let stack_ret = ctx.stack_push(Type::CString);
// String#+@ can only exist on T_STRING
let stack_ret = ctx.stack_push(Type::TString);

// If the string isn't frozen, we just return it.
asm.mov(stack_ret, recv_opnd);
Expand Down

0 comments on commit 4d75035

Please sign in to comment.