aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--insns.def3
-rw-r--r--internal.h1
-rw-r--r--string.c31
-rw-r--r--vm_insnhelper.c3
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);
}