From b5146e375aca25a15ec46978711cde28e5f761d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Tue, 6 Aug 2019 12:56:18 +0900 Subject: [PATCH] leafify opt_plus Inspired by 346aa557b31fe96760e505d30da26eb7a846bac9 Closes: https://github.com/ruby/ruby/pull/2321 --- insns.def | 3 --- internal.h | 1 + string.c | 31 +++++++++++++++++++++++++++++++ vm_insnhelper.c | 3 ++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/insns.def b/insns.def index 40855d6f9d..6cfb3b121f 100644 --- a/insns.def +++ b/insns.def @@ -1080,9 +1080,6 @@ opt_plus (CALL_INFO ci, CALL_CACHE cc) (VALUE recv, VALUE obj) (VALUE val) -/* Array + anything can be handled inside of opt_plus, and that - * anything is converted into array using #to_ary. */ -// attr bool leaf = false; /* has rb_to_array_type() */ { val = vm_opt_plus(recv, obj); diff --git a/internal.h b/internal.h index d391597d54..bd7162e76c 100644 --- a/internal.h +++ b/internal.h @@ -2124,6 +2124,7 @@ char *rb_str_to_cstr(VALUE str); VALUE rb_str_eql(VALUE str1, VALUE str2); VALUE rb_obj_as_string_result(VALUE str, VALUE obj); const char *ruby_escaped_char(int c); +VALUE rb_str_opt_plus(VALUE, VALUE); /* expect tail call optimization */ static inline VALUE diff --git a/string.c b/string.c index 6cef5ab157..2890f46e24 100644 --- a/string.c +++ b/string.c @@ -1952,6 +1952,37 @@ rb_str_plus(VALUE str1, VALUE str2) return str3; } +/* A variant of rb_str_plus that does not raise but return Qundef instead. */ +MJIT_FUNC_EXPORTED VALUE +rb_str_opt_plus(VALUE str1, VALUE str2) +{ + assert(RBASIC_CLASS(str1) == rb_cString); + assert(RBASIC_CLASS(str2) == rb_cString); + long len1, len2; + MAYBE_UNUSED(char) *ptr1, *ptr2; + RSTRING_GETMEM(str1, ptr1, len1); + RSTRING_GETMEM(str2, ptr2, len2); + int enc1 = rb_enc_get_index(str1); + int enc2 = rb_enc_get_index(str2); + + if (enc1 < 0) { + return Qundef; + } + else if (enc2 < 0) { + return Qundef; + } + else if (enc1 != enc2) { + return Qundef; + } + else if (len1 > LONG_MAX - len2) { + return Qundef; + } + else { + return rb_str_plus(str1, str2); + } + +} + /* * call-seq: * str * integer -> new_str diff --git a/vm_insnhelper.c b/vm_insnhelper.c index e68ded7d15..d7aa5ce57c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -3848,9 +3848,10 @@ vm_opt_plus(VALUE recv, VALUE obj) else if (RBASIC_CLASS(recv) == rb_cString && RBASIC_CLASS(obj) == rb_cString && BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) { - return rb_str_plus(recv, obj); + return rb_str_opt_plus(recv, obj); } else if (RBASIC_CLASS(recv) == rb_cArray && + RBASIC_CLASS(obj) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) { return rb_ary_plus(recv, obj); }