Skip to content

Commit 6deeec5

Browse files
casperisfineetiennebarriebyroot
authored
Mark strings returned by Symbol#to_s as chilled (#12065)
* Use FL_USER0 for ELTS_SHARED This makes space in RString for two bits for chilled strings. * Mark strings returned by `Symbol#to_s` as chilled [Feature #20350] `STR_CHILLED` now spans on two user flags. If one bit is set it marks a chilled string literal, if it's the other it marks a `Symbol#to_s` chilled string. Since it's not possible, and doesn't make much sense to include debug info when `--debug-frozen-string-literal` is set, we can't include allocation source, but we can safely include the symbol name in the warning message, making it much easier to find the source of the issue. Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com> --------- Co-authored-by: Étienne Barrié <etienne.barrie@gmail.com> Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
1 parent 37a16c7 commit 6deeec5

File tree

15 files changed

+181
-85
lines changed

15 files changed

+181
-85
lines changed

array.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ VALUE rb_cArray_empty_frozen;
4242

4343
/* Flags of RArray
4444
*
45+
* 0: RARRAY_SHARED_FLAG (equal to ELTS_SHARED)
46+
* The array is shared. The buffer this array points to is owned by
47+
* another array (the shared root).
4548
* 1: RARRAY_EMBED_FLAG
4649
* The array is embedded (its contents follow the header, rather than
4750
* being on a separately allocated buffer).
48-
* 2: RARRAY_SHARED_FLAG (equal to ELTS_SHARED)
49-
* The array is shared. The buffer this array points to is owned by
50-
* another array (the shared root).
5151
* 3-9: RARRAY_EMBED_LEN
5252
* The length of the array when RARRAY_EMBED_FLAG is set.
5353
* 12: RARRAY_SHARED_ROOT_FLAG

compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8950,7 +8950,7 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
89508950

89518951
if (!SYMBOL_P(symbol)) goto non_symbol_arg;
89528952

8953-
string = rb_sym_to_s(symbol);
8953+
string = rb_sym2str(symbol);
89548954
if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
89558955
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
89568956
}

error.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4016,7 +4016,7 @@ rb_error_frozen_object(VALUE frozen_obj)
40164016
}
40174017

40184018
void
4019-
rb_warn_unchilled(VALUE obj)
4019+
rb_warn_unchilled_literal(VALUE obj)
40204020
{
40214021
rb_warning_category_t category = RB_WARN_CATEGORY_DEPRECATED;
40224022
if (!NIL_P(ruby_verbose) && rb_warning_category_enabled_p(category)) {
@@ -4047,6 +4047,15 @@ rb_warn_unchilled(VALUE obj)
40474047
}
40484048
}
40494049

4050+
void
4051+
rb_warn_unchilled_symbol_to_s(VALUE obj)
4052+
{
4053+
rb_category_warn(
4054+
RB_WARN_CATEGORY_DEPRECATED,
4055+
"warning: string returned by :%s.to_s will be frozen in the future", RSTRING_PTR(obj)
4056+
);
4057+
}
4058+
40504059
#undef rb_check_frozen
40514060
void
40524061
rb_check_frozen(VALUE obj)

include/ruby/internal/abi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* In released versions of Ruby, this number is not defined since teeny
2525
* versions of Ruby should guarantee ABI compatibility.
2626
*/
27-
#define RUBY_ABI_VERSION 0
27+
#define RUBY_ABI_VERSION 1
2828

2929
/* Windows does not support weak symbols so ruby_abi_version will not exist
3030
* in the shared library. */

include/ruby/internal/core/rarray.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
* here is at least incomplete.
8181
*/
8282
enum ruby_rarray_flags {
83+
/* RUBY_FL_USER0 is for ELTS_SHARED */
84+
8385
/**
8486
* This flag has something to do with memory footprint. If the array is
8587
* "small" enough, ruby tries to be creative to abuse padding bits of
@@ -99,8 +101,6 @@ enum ruby_rarray_flags {
99101
*/
100102
RARRAY_EMBED_FLAG = RUBY_FL_USER1,
101103

102-
/* RUBY_FL_USER2 is for ELTS_SHARED */
103-
104104
/**
105105
* When an array employs embedded strategy (see ::RARRAY_EMBED_FLAG), these
106106
* bits are used to store the number of elements actually filled into

include/ruby/internal/fl_type.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ ruby_fl_type {
370370
* 3rd parties. It must be an implementation detail that they should never
371371
* know. Might better be hidden.
372372
*/
373-
RUBY_ELTS_SHARED = RUBY_FL_USER2,
373+
RUBY_ELTS_SHARED = RUBY_FL_USER0,
374374

375375
/**
376376
* This flag has something to do with an object's class. There are kind of

include/ruby/internal/intern/error.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ rb_check_frozen_inline(VALUE obj)
258258

259259
/* ref: internal CHILLED_STRING_P()
260260
This is an implementation detail subject to change. */
261-
if (RB_UNLIKELY(RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, RUBY_FL_USER3))) {
261+
if (RB_UNLIKELY(RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, RUBY_FL_USER2 | RUBY_FL_USER3))) { // STR_CHILLED
262262
rb_str_modify(obj);
263263
}
264264
}

internal/string.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
#include "ruby/encoding.h" /* for rb_encoding */
1616
#include "ruby/ruby.h" /* for VALUE */
1717

18-
#define STR_NOEMBED FL_USER1
19-
#define STR_SHARED FL_USER2 /* = ELTS_SHARED */
20-
#define STR_CHILLED FL_USER3
18+
#define STR_SHARED FL_USER0 /* = ELTS_SHARED */
19+
#define STR_NOEMBED FL_USER1
20+
#define STR_CHILLED (FL_USER2 | FL_USER3)
21+
#define STR_CHILLED_LITERAL FL_USER2
22+
#define STR_CHILLED_SYMBOL_TO_S FL_USER3
2123

2224
enum ruby_rstring_private_flags {
2325
RSTRING_CHILLED = STR_CHILLED,
@@ -60,7 +62,8 @@ VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
6062
VALUE rb_str_with_debug_created_info(VALUE, VALUE, int);
6163

6264
/* error.c */
63-
void rb_warn_unchilled(VALUE str);
65+
void rb_warn_unchilled_literal(VALUE str);
66+
void rb_warn_unchilled_symbol_to_s(VALUE str);
6467

6568
static inline bool STR_EMBED_P(VALUE str);
6669
static inline bool STR_SHARED_P(VALUE str);
@@ -127,14 +130,18 @@ CHILLED_STRING_P(VALUE obj)
127130
static inline void
128131
CHILLED_STRING_MUTATED(VALUE str)
129132
{
133+
VALUE chilled_reason = RB_FL_TEST_RAW(str, STR_CHILLED);
130134
FL_UNSET_RAW(str, STR_CHILLED);
131-
rb_warn_unchilled(str);
132-
}
133-
134-
static inline void
135-
STR_CHILL_RAW(VALUE str)
136-
{
137-
FL_SET_RAW(str, STR_CHILLED);
135+
switch (chilled_reason) {
136+
case STR_CHILLED_SYMBOL_TO_S:
137+
rb_warn_unchilled_symbol_to_s(str);
138+
break;
139+
case STR_CHILLED_LITERAL:
140+
rb_warn_unchilled_literal(str);
141+
break;
142+
default:
143+
rb_bug("RString was chilled for multiple reasons");
144+
}
138145
}
139146

140147
static inline bool

lib/ruby_vm/rjit/c_type.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ module Immediate
3131
def self.new(fiddle_type)
3232
name = Fiddle.constants.find do |const|
3333
const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
34-
end&.to_s
35-
name.delete_prefix!('TYPE_')
34+
end&.name
35+
name = name.delete_prefix('TYPE_')
3636
if fiddle_type.negative?
3737
name.prepend('U')
3838
end

object.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,10 +500,12 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
500500
case Qnil:
501501
rb_funcall(clone, id_init_clone, 1, obj);
502502
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
503-
if (CHILLED_STRING_P(obj)) {
504-
STR_CHILL_RAW(clone);
503+
504+
if (RB_TYPE_P(obj, T_STRING)) {
505+
FL_SET_RAW(clone, FL_TEST_RAW(obj, STR_CHILLED));
505506
}
506-
else if (RB_OBJ_FROZEN(obj)) {
507+
508+
if (RB_OBJ_FROZEN(obj)) {
507509
rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
508510
if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
509511
rb_evict_ivars_to_hash(clone);

0 commit comments

Comments
 (0)