merge revision(s) c178926fbe879045fa711444a1fd9e906af23e3b,a4b7ec12298c78392797e5ba7704076550e4f100: [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(-)
This commit is contained in:
NARUSE, Yui 2023-03-07 19:48:32 +09:00
Родитель f1cde05d99
Коммит 4d75035e17
3 изменённых файлов: 56 добавлений и 5 удалений

Просмотреть файл

@ -1077,6 +1077,50 @@ class TestYJIT < Test::Unit::TestCase
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

Просмотреть файл

@ -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"

Просмотреть файл

@ -4047,17 +4047,24 @@ 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));
@ -4065,8 +4072,8 @@ fn jit_rb_str_uplus(
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);