summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS.md6
-rw-r--r--bootstraptest/test_ractor.rb11
-rw-r--r--bootstraptest/test_yjit.rb31
-rw-r--r--class.c5
-rw-r--r--compile.c17
-rw-r--r--error.c6
-rw-r--r--ext/objspace/objspace_dump.c2
-rw-r--r--gems/bundled_gems12
-rw-r--r--include/ruby/internal/fl_type.h3
-rw-r--r--include/ruby/internal/intern/error.h1
-rw-r--r--insns.def12
-rw-r--r--internal/string.h23
-rw-r--r--iseq.c31
-rw-r--r--iseq.h6
-rw-r--r--lib/ruby_vm/rjit/insn_compiler.rb22
-rw-r--r--mini_builtin.c20
-rw-r--r--object.c5
-rw-r--r--prism_compile.c82
-rw-r--r--prism_compile.h1
-rw-r--r--ractor.c16
-rw-r--r--ruby.c2
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_raw.rb3
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb35
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb19
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb69
-rw-r--r--spec/ruby/language/string_spec.rb4
-rw-r--r--spec/ruby/shared/kernel/object_id.rb14
-rw-r--r--string.c18
-rw-r--r--test/ruby/test_compile_prism.rb65
-rw-r--r--test/ruby/test_string.rb33
-rw-r--r--vm_eval.c2
-rw-r--r--vm_opts.h2
-rw-r--r--yjit/src/codegen.rs24
-rw-r--r--yjit/src/cruby_bindings.inc.rs386
36 files changed, 714 insertions, 282 deletions
diff --git a/NEWS.md b/NEWS.md
index 8b6d4e8817..a4380a83a1 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -7,6 +7,12 @@ Note that each entry is kept to a minimum, see links for details.
## Language changes
+* String literals in files without a `frozen_string_literal` comment now behave
+ as if they were frozen. If they are mutated a deprecation warning is emited.
+ These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`.
+ To disable this change you can run Ruby with the `--disable-frozen-string-literal` command line
+ argument. [Feature #20205]
+
* `it` is added to reference a block parameter. [[Feature #18980]]
* Keyword splatting `nil` when calling methods is now supported.
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 3298ff1443..4868810308 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -1792,3 +1792,14 @@ assert_equal 'ok', %q{
}
end # if !ENV['GITHUB_WORKFLOW']
+
+# Chilled strings are not shareable
+assert_equal 'false', %q{
+ Ractor.shareable?("chilled")
+}
+
+# Chilled strings can be made shareable
+assert_equal 'true', %q{
+ shareable = Ractor.make_shareable("chilled")
+ shareable == "chilled" && Ractor.shareable?(shareable)
+}
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index ddd1e321a0..3eef86e0a9 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -4679,6 +4679,37 @@ assert_equal '[0, {1=>1}]', %q{
test(KwInit, [Hash.ruby2_keywords_hash({1 => 1})])
}
+# Chilled string setivar trigger warning
+assert_equal 'literal string will be frozen in the future', %q{
+ Warning[:deprecated] = true
+ $VERBOSE = true
+ $warning = "no-warning"
+ module ::Warning
+ def self.warn(message)
+ $warning = message.split("warning: ").last.strip
+ end
+ end
+
+ class String
+ def setivar!
+ @ivar = 42
+ end
+ end
+
+ def setivar!(str)
+ str.setivar!
+ end
+
+ 10.times { setivar!("mutable".dup) }
+ 10.times do
+ setivar!("frozen".freeze)
+ rescue FrozenError
+ end
+
+ setivar!("chilled") # Emit warning
+ $warning
+}
+
# arity=-2 cfuncs
assert_equal '["", "1/2", [0, [:ok, 1]]]', %q{
def test_cases(file, chain)
diff --git a/class.c b/class.c
index 98e7dfcc08..cee2065ae4 100644
--- a/class.c
+++ b/class.c
@@ -2244,7 +2244,10 @@ singleton_class_of(VALUE obj)
return klass;
case T_STRING:
- if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
+ if (CHILLED_STRING_P(obj)) {
+ CHILLED_STRING_MUTATED(obj);
+ }
+ else if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
rb_raise(rb_eTypeError, "can't define singleton");
}
}
diff --git a/compile.c b/compile.c
index 099341bcf6..5516f64f54 100644
--- a/compile.c
+++ b/compile.c
@@ -4723,7 +4723,7 @@ frozen_string_literal_p(const rb_iseq_t *iseq)
return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
}
-static inline int
+static inline bool
static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
{
switch (nd_type(node)) {
@@ -10365,12 +10365,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
debugp_param("nd_lit", get_string_value(node));
if (!popped) {
VALUE lit = get_string_value(node);
- if (!frozen_string_literal_p(iseq)) {
+ switch (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
+ case ISEQ_FROZEN_STRING_LITERAL_UNSET:
+ lit = rb_fstring(lit);
+ ADD_INSN1(ret, node, putchilledstring, lit);
+ RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
lit = rb_fstring(lit);
ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
- }
- else {
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
lit = rb_str_dup(lit);
@@ -10382,6 +10388,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ break;
+ default:
+ rb_bug("invalid frozen_string_literal");
}
}
break;
diff --git a/error.c b/error.c
index b9a99dc0bc..dc032df651 100644
--- a/error.c
+++ b/error.c
@@ -3860,6 +3860,12 @@ void
rb_error_frozen_object(VALUE frozen_obj)
{
rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
+
+ if (CHILLED_STRING_P(frozen_obj)) {
+ CHILLED_STRING_MUTATED(frozen_obj);
+ return;
+ }
+
VALUE debug_info;
const ID created_info = id_debug_created_info;
VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index d05fe66037..bb479b91c5 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -476,6 +476,8 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, ", \"embedded\":true");
if (FL_TEST(obj, RSTRING_FSTR))
dump_append(dc, ", \"fstring\":true");
+ if (CHILLED_STRING_P(obj))
+ dump_append(dc, ", \"chilled\":true");
if (STR_SHARED_P(obj))
dump_append(dc, ", \"shared\":true");
else
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 5b56c88a49..f64651592d 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -5,8 +5,12 @@
# - repository-url: URL from where clone for test
# - revision: revision in repository-url to test
# if `revision` is not given, "v"+`version` or `version` will be used.
-minitest 5.22.3 https://github.com/minitest/minitest
-power_assert 2.0.3 https://github.com/ruby/power_assert
+
+# Waiting for https://github.com/minitest/minitest/pull/991
+minitest 5.22.3 https://github.com/Shopify/minitest b5f5202575894796e00109a8f8a5041b778991ee
+
+# Waiting for https://github.com/ruby/power_assert/pull/48
+power_assert 2.0.3 https://github.com/ruby/power_assert 78dd2ab3ccd93796d83c0b35b978c39bfabb938c
rake 13.1.0 https://github.com/ruby/rake
test-unit 3.6.2 https://github.com/test-unit/test-unit
rexml 3.2.6 https://github.com/ruby/rexml
@@ -17,8 +21,8 @@ net-pop 0.1.2 https://github.com/ruby/net-pop
net-smtp 0.4.0.1 https://github.com/ruby/net-smtp
matrix 0.4.2 https://github.com/ruby/matrix
prime 0.1.2 https://github.com/ruby/prime
-rbs 3.4.4 https://github.com/ruby/rbs 61b412bc7ba00519e7d6d08450bd384990d94ea2
-typeprof 0.21.11 https://github.com/ruby/typeprof
+rbs 3.4.4 https://github.com/ruby/rbs ba7872795d5de04adb8ff500c0e6afdc81a041dd
+typeprof 0.21.11 https://github.com/ruby/typeprof b19a6416da3a05d57fadd6ffdadb382b6d236ca5
debug 1.9.1 https://github.com/ruby/debug 2d602636d99114d55a32fedd652c9c704446a749
racc 1.7.3 https://github.com/ruby/racc
mutex_m 0.2.0 https://github.com/ruby/mutex_m
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index 16e0dfe139..eb212db7dc 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -916,6 +916,9 @@ static inline void
RB_OBJ_FREEZE_RAW(VALUE obj)
{
RB_FL_SET_RAW(obj, RUBY_FL_FREEZE);
+ if (TYPE(obj) == T_STRING) {
+ RB_FL_UNSET_RAW(obj, FL_USER3); // STR_CHILLED
+ }
}
RUBY_SYMBOL_EXPORT_BEGIN
diff --git a/include/ruby/internal/intern/error.h b/include/ruby/internal/intern/error.h
index bf8daadd3e..11e147a121 100644
--- a/include/ruby/internal/intern/error.h
+++ b/include/ruby/internal/intern/error.h
@@ -190,7 +190,6 @@ RBIMPL_ATTR_NONNULL(())
*/
void rb_error_frozen(const char *what);
-RBIMPL_ATTR_NORETURN()
/**
* Identical to rb_error_frozen(), except it takes arbitrary Ruby object
* instead of C's string.
diff --git a/insns.def b/insns.def
index 966f51ecfb..9c649904b8 100644
--- a/insns.def
+++ b/insns.def
@@ -375,7 +375,17 @@ putstring
()
(VALUE val)
{
- val = rb_ec_str_resurrect(ec, str);
+ val = rb_ec_str_resurrect(ec, str, false);
+}
+
+/* put chilled string val. string will be copied but frozen in the future. */
+DEFINE_INSN
+putchilledstring
+(VALUE str)
+()
+(VALUE val)
+{
+ val = rb_ec_str_resurrect(ec, str, true);
}
/* put concatenate strings */
diff --git a/internal/string.h b/internal/string.h
index cde81a1a25..fb37f73114 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -17,6 +17,7 @@
#define STR_NOEMBED FL_USER1
#define STR_SHARED FL_USER2 /* = ELTS_SHARED */
+#define STR_CHILLED FL_USER3
#ifdef rb_fstring_cstr
# undef rb_fstring_cstr
@@ -77,7 +78,7 @@ VALUE rb_id_quote_unprintable(ID);
VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc);
struct rb_execution_context_struct;
-VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str);
+VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled);
#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str))
#define rb_fstring_literal(str) rb_fstring_lit(str)
@@ -109,6 +110,26 @@ STR_SHARED_P(VALUE str)
}
static inline bool
+CHILLED_STRING_P(VALUE obj)
+{
+ return RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, STR_CHILLED);
+}
+
+static inline void
+CHILLED_STRING_MUTATED(VALUE str)
+{
+ rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "literal string will be frozen in the future");
+ FL_UNSET_RAW(str, STR_CHILLED | FL_FREEZE);
+}
+
+static inline void
+STR_CHILL_RAW(VALUE str)
+{
+ // Chilled strings are always also frozen
+ FL_SET_RAW(str, STR_CHILLED | RUBY_FL_FREEZE);
+}
+
+static inline bool
is_ascii_string(VALUE str)
{
return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT;
diff --git a/iseq.c b/iseq.c
index 1d903f9591..057e047ef9 100644
--- a/iseq.c
+++ b/iseq.c
@@ -720,18 +720,20 @@ finish_iseq_build(rb_iseq_t *iseq)
}
static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
- OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
- OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
- OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
- OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
- OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
- OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
- OPT_FROZEN_STRING_LITERAL,
- OPT_DEBUG_FROZEN_STRING_LITERAL,
- TRUE, /* coverage_enabled */
+ .inline_const_cache = OPT_INLINE_CONST_CACHE,
+ .peephole_optimization = OPT_PEEPHOLE_OPTIMIZATION,
+ .tailcall_optimization = OPT_TAILCALL_OPTIMIZATION,
+ .specialized_instruction = OPT_SPECIALISED_INSTRUCTION,
+ .operands_unification = OPT_OPERANDS_UNIFICATION,
+ .instructions_unification = OPT_INSTRUCTIONS_UNIFICATION,
+ .frozen_string_literal = OPT_FROZEN_STRING_LITERAL,
+ .debug_frozen_string_literal = OPT_DEBUG_FROZEN_STRING_LITERAL,
+ .coverage_enabled = TRUE,
};
-static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
+static const rb_compile_option_t COMPILE_OPTION_FALSE = {
+ .frozen_string_literal = -1, // unspecified
+};
int
rb_iseq_opt_frozen_string_literal(void)
@@ -770,9 +772,11 @@ set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *as
{
#define SET_COMPILE_OPTION(o, a, mem) \
((a)->mem < 0 ? 0 : ((o)->mem = (a)->mem > 0))
- SET_COMPILE_OPTION(option, ast, frozen_string_literal);
SET_COMPILE_OPTION(option, ast, coverage_enabled);
#undef SET_COMPILE_OPTION
+ if (ast->frozen_string_literal >= 0) {
+ option->frozen_string_literal = ast->frozen_string_literal;
+ }
return option;
}
@@ -814,13 +818,14 @@ make_compile_option_value(rb_compile_option_t *option)
SET_COMPILE_OPTION(option, opt, specialized_instruction);
SET_COMPILE_OPTION(option, opt, operands_unification);
SET_COMPILE_OPTION(option, opt, instructions_unification);
- SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
SET_COMPILE_OPTION(option, opt, coverage_enabled);
SET_COMPILE_OPTION_NUM(option, opt, debug_level);
}
#undef SET_COMPILE_OPTION
#undef SET_COMPILE_OPTION_NUM
+ VALUE frozen_string_literal = option->frozen_string_literal == -1 ? Qnil : RBOOL(option->frozen_string_literal);
+ rb_hash_aset(opt, ID2SYM(rb_intern("frozen_string_literal")), frozen_string_literal);
return opt;
}
@@ -1248,7 +1253,7 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
pm_parse_result_t result = { 0 };
pm_options_line_set(&result.options, NUM2INT(line));
- pm_options_frozen_string_literal_set(&result.options, option.frozen_string_literal);
+ pm_options_frozen_string_literal_init(&result, option.frozen_string_literal);
VALUE error;
if (RB_TYPE_P(src, T_FILE)) {
diff --git a/iseq.h b/iseq.h
index 78e0d900db..a0b59c441f 100644
--- a/iseq.h
+++ b/iseq.h
@@ -47,6 +47,10 @@ extern const ID rb_iseq_shared_exc_local_tbl[];
#define ISEQ_FLIP_CNT(iseq) ISEQ_BODY(iseq)->variable.flip_count
+#define ISEQ_FROZEN_STRING_LITERAL_ENABLED 1
+#define ISEQ_FROZEN_STRING_LITERAL_DISABLED 0
+#define ISEQ_FROZEN_STRING_LITERAL_UNSET -1
+
static inline rb_snum_t
ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq)
{
@@ -227,7 +231,7 @@ struct rb_compile_option_struct {
unsigned int specialized_instruction: 1;
unsigned int operands_unification: 1;
unsigned int instructions_unification: 1;
- unsigned int frozen_string_literal: 1;
+ signed int frozen_string_literal: 2; /* -1: not specified, 0: false, 1: true */
unsigned int debug_frozen_string_literal: 1;
unsigned int coverage_enabled: 1;
int debug_level;
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb
index 1bcee7cb70..2346c92bd1 100644
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ b/lib/ruby_vm/rjit/insn_compiler.rb
@@ -57,6 +57,7 @@ module RubyVM::RJIT
when :putobject then putobject(jit, ctx, asm)
when :putspecialobject then putspecialobject(jit, ctx, asm)
when :putstring then putstring(jit, ctx, asm)
+ when :putchilledstring then putchilledstring(jit, ctx, asm)
when :concatstrings then concatstrings(jit, ctx, asm)
when :anytostring then anytostring(jit, ctx, asm)
when :toregexp then toregexp(jit, ctx, asm)
@@ -776,6 +777,27 @@ module RubyVM::RJIT
asm.mov(C_ARGS[0], EC)
asm.mov(C_ARGS[1], to_value(put_val))
+ asm.mov(C_ARGS[2], 0)
+ asm.call(C.rb_ec_str_resurrect)
+
+ stack_top = ctx.stack_push(Type::TString)
+ asm.mov(stack_top, C_RET)
+
+ KeepCompiling
+ end
+
+ # @param jit [RubyVM::RJIT::JITState]
+ # @param ctx [RubyVM::RJIT::Context]
+ # @param asm [RubyVM::RJIT::Assembler]
+ def putchilledstring(jit, ctx, asm)
+ put_val = jit.operand(0, ruby: true)
+
+ # Save the PC and SP because the callee will allocate
+ jit_prepare_routine_call(jit, ctx, asm)
+
+ asm.mov(C_ARGS[0], EC)
+ asm.mov(C_ARGS[1], to_value(put_val))
+ asm.mov(C_ARGS[2], 1)
asm.call(C.rb_ec_str_resurrect)
stack_top = ctx.stack_push(Type::TString)
diff --git a/mini_builtin.c b/mini_builtin.c
index a93a5ebddb..dce822a86c 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -28,16 +28,16 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
}
vm->builtin_function_table = table;
static const rb_compile_option_t optimization = {
- TRUE, /* unsigned int inline_const_cache; */
- TRUE, /* unsigned int peephole_optimization; */
- FALSE,/* unsigned int tailcall_optimization; */
- TRUE, /* unsigned int specialized_instruction; */
- TRUE, /* unsigned int operands_unification; */
- TRUE, /* unsigned int instructions_unification; */
- TRUE, /* unsigned int frozen_string_literal; */
- FALSE, /* unsigned int debug_frozen_string_literal; */
- FALSE, /* unsigned int coverage_enabled; */
- 0, /* int debug_level; */
+ .inline_const_cache = TRUE,
+ .peephole_optimization = TRUE,
+ .tailcall_optimization = FALSE,
+ .specialized_instruction = TRUE,
+ .operands_unification = TRUE,
+ .instructions_unification = TRUE,
+ .frozen_string_literal = TRUE,
+ .debug_frozen_string_literal = FALSE,
+ .coverage_enabled = FALSE,
+ .debug_level = 0,
};
const rb_iseq_t *iseq = rb_iseq_new_with_opt(&ast->body, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization);
GET_VM()->builtin_function_table = NULL;
diff --git a/object.c b/object.c
index 26c03075a0..572f577312 100644
--- a/object.c
+++ b/object.c
@@ -502,7 +502,10 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
case Qnil:
rb_funcall(clone, id_init_clone, 1, obj);
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
- if (RB_OBJ_FROZEN(obj)) {
+ if (CHILLED_STRING_P(obj)) {
+ STR_CHILL_RAW(clone);
+ }
+ else if (RB_OBJ_FROZEN(obj)) {
rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
rb_evict_ivars_to_hash(clone);
diff --git a/prism_compile.c b/prism_compile.c
index 0508ced5ff..e919a44c08 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -787,6 +787,44 @@ pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_
if (parts_size > 0) {
VALUE current_string = Qnil;
+ bool literal = true;
+ for (size_t index = 0; index < parts_size; index++) {
+ const pm_node_t *part = parts->nodes[index];
+
+ if (!PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
+ literal = false;
+ break;
+ }
+ }
+
+ if (literal) {
+ for (size_t index = 0; index < parts_size; index++) {
+ const pm_node_t *part = parts->nodes[index];
+ const pm_string_node_t *string_node = (const pm_string_node_t *)part;
+ VALUE string_value = parse_string_encoded(scope_node, (pm_node_t *)string_node, &string_node->unescaped);
+
+ if (RTEST(current_string)) {
+ current_string = rb_str_concat(current_string, string_value);
+ }
+ else {
+ current_string = string_value;
+ }
+ }
+
+ const pm_node_t *part = parts->nodes[0];
+ current_string = rb_fstring(current_string);
+ if (PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
+ ADD_INSN1(ret, &dummy_line_node, putobject, current_string);
+ }
+ else if (PM_NODE_FLAG_P(part, PM_STRING_FLAGS_MUTABLE)) {
+ ADD_INSN1(ret, &dummy_line_node, putstring, current_string);
+ }
+ else {
+ ADD_INSN1(ret, &dummy_line_node, putchilledstring, current_string);
+ }
+ return 1;
+ }
+
for (size_t index = 0; index < parts_size; index++) {
const pm_node_t *part = parts->nodes[index];
@@ -820,12 +858,7 @@ pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_
current_string = rb_enc_str_new(NULL, 0, scope_node->encoding);
}
- if (frozen_string_literal_p(iseq)) {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_freeze(current_string));
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putstring, rb_str_freeze(current_string));
- }
+ ADD_INSN1(ret, &dummy_line_node, putobject, rb_fstring(current_string));
current_string = Qnil;
number_of_items_pushed++;
@@ -841,14 +874,7 @@ pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_
if (RTEST(current_string)) {
current_string = rb_fstring(current_string);
-
- if (frozen_string_literal_p(iseq)) {
- ADD_INSN1(ret, &dummy_line_node, putobject, current_string);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putstring, current_string);
- }
-
+ ADD_INSN1(ret, &dummy_line_node, putobject, current_string);
current_string = Qnil;
number_of_items_pushed++;
}
@@ -7925,9 +7951,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) {
PUSH_INSN1(ret, location, putobject, string);
}
- else {
+ else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, string);
}
+ else {
+ PUSH_INSN1(ret, location, putchilledstring, string);
+ }
}
return;
}
@@ -7979,9 +8008,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_FROZEN)) {
PUSH_INSN1(ret, location, putobject, value);
}
- else {
+ else if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, value);
}
+ else {
+ PUSH_INSN1(ret, location, putchilledstring, value);
+ }
}
return;
}
@@ -8354,6 +8386,24 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
return lines;
}
+void
+pm_options_frozen_string_literal_init(pm_parse_result_t *result, int frozen_string_literal)
+{
+ switch (frozen_string_literal) {
+ case ISEQ_FROZEN_STRING_LITERAL_UNSET:
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
+ pm_options_frozen_string_literal_set(&result->options, false);
+ break;
+ case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
+ pm_options_frozen_string_literal_set(&result->options, true);
+ break;
+ default:
+ rb_bug("pm_options_frozen_string_literal_init: invalid frozen_string_literal=%d", frozen_string_literal);
+ break;
+ }
+}
+
/**
* Attempt to load the file into memory. Return a Ruby error if the file cannot
* be read.
diff --git a/prism_compile.h b/prism_compile.h
index 427fa54b51..0c1510d67f 100644
--- a/prism_compile.h
+++ b/prism_compile.h
@@ -47,6 +47,7 @@ typedef struct {
bool parsed;
} pm_parse_result_t;
+void pm_options_frozen_string_literal_init(pm_parse_result_t *result, int frozen_string_literal);
VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath);
VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath);
VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath);
diff --git a/ractor.c b/ractor.c
index 4eee3cc731..7b9c088ceb 100644
--- a/ractor.c
+++ b/ractor.c
@@ -2985,7 +2985,10 @@ rb_obj_traverse(VALUE obj,
static int
frozen_shareable_p(VALUE obj, bool *made_shareable)
{
- if (!RB_TYPE_P(obj, T_DATA)) {
+ if (CHILLED_STRING_P(obj)) {
+ return false;
+ }
+ else if (!RB_TYPE_P(obj, T_DATA)) {
return true;
}
else if (RTYPEDDATA_P(obj)) {
@@ -3014,6 +3017,17 @@ make_shareable_check_shareable(VALUE obj)
if (rb_ractor_shareable_p(obj)) {
return traverse_skip;
}
+ else if (CHILLED_STRING_P(obj)) {
+ rb_funcall(obj, idFreeze, 0);
+
+ if (UNLIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
+ rb_raise(rb_eRactorError, "#freeze does not freeze object correctly");
+ }
+
+ if (RB_OBJ_SHAREABLE_P(obj)) {
+ return traverse_skip;
+ }
+ }
else if (!frozen_shareable_p(obj, &made_shareable)) {
if (made_shareable) {
return traverse_skip;
diff --git a/ruby.c b/ruby.c
index 3b9cce01f1..5c1d44ec6d 100644
--- a/ruby.c
+++ b/ruby.c
@@ -2116,7 +2116,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
pm_options_t *options = &result->options;
pm_options_line_set(options, 1);
- pm_options_frozen_string_literal_set(&result->options, rb_iseq_opt_frozen_string_literal());
+ pm_options_frozen_string_literal_init(result, rb_iseq_opt_frozen_string_literal());
if (opt->ext.enc.name != 0) {
pm_options_encoding_set(options, StringValueCStr(opt->ext.enc.name));
diff --git a/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb b/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
new file mode 100644
index 0000000000..fb84b546c0
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb b/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
new file mode 100644
index 0000000000..381a742001
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: false
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_raw.rb b/spec/ruby/command_line/fixtures/string_literal_raw.rb
new file mode 100644
index 0000000000..56b1841296
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_raw.rb
@@ -0,0 +1,3 @@
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 647b69daed..24b979b68b 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -19,6 +19,41 @@ describe "The --enable-frozen-string-literal flag causes string literals to" do
end
end
+describe "The --disable-frozen-string-literal flag causes string literals to" do
+
+ it "produce a different object each time" do
+ ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb"), options: "--disable-frozen-string-literal").chomp.should == "false"
+ end
+
+end
+
+describe "With neither --enable-frozen-string-literal nor --disable-frozen-string-literal flag set" do
+
+ it "produce a different object each time" do
+ ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"
+ end
+
+ ruby_version_is "3.4" do
+ it "if file has no frozen_string_literal comment produce different frozen strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:true interned:false"
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "if file has no frozen_string_literal comment produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
+ end
+ end
+
+ it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_frozen_comment.rb")).chomp.should == "frozen:true interned:true"
+ end
+
+ it "if file has frozen_string_literal:false comment produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_mutable_comment.rb")).chomp.should == "frozen:false interned:false"
+ end
+end
+
describe "The --debug flag produces" do
it "debugging info on attempted frozen string modification" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--debug', args: "2>&1")
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 15c9d511fc..5d82f57e44 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -350,9 +350,11 @@ CODE
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
+
code = <<CODE.b
# encoding: UTF-8
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring = "frozen"
end
@@ -362,7 +364,7 @@ CODE
EvalSpecs.constants(false).should include(:"Vπstring")
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
- EvalSpecs::Vπstring.frozen?.should be_true
+ EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@@ -381,8 +383,9 @@ CODE
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
code = <<CODE.b
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
# encoding: UTF-8
class EvalSpecs
Vπfrozen_first = "frozen"
@@ -396,24 +399,24 @@ CODE
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
- value.frozen?.should be_true
+ value.frozen?.should == !frozen_string_default
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
- default_frozen_string_literal = "test".frozen?
+ frozen_string_default = "test".frozen?
code = <<CODE
some_token_before_magic_comment = :anything
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring_not_frozen = "not frozen"
end
CODE
-> { eval(code) }.should complain(/warning: [`']frozen_string_literal' is ignored after any tokens/, verbose: true)
- EvalSpecs::Vπstring_not_frozen.frozen?.should == default_frozen_string_literal
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
-> { eval(code) }.should_not complain(verbose: false)
- EvalSpecs::Vπstring_not_frozen.frozen?.should == default_frozen_string_literal
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
end
end
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
new file mode 100644
index 0000000000..8de4fc421b
--- /dev/null
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -0,0 +1,69 @@
+require_relative '../../spec_helper'
+
+describe "chilled String" do
+ guard -> { ruby_version_is "3.4" and !"test".equal?("test") } do
+ describe "#frozen?" do
+ it "returns true" do
+ "chilled".frozen?.should == true
+ end
+ end
+
+ describe "#-@" do
+ it "returns a different instance" do
+ input = "chilled"
+ interned = (-input)
+ interned.frozen?.should == true
+ interned.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#+@" do
+ it "returns a different instance" do
+ input = "chilled"
+ duped = (+input)
+ duped.frozen?.should == false
+ duped.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#clone" do
+ it "preserves chilled status" do
+ input = "chilled".clone
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+ end
+
+ describe "mutation" do
+ it "emits a warning" do
+ input = "chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+
+ it "emits a warning on singleton_class creaation" do
+ -> {
+ "chilled".singleton_class
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "emits a warning on instance variable assignment" do
+ -> {
+ "chilled".instance_variable_set(:@ivar, 42)
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "raises FrozenError after the string was explictly frozen" do
+ input = "chilled"
+ input.freeze
+ -> {
+ input << "mutated"
+ }.should raise_error(FrozenError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index f2764eada0..1a1cd35850 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -232,8 +232,8 @@ describe "Ruby String literals" do
end
it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
- frozen_literals_by_default = eval("'test'").frozen?
- ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == (!frozen_literals_by_default).to_s
+ frozen_string_literal = "test".frozen? && "test".equal?("test")
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == (!frozen_string_literal).to_s
end
it "produce different objects for literals with the same content in different files if they have different encodings" do
diff --git a/spec/ruby/shared/kernel/object_id.rb b/spec/ruby/shared/kernel/object_id.rb
index 3e032102f1..099df8ff94 100644
--- a/spec/ruby/shared/kernel/object_id.rb
+++ b/spec/ruby/shared/kernel/object_id.rb
@@ -52,7 +52,7 @@ describe :object_id, shared: true do
o1.send(@method).should_not == o2.send(@method)
end
- guard -> { "test".frozen? } do # --enable-frozen-string-literal in $RUBYOPT
+ guard -> { "test".frozen? && "test".equal?("test") } do # --enable-frozen-string-literal in $RUBYOPT
it "returns the same value for two identical String literals" do
o1 = "hello"
o2 = "hello"
@@ -60,7 +60,17 @@ describe :object_id, shared: true do
end
end
- guard_not -> { "test".frozen? } do
+ guard -> { "test".frozen? && !"test".equal?("test") } do # chilled string literals
+ it "returns a different frozen value for two String literals" do
+ o1 = "hello"
+ o2 = "hello"
+ o1.send(@method).should_not == o2.send(@method)
+ o1.frozen?.should == true
+ o2.frozen?.should == true
+ end
+ end
+
+ guard -> { !"test".frozen? } do
it "returns a different value for two String literals" do
o1 = "hello"
o2 = "hello"
diff --git a/string.c b/string.c
index a756523c4b..cbd8f90585 100644
--- a/string.c
+++ b/string.c
@@ -380,8 +380,9 @@ fstr_update_callback(st_data_t *key, st_data_t *value, st_data_t data, int exist
OBJ_FREEZE_RAW(str);
}
else {
- if (!OBJ_FROZEN(str))
+ if (!OBJ_FROZEN(str) || CHILLED_STRING_P(str)) {
str = str_new_frozen(rb_cString, str);
+ }
if (STR_SHARED_P(str)) { /* str should not be shared */
/* shared substring */
str_make_independent(str);
@@ -422,7 +423,7 @@ rb_fstring(VALUE str)
}
}
- if (!FL_TEST_RAW(str, FL_FREEZE | STR_NOFREE))
+ if (!FL_TEST_RAW(str, FL_FREEZE | STR_NOFREE | STR_CHILLED))
rb_str_resize(str, RSTRING_LEN(str));
fstr = register_fstring(str, FALSE);
@@ -1822,10 +1823,14 @@ rb_str_resurrect(VALUE str)
}
VALUE
-rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str)
+rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled)
{
RUBY_DTRACE_CREATE_HOOK(STRING, RSTRING_LEN(str));
- return ec_str_duplicate(ec, rb_cString, str);
+ VALUE new_str = ec_str_duplicate(ec, rb_cString, str);
+ if (chilled) {
+ STR_CHILL_RAW(new_str);
+ }
+ return new_str;
}
/*
@@ -3019,12 +3024,15 @@ str_substr(VALUE str, long beg, long len, int empty)
VALUE
rb_str_freeze(VALUE str)
{
+ if (CHILLED_STRING_P(str)) {
+ FL_UNSET_RAW(str, STR_CHILLED);
+ }
+
if (OBJ_FROZEN(str)) return str;
rb_str_resize(str, RSTRING_LEN(str));
return rb_obj_freeze(str);
}
-
/*
* call-seq:
* +string -> new_string or self
diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb
index 8af9f1ade0..eef909eb07 100644
--- a/test/ruby/test_compile_prism.rb
+++ b/test/ruby/test_compile_prism.rb
@@ -592,22 +592,16 @@ module Prism
assert_prism_eval('$pit = 1; "1 #$pit 1"')
assert_prism_eval('"1 #{1 + 2} 1"')
assert_prism_eval('"Prism" "::" "TestCompilePrism"')
- assert_prism_eval('("a""b").frozen?')
- assert_prism_eval(<<-CODE)
- # frozen_string_literal: true
-
- ("a""b").frozen?
- CODE
- assert_prism_eval(<<-CODE)
+ assert_prism_eval(<<-'RUBY')
# frozen_string_literal: true
- ("a""b""#{1}").frozen?
- CODE
- assert_prism_eval(<<-CODE)
+ !("a""b""#{1}").frozen?
+ RUBY
+ assert_prism_eval(<<-'RUBY')
# frozen_string_literal: true
- ("a""#{1}""b").frozen?
- CODE
+ !("a""#{1}""b").frozen?
+ RUBY
# Test encoding of interpolated strings
assert_prism_eval(<<~'RUBY')
@@ -620,6 +614,15 @@ module Prism
RUBY
end
+ def test_concatenated_StringNode
+ assert_prism_eval('("a""b").frozen?')
+ assert_prism_eval(<<-CODE)
+ # frozen_string_literal: true
+
+ ("a""b").frozen?
+ CODE
+ end
+
def test_InterpolatedSymbolNode
assert_prism_eval('$pit = 1; :"1 #$pit 1"')
assert_prism_eval(':"1 #{1 + 2} 1"')
@@ -673,7 +676,9 @@ module Prism
def test_StringNode
assert_prism_eval('"pit"')
assert_prism_eval('"a".frozen?')
+ end
+ def test_StringNode_frozen_string_literal_true
[
# Test that string literal is frozen
<<~RUBY,
@@ -690,6 +695,31 @@ module Prism
end
end
+ def test_StringNode_frozen_string_literal_false
+ [
+ # Test that string literal is frozen
+ <<~RUBY,
+ # frozen_string_literal: false
+ !"a".frozen?
+ RUBY
+ # Test that two string literals with the same contents are the same string
+ <<~RUBY,
+ # frozen_string_literal: false
+ !"hello".equal?("hello")
+ RUBY
+ ].each do |src|
+ assert_prism_eval(src, raw: true)
+ end
+ end
+
+ def test_StringNode_frozen_string_literal_default
+ # Test that string literal is chilled
+ assert_prism_eval('"a".frozen?')
+
+ # Test that two identical chilled string literals aren't the same object
+ assert_prism_eval('!"hello".equal?("hello")')
+ end
+
def test_SymbolNode
assert_prism_eval(":pit")
@@ -2620,27 +2650,28 @@ end
private
- def compare_eval(source, raw:)
+ def compare_eval(source, raw:, location:)
source = raw ? source : "class Prism::TestCompilePrism\n#{source}\nend"
ruby_eval = RubyVM::InstructionSequence.compile(source).eval
prism_eval = RubyVM::InstructionSequence.compile_prism(source).eval
if ruby_eval.is_a? Proc
- assert_equal ruby_eval.class, prism_eval.class
+ assert_equal ruby_eval.class, prism_eval.class, "@#{location.path}:#{location.lineno}"
else
- assert_equal ruby_eval, prism_eval
+ assert_equal ruby_eval, prism_eval, "@#{location.path}:#{location.lineno}"
end
end
def assert_prism_eval(source, raw: false)
+ location = caller_locations(1, 1).first
$VERBOSE, verbose_bak = nil, $VERBOSE
begin
- compare_eval(source, raw:)
+ compare_eval(source, raw:, location:)
# Test "popped" functionality
- compare_eval("#{source}; 1", raw:)
+ compare_eval("#{source}; 1", raw:, location:)
ensure
$VERBOSE = verbose_bak
end
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 58e1af2b61..3f1b91a6a9 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -3610,6 +3610,39 @@ CODE
assert_bytesplice_raise(ArgumentError, S("hello"), 0..-1, "bye", 0, 3)
end
+ def test_chilled_string
+ chilled_string = eval('"chilled"')
+
+ # Chilled strings pretend to be frozen
+ assert_predicate chilled_string, :frozen?
+
+ assert_not_predicate chilled_string.dup, :frozen?
+ assert_predicate chilled_string.clone, :frozen?
+
+ # @+ treat the original string as frozen
+ assert_not_predicate +chilled_string, :frozen?
+ assert_not_same chilled_string, +chilled_string
+
+ # @- the the original string as mutable
+ assert_predicate -chilled_string, :frozen?
+ assert_not_same chilled_string, -chilled_string
+ end
+
+ def test_chilled_string_setivar
+ String.class_eval <<~RUBY, __FILE__, __LINE__ + 1
+ def setivar!
+ @ivar = 42
+ @ivar
+ end
+ RUBY
+ chilled_string = eval('"chilled"')
+ begin
+ assert_equal 42, chilled_string.setivar!
+ ensure
+ String.undef_method(:setivar!)
+ end
+ end
+
private
def assert_bytesplice_result(expected, s, *args)
diff --git a/vm_eval.c b/vm_eval.c
index c52244ed1e..c9a9751ab3 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1663,7 +1663,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line,
pm_parse_result_t result = { 0 };
pm_options_line_set(&result.options, line);
- pm_options_frozen_string_literal_set(&result.options, rb_iseq_opt_frozen_string_literal());
+ pm_options_frozen_string_literal_init(&result, rb_iseq_opt_frozen_string_literal());
// Cout scopes, one for each parent iseq, plus one for our local scope
int scopes_count = 0;
diff --git a/vm_opts.h b/vm_opts.h
index 7b3caf4754..ce47745b11 100644
--- a/vm_opts.h
+++ b/vm_opts.h
@@ -19,7 +19,7 @@
#define OPT_PEEPHOLE_OPTIMIZATION 1
#define OPT_SPECIALISED_INSTRUCTION 1
#define OPT_INLINE_CONST_CACHE 1
-#define OPT_FROZEN_STRING_LITERAL 0
+#define OPT_FROZEN_STRING_LITERAL -1
#define OPT_DEBUG_FROZEN_STRING_LITERAL 0
/* Build Options.
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 745433ab00..6963aca48e 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -2327,7 +2327,28 @@ fn gen_putstring(
let str_opnd = asm.ccall(
rb_ec_str_resurrect as *const u8,
- vec![EC, put_val.into()]
+ vec![EC, put_val.into(), 0.into()]
+ );
+
+ let stack_top = asm.stack_push(Type::TString);
+ asm.mov(stack_top, str_opnd);
+
+ Some(KeepCompiling)
+}
+
+fn gen_putchilledstring(
+ jit: &mut JITState,
+ asm: &mut Assembler,
+ _ocb: &mut OutlinedCb,
+) -> Option<CodegenStatus> {
+ let put_val = jit.get_arg(0);
+
+ // Save the PC and SP because the callee will allocate
+ jit_prepare_call_with_gc(jit, asm);
+
+ let str_opnd = asm.ccall(
+ rb_ec_str_resurrect as *const u8,
+ vec![EC, put_val.into(), 1.into()]
);
let stack_top = asm.stack_push(Type::TString);
@@ -9778,6 +9799,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
YARVINSN_pushtoarray => Some(gen_pushtoarray),
YARVINSN_newrange => Some(gen_newrange),
YARVINSN_putstring => Some(gen_putstring),
+ YARVINSN_putchilledstring => Some(gen_putchilledstring),
YARVINSN_expandarray => Some(gen_expandarray),
YARVINSN_defined => Some(gen_defined),
YARVINSN_definedivar => Some(gen_definedivar),
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 36a0865246..359227d60d 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -726,195 +726,197 @@ pub const YARVINSN_putself: ruby_vminsn_type = 18;
pub const YARVINSN_putobject: ruby_vminsn_type = 19;
pub const YARVINSN_putspecialobject: ruby_vminsn_type = 20;
pub const YARVINSN_putstring: ruby_vminsn_type = 21;
-pub const YARVINSN_concatstrings: ruby_vminsn_type = 22;
-pub const YARVINSN_anytostring: ruby_vminsn_type = 23;
-pub const YARVINSN_toregexp: ruby_vminsn_type = 24;
-pub const YARVINSN_intern: ruby_vminsn_type = 25;
-pub const YARVINSN_newarray: ruby_vminsn_type = 26;
-pub const YARVINSN_newarraykwsplat: ruby_vminsn_type = 27;
-pub const YARVINSN_pushtoarraykwsplat: ruby_vminsn_type = 28;
-pub const YARVINSN_duparray: ruby_vminsn_type = 29;
-pub const YARVINSN_duphash: ruby_vminsn_type = 30;
-pub const YARVINSN_expandarray: ruby_vminsn_type = 31;
-pub const YARVINSN_concatarray: ruby_vminsn_type = 32;
-pub const YARVINSN_concattoarray: ruby_vminsn_type = 33;
-pub const YARVINSN_pushtoarray: ruby_vminsn_type = 34;
-pub const YARVINSN_splatarray: ruby_vminsn_type = 35;
-pub const YARVINSN_splatkw: ruby_vminsn_type = 36;
-pub const YARVINSN_newhash: ruby_vminsn_type = 37;
-pub const YARVINSN_newrange: ruby_vminsn_type = 38;
-pub const YARVINSN_pop: ruby_vminsn_type = 39;
-pub const YARVINSN_dup: ruby_vminsn_type = 40;
-pub const YARVINSN_dupn: ruby_vminsn_type = 41;
-pub const YARVINSN_swap: ruby_vminsn_type = 42;
-pub const YARVINSN_opt_reverse: ruby_vminsn_type = 43;
-pub const YARVINSN_topn: ruby_vminsn_type = 44;
-pub const YARVINSN_setn: ruby_vminsn_type = 45;
-pub const YARVINSN_adjuststack: ruby_vminsn_type = 46;
-pub const YARVINSN_defined: ruby_vminsn_type = 47;
-pub const YARVINSN_definedivar: ruby_vminsn_type = 48;
-pub const YARVINSN_checkmatch: ruby_vminsn_type = 49;
-pub const YARVINSN_checkkeyword: ruby_vminsn_type = 50;
-pub const YARVINSN_checktype: ruby_vminsn_type = 51;
-pub const YARVINSN_defineclass: ruby_vminsn_type = 52;
-pub const YARVINSN_definemethod: ruby_vminsn_type = 53;
-pub const YARVINSN_definesmethod: ruby_vminsn_type = 54;
-pub const YARVINSN_send: ruby_vminsn_type = 55;
-pub const YARVINSN_opt_send_without_block: ruby_vminsn_type = 56;
-pub const YARVINSN_objtostring: ruby_vminsn_type = 57;
-pub const YARVINSN_opt_str_freeze: ruby_vminsn_type = 58;
-pub const YARVINSN_opt_nil_p: ruby_vminsn_type = 59;
-pub const YARVINSN_opt_str_uminus: ruby_vminsn_type = 60;
-pub const YARVINSN_opt_newarray_send: ruby_vminsn_type = 61;
-pub const YARVINSN_invokesuper: ruby_vminsn_type = 62;
-pub const YARVINSN_invokeblock: ruby_vminsn_type = 63;
-pub const YARVINSN_leave: ruby_vminsn_type = 64;
-pub const YARVINSN_throw: ruby_vminsn_type = 65;
-pub const YARVINSN_jump: ruby_vminsn_type = 66;
-pub const YARVINSN_branchif: ruby_vminsn_type = 67;
-pub const YARVINSN_branchunless: ruby_vminsn_type = 68;
-pub const YARVINSN_branchnil: ruby_vminsn_type = 69;
-pub const YARVINSN_once: ruby_vminsn_type = 70;
-pub const YARVINSN_opt_case_dispatch: ruby_vminsn_type = 71;
-pub const YARVINSN_opt_plus: ruby_vminsn_type = 72;
-pub const YARVINSN_opt_minus: ruby_vminsn_type = 73;
-pub const YARVINSN_opt_mult: ruby_vminsn_type = 74;
-pub const YARVINSN_opt_div: ruby_vminsn_type = 75;
-pub const YARVINSN_opt_mod: ruby_vminsn_type = 76;
-pub const YARVINSN_opt_eq: ruby_vminsn_type = 77;
-pub const YARVINSN_opt_neq: ruby_vminsn_type = 78;
-pub const YARVINSN_opt_lt: ruby_vminsn_type = 79;
-pub const YARVINSN_opt_le: ruby_vminsn_type = 80;
-pub const YARVINSN_opt_gt: ruby_vminsn_type = 81;
-pub const YARVINSN_opt_ge: ruby_vminsn_type = 82;
-pub const YARVINSN_opt_ltlt: ruby_vminsn_type = 83;
-pub const YARVINSN_opt_and: ruby_vminsn_type = 84;
-pub const YARVINSN_opt_or: ruby_vminsn_type = 85;
-pub const YARVINSN_opt_aref: ruby_vminsn_type = 86;
-pub const YARVINSN_opt_aset: ruby_vminsn_type = 87;
-pub const YARVINSN_opt_aset_with: ruby_vminsn_type = 88;
-pub const YARVINSN_opt_aref_with: ruby_vminsn_type = 89;
-pub const YARVINSN_opt_length: ruby_vminsn_type = 90;
-pub const YARVINSN_opt_size: ruby_vminsn_type = 91;
-pub const YARVINSN_opt_empty_p: ruby_vminsn_type = 92;
-pub const YARVINSN_opt_succ: ruby_vminsn_type = 93;
-pub const YARVINSN_opt_not: ruby_vminsn_type = 94;
-pub const YARVINSN_opt_regexpmatch2: ruby_vminsn_type = 95;
-pub const YARVINSN_invokebuiltin: ruby_vminsn_type = 96;
-pub const YARVINSN_opt_invokebuiltin_delegate: ruby_vminsn_type = 97;
-pub const YARVINSN_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 98;
-pub const YARVINSN_getlocal_WC_0: ruby_vminsn_type = 99;
-pub const YARVINSN_getlocal_WC_1: ruby_vminsn_type = 100;
-pub const YARVINSN_setlocal_WC_0: ruby_vminsn_type = 101;
-pub const YARVINSN_setlocal_WC_1: ruby_vminsn_type = 102;
-pub const YARVINSN_putobject_INT2FIX_0_: ruby_vminsn_type = 103;
-pub const YARVINSN_putobject_INT2FIX_1_: ruby_vminsn_type = 104;
-pub const YARVINSN_trace_nop: ruby_vminsn_type = 105;
-pub const YARVINSN_trace_getlocal: ruby_vminsn_type = 106;
-pub const YARVINSN_trace_setlocal: ruby_vminsn_type = 107;
-pub const YARVINSN_trace_getblockparam: ruby_vminsn_type = 108;
-pub const YARVINSN_trace_setblockparam: ruby_vminsn_type = 109;
-pub const YARVINSN_trace_getblockparamproxy: ruby_vminsn_type = 110;
-pub const YARVINSN_trace_getspecial: ruby_vminsn_type = 111;
-pub const YARVINSN_trace_setspecial: ruby_vminsn_type = 112;
-pub const YARVINSN_trace_getinstancevariable: ruby_vminsn_type = 113;
-pub const YARVINSN_trace_setinstancevariable: ruby_vminsn_type = 114;
-pub const YARVINSN_trace_getclassvariable: ruby_vminsn_type = 115;
-pub const YARVINSN_trace_setclassvariable: ruby_vminsn_type = 116;
-pub const YARVINSN_trace_opt_getconstant_path: ruby_vminsn_type = 117;
-pub const YARVINSN_trace_getconstant: ruby_vminsn_type = 118;
-pub const YARVINSN_trace_setconstant: ruby_vminsn_type = 119;
-pub const YARVINSN_trace_getglobal: ruby_vminsn_type = 120;
-pub const YARVINSN_trace_setglobal: ruby_vminsn_type = 121;
-pub const YARVINSN_trace_putnil: ruby_vminsn_type = 122;
-pub const YARVINSN_trace_putself: ruby_vminsn_type = 123;
-pub const YARVINSN_trace_putobject: ruby_vminsn_type = 124;
-pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 125;
-pub const YARVINSN_trace_putstring: ruby_vminsn_type = 126;
-pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 127;
-pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 128;
-pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 129;
-pub const YARVINSN_trace_intern: ruby_vminsn_type = 130;
-pub const YARVINSN_trace_newarray: ruby_vminsn_type = 131;
-pub const YARVINSN_trace_newarraykwsplat: ruby_vminsn_type = 132;
-pub const YARVINSN_trace_pushtoarraykwsplat: ruby_vminsn_type = 133;
-pub const YARVINSN_trace_duparray: ruby_vminsn_type = 134;
-pub const YARVINSN_trace_duphash: ruby_vminsn_type = 135;
-pub const YARVINSN_trace_expandarray: ruby_vminsn_type = 136;
-pub const YARVINSN_trace_concatarray: ruby_vminsn_type = 137;
-pub const YARVINSN_trace_concattoarray: ruby_vminsn_type = 138;
-pub const YARVINSN_trace_pushtoarray: ruby_vminsn_type = 139;
-pub const YARVINSN_trace_splatarray: ruby_vminsn_type = 140;
-pub const YARVINSN_trace_splatkw: ruby_vminsn_type = 141;
-pub const YARVINSN_trace_newhash: ruby_vminsn_type = 142;
-pub const YARVINSN_trace_newrange: ruby_vminsn_type = 143;
-pub const YARVINSN_trace_pop: ruby_vminsn_type = 144;
-pub const YARVINSN_trace_dup: ruby_vminsn_type = 145;
-pub const YARVINSN_trace_dupn: ruby_vminsn_type = 146;
-pub const YARVINSN_trace_swap: ruby_vminsn_type = 147;
-pub const YARVINSN_trace_opt_reverse: ruby_vminsn_type = 148;
-pub const YARVINSN_trace_topn: ruby_vminsn_type = 149;
-pub const YARVINSN_trace_setn: ruby_vminsn_type = 150;
-pub const YARVINSN_trace_adjuststack: ruby_vminsn_type = 151;
-pub const YARVINSN_trace_defined: ruby_vminsn_type = 152;
-pub const YARVINSN_trace_definedivar: ruby_vminsn_type = 153;
-pub const YARVINSN_trace_checkmatch: ruby_vminsn_type = 154;
-pub const YARVINSN_trace_checkkeyword: ruby_vminsn_type = 155;
-pub const YARVINSN_trace_checktype: ruby_vminsn_type = 156;
-pub const YARVINSN_trace_defineclass: ruby_vminsn_type = 157;
-pub const YARVINSN_trace_definemethod: ruby_vminsn_type = 158;
-pub const YARVINSN_trace_definesmethod: ruby_vminsn_type = 159;
-pub const YARVINSN_trace_send: ruby_vminsn_type = 160;
-pub const YARVINSN_trace_opt_send_without_block: ruby_vminsn_type = 161;
-pub const YARVINSN_trace_objtostring: ruby_vminsn_type = 162;
-pub const YARVINSN_trace_opt_str_freeze: ruby_vminsn_type = 163;
-pub const YARVINSN_trace_opt_nil_p: ruby_vminsn_type = 164;
-pub const YARVINSN_trace_opt_str_uminus: ruby_vminsn_type = 165;
-pub const YARVINSN_trace_opt_newarray_send: ruby_vminsn_type = 166;
-pub const YARVINSN_trace_invokesuper: ruby_vminsn_type = 167;
-pub const YARVINSN_trace_invokeblock: ruby_vminsn_type = 168;
-pub const YARVINSN_trace_leave: ruby_vminsn_type = 169;
-pub const YARVINSN_trace_throw: ruby_vminsn_type = 170;
-pub const YARVINSN_trace_jump: ruby_vminsn_type = 171;
-pub const YARVINSN_trace_branchif: ruby_vminsn_type = 172;
-pub const YARVINSN_trace_branchunless: ruby_vminsn_type = 173;
-pub const YARVINSN_trace_branchnil: ruby_vminsn_type = 174;
-pub const YARVINSN_trace_once: ruby_vminsn_type = 175;
-pub const YARVINSN_trace_opt_case_dispatch: ruby_vminsn_type = 176;
-pub const YARVINSN_trace_opt_plus: ruby_vminsn_type = 177;
-pub const YARVINSN_trace_opt_minus: ruby_vminsn_type = 178;
-pub const YARVINSN_trace_opt_mult: ruby_vminsn_type = 179;
-pub const YARVINSN_trace_opt_div: ruby_vminsn_type = 180;
-pub const YARVINSN_trace_opt_mod: ruby_vminsn_type = 181;
-pub const YARVINSN_trace_opt_eq: ruby_vminsn_type = 182;
-pub const YARVINSN_trace_opt_neq: ruby_vminsn_type = 183;
-pub const YARVINSN_trace_opt_lt: ruby_vminsn_type = 184;
-pub const YARVINSN_trace_opt_le: ruby_vminsn_type = 185;
-pub const YARVINSN_trace_opt_gt: ruby_vminsn_type = 186;
-pub const YARVINSN_trace_opt_ge: ruby_vminsn_type = 187;
-pub const YARVINSN_trace_opt_ltlt: ruby_vminsn_type = 188;
-pub const YARVINSN_trace_opt_and: ruby_vminsn_type = 189;
-pub const YARVINSN_trace_opt_or: ruby_vminsn_type = 190;
-pub const YARVINSN_trace_opt_aref: ruby_vminsn_type = 191;
-pub const YARVINSN_trace_opt_aset: ruby_vminsn_type = 192;
-pub const YARVINSN_trace_opt_aset_with: ruby_vminsn_type = 193;
-pub const YARVINSN_trace_opt_aref_with: ruby_vminsn_type = 194;
-pub const YARVINSN_trace_opt_length: ruby_vminsn_type = 195;
-pub const YARVINSN_trace_opt_size: ruby_vminsn_type = 196;
-pub const YARVINSN_trace_opt_empty_p: ruby_vminsn_type = 197;
-pub const YARVINSN_trace_opt_succ: ruby_vminsn_type = 198;
-pub const YARVINSN_trace_opt_not: ruby_vminsn_type = 199;
-pub const YARVINSN_trace_opt_regexpmatch2: ruby_vminsn_type = 200;
-pub const YARVINSN_trace_invokebuiltin: ruby_vminsn_type = 201;
-pub const YARVINSN_trace_opt_invokebuiltin_delegate: ruby_vminsn_type = 202;
-pub const YARVINSN_trace_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 203;
-pub const YARVINSN_trace_getlocal_WC_0: ruby_vminsn_type = 204;
-pub const YARVINSN_trace_getlocal_WC_1: ruby_vminsn_type = 205;
-pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 206;
-pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 207;
-pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 208;
-pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 209;
-pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 210;
+pub const YARVINSN_putchilledstring: ruby_vminsn_type = 22;
+pub const YARVINSN_concatstrings: ruby_vminsn_type = 23;
+pub const YARVINSN_anytostring: ruby_vminsn_type = 24;
+pub const YARVINSN_toregexp: ruby_vminsn_type = 25;
+pub const YARVINSN_intern: ruby_vminsn_type = 26;
+pub const YARVINSN_newarray: ruby_vminsn_type = 27;
+pub const YARVINSN_newarraykwsplat: ruby_vminsn_type = 28;
+pub const YARVINSN_pushtoarraykwsplat: ruby_vminsn_type = 29;
+pub const YARVINSN_duparray: ruby_vminsn_type = 30;
+pub const YARVINSN_duphash: ruby_vminsn_type = 31;
+pub const YARVINSN_expandarray: ruby_vminsn_type = 32;
+pub const YARVINSN_concatarray: ruby_vminsn_type = 33;
+pub const YARVINSN_concattoarray: ruby_vminsn_type = 34;
+pub const YARVINSN_pushtoarray: ruby_vminsn_type = 35;
+pub const YARVINSN_splatarray: ruby_vminsn_type = 36;
+pub const YARVINSN_splatkw: ruby_vminsn_type = 37;
+pub const YARVINSN_newhash: ruby_vminsn_type = 38;
+pub const YARVINSN_newrange: ruby_vminsn_type = 39;
+pub const YARVINSN_pop: ruby_vminsn_type = 40;
+pub const YARVINSN_dup: ruby_vminsn_type = 41;
+pub const YARVINSN_dupn: ruby_vminsn_type = 42;
+pub const YARVINSN_swap: ruby_vminsn_type = 43;
+pub const YARVINSN_opt_reverse: ruby_vminsn_type = 44;
+pub const YARVINSN_topn: ruby_vminsn_type = 45;
+pub const YARVINSN_setn: ruby_vminsn_type = 46;
+pub const YARVINSN_adjuststack: ruby_vminsn_type = 47;
+pub const YARVINSN_defined: ruby_vminsn_type = 48;
+pub const YARVINSN_definedivar: ruby_vminsn_type = 49;
+pub const YARVINSN_checkmatch: ruby_vminsn_type = 50;
+pub const YARVINSN_checkkeyword: ruby_vminsn_type = 51;
+pub const YARVINSN_checktype: ruby_vminsn_type = 52;
+pub const YARVINSN_defineclass: ruby_vminsn_type = 53;
+pub const YARVINSN_definemethod: ruby_vminsn_type = 54;
+pub const YARVINSN_definesmethod: ruby_vminsn_type = 55;
+pub const YARVINSN_send: ruby_vminsn_type = 56;
+pub const YARVINSN_opt_send_without_block: ruby_vminsn_type = 57;
+pub const YARVINSN_objtostring: ruby_vminsn_type = 58;
+pub const YARVINSN_opt_str_freeze: ruby_vminsn_type = 59;
+pub const YARVINSN_opt_nil_p: ruby_vminsn_type = 60;
+pub const YARVINSN_opt_str_uminus: ruby_vminsn_type = 61;
+pub const YARVINSN_opt_newarray_send: ruby_vminsn_type = 62;
+pub const YARVINSN_invokesuper: ruby_vminsn_type = 63;
+pub const YARVINSN_invokeblock: ruby_vminsn_type = 64;
+pub const YARVINSN_leave: ruby_vminsn_type = 65;
+pub const YARVINSN_throw: ruby_vminsn_type = 66;
+pub const YARVINSN_jump: ruby_vminsn_type = 67;
+pub const YARVINSN_branchif: ruby_vminsn_type = 68;
+pub const YARVINSN_branchunless: ruby_vminsn_type = 69;
+pub const YARVINSN_branchnil: ruby_vminsn_type = 70;
+pub const YARVINSN_once: ruby_vminsn_type = 71;
+pub const YARVINSN_opt_case_dispatch: ruby_vminsn_type = 72;
+pub const YARVINSN_opt_plus: ruby_vminsn_type = 73;
+pub const YARVINSN_opt_minus: ruby_vminsn_type = 74;
+pub const YARVINSN_opt_mult: ruby_vminsn_type = 75;
+pub const YARVINSN_opt_div: ruby_vminsn_type = 76;
+pub const YARVINSN_opt_mod: ruby_vminsn_type = 77;
+pub const YARVINSN_opt_eq: ruby_vminsn_type = 78;
+pub const YARVINSN_opt_neq: ruby_vminsn_type = 79;
+pub const YARVINSN_opt_lt: ruby_vminsn_type = 80;
+pub const YARVINSN_opt_le: ruby_vminsn_type = 81;
+pub const YARVINSN_opt_gt: ruby_vminsn_type = 82;
+pub const YARVINSN_opt_ge: ruby_vminsn_type = 83;
+pub const YARVINSN_opt_ltlt: ruby_vminsn_type = 84;
+pub const YARVINSN_opt_and: ruby_vminsn_type = 85;
+pub const YARVINSN_opt_or: ruby_vminsn_type = 86;
+pub const YARVINSN_opt_aref: ruby_vminsn_type = 87;
+pub const YARVINSN_opt_aset: ruby_vminsn_type = 88;
+pub const YARVINSN_opt_aset_with: ruby_vminsn_type = 89;
+pub const YARVINSN_opt_aref_with: ruby_vminsn_type = 90;
+pub const YARVINSN_opt_length: ruby_vminsn_type = 91;
+pub const YARVINSN_opt_size: ruby_vminsn_type = 92;
+pub const YARVINSN_opt_empty_p: ruby_vminsn_type = 93;
+pub const YARVINSN_opt_succ: ruby_vminsn_type = 94;
+pub const YARVINSN_opt_not: ruby_vminsn_type = 95;
+pub const YARVINSN_opt_regexpmatch2: ruby_vminsn_type = 96;
+pub const YARVINSN_invokebuiltin: ruby_vminsn_type = 97;
+pub const YARVINSN_opt_invokebuiltin_delegate: ruby_vminsn_type = 98;
+pub const YARVINSN_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 99;
+pub const YARVINSN_getlocal_WC_0: ruby_vminsn_type = 100;
+pub const YARVINSN_getlocal_WC_1: ruby_vminsn_type = 101;
+pub const YARVINSN_setlocal_WC_0: ruby_vminsn_type = 102;
+pub const YARVINSN_setlocal_WC_1: ruby_vminsn_type = 103;
+pub const YARVINSN_putobject_INT2FIX_0_: ruby_vminsn_type = 104;
+pub const YARVINSN_putobject_INT2FIX_1_: ruby_vminsn_type = 105;
+pub const YARVINSN_trace_nop: ruby_vminsn_type = 106;
+pub const YARVINSN_trace_getlocal: ruby_vminsn_type = 107;
+pub const YARVINSN_trace_setlocal: ruby_vminsn_type = 108;
+pub const YARVINSN_trace_getblockparam: ruby_vminsn_type = 109;
+pub const YARVINSN_trace_setblockparam: ruby_vminsn_type = 110;
+pub const YARVINSN_trace_getblockparamproxy: ruby_vminsn_type = 111;
+pub const YARVINSN_trace_getspecial: ruby_vminsn_type = 112;
+pub const YARVINSN_trace_setspecial: ruby_vminsn_type = 113;
+pub const YARVINSN_trace_getinstancevariable: ruby_vminsn_type = 114;
+pub const YARVINSN_trace_setinstancevariable: ruby_vminsn_type = 115;
+pub const YARVINSN_trace_getclassvariable: ruby_vminsn_type = 116;
+pub const YARVINSN_trace_setclassvariable: ruby_vminsn_type = 117;
+pub const YARVINSN_trace_opt_getconstant_path: ruby_vminsn_type = 118;
+pub const YARVINSN_trace_getconstant: ruby_vminsn_type = 119;
+pub const YARVINSN_trace_setconstant: ruby_vminsn_type = 120;
+pub const YARVINSN_trace_getglobal: ruby_vminsn_type = 121;
+pub const YARVINSN_trace_setglobal: ruby_vminsn_type = 122;
+pub const YARVINSN_trace_putnil: ruby_vminsn_type = 123;
+pub const YARVINSN_trace_putself: ruby_vminsn_type = 124;
+pub const YARVINSN_trace_putobject: ruby_vminsn_type = 125;
+pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 126;
+pub const YARVINSN_trace_putstring: ruby_vminsn_type = 127;
+pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 128;
+pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 129;
+pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 130;
+pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 131;
+pub const YARVINSN_trace_intern: ruby_vminsn_type = 132;
+pub const YARVINSN_trace_newarray: ruby_vminsn_type = 133;
+pub const YARVINSN_trace_newarraykwsplat: ruby_vminsn_type = 134;
+pub const YARVINSN_trace_pushtoarraykwsplat: ruby_vminsn_type = 135;
+pub const YARVINSN_trace_duparray: ruby_vminsn_type = 136;
+pub const YARVINSN_trace_duphash: ruby_vminsn_type = 137;
+pub const YARVINSN_trace_expandarray: ruby_vminsn_type = 138;
+pub const YARVINSN_trace_concatarray: ruby_vminsn_type = 139;
+pub const YARVINSN_trace_concattoarray: ruby_vminsn_type = 140;
+pub const YARVINSN_trace_pushtoarray: ruby_vminsn_type = 141;
+pub const YARVINSN_trace_splatarray: ruby_vminsn_type = 142;
+pub const YARVINSN_trace_splatkw: ruby_vminsn_type = 143;
+pub const YARVINSN_trace_newhash: ruby_vminsn_type = 144;
+pub const YARVINSN_trace_newrange: ruby_vminsn_type = 145;
+pub const YARVINSN_trace_pop: ruby_vminsn_type = 146;
+pub const YARVINSN_trace_dup: ruby_vminsn_type = 147;
+pub const YARVINSN_trace_dupn: ruby_vminsn_type = 148;
+pub const YARVINSN_trace_swap: ruby_vminsn_type = 149;
+pub const YARVINSN_trace_opt_reverse: ruby_vminsn_type = 150;
+pub const YARVINSN_trace_topn: ruby_vminsn_type = 151;
+pub const YARVINSN_trace_setn: ruby_vminsn_type = 152;
+pub const YARVINSN_trace_adjuststack: ruby_vminsn_type = 153;
+pub const YARVINSN_trace_defined: ruby_vminsn_type = 154;
+pub const YARVINSN_trace_definedivar: ruby_vminsn_type = 155;
+pub const YARVINSN_trace_checkmatch: ruby_vminsn_type = 156;
+pub const YARVINSN_trace_checkkeyword: ruby_vminsn_type = 157;
+pub const YARVINSN_trace_checktype: ruby_vminsn_type = 158;
+pub const YARVINSN_trace_defineclass: ruby_vminsn_type = 159;
+pub const YARVINSN_trace_definemethod: ruby_vminsn_type = 160;
+pub const YARVINSN_trace_definesmethod: ruby_vminsn_type = 161;
+pub const YARVINSN_trace_send: ruby_vminsn_type = 162;
+pub const YARVINSN_trace_opt_send_without_block: ruby_vminsn_type = 163;
+pub const YARVINSN_trace_objtostring: ruby_vminsn_type = 164;
+pub const YARVINSN_trace_opt_str_freeze: ruby_vminsn_type = 165;
+pub const YARVINSN_trace_opt_nil_p: ruby_vminsn_type = 166;
+pub const YARVINSN_trace_opt_str_uminus: ruby_vminsn_type = 167;
+pub const YARVINSN_trace_opt_newarray_send: ruby_vminsn_type = 168;
+pub const YARVINSN_trace_invokesuper: ruby_vminsn_type = 169;
+pub const YARVINSN_trace_invokeblock: ruby_vminsn_type = 170;
+pub const YARVINSN_trace_leave: ruby_vminsn_type = 171;
+pub const YARVINSN_trace_throw: ruby_vminsn_type = 172;
+pub const YARVINSN_trace_jump: ruby_vminsn_type = 173;
+pub const YARVINSN_trace_branchif: ruby_vminsn_type = 174;
+pub const YARVINSN_trace_branchunless: ruby_vminsn_type = 175;
+pub const YARVINSN_trace_branchnil: ruby_vminsn_type = 176;
+pub const YARVINSN_trace_once: ruby_vminsn_type = 177;
+pub const YARVINSN_trace_opt_case_dispatch: ruby_vminsn_type = 178;
+pub const YARVINSN_trace_opt_plus: ruby_vminsn_type = 179;
+pub const YARVINSN_trace_opt_minus: ruby_vminsn_type = 180;
+pub const YARVINSN_trace_opt_mult: ruby_vminsn_type = 181;
+pub const YARVINSN_trace_opt_div: ruby_vminsn_type = 182;
+pub const YARVINSN_trace_opt_mod: ruby_vminsn_type = 183;
+pub const YARVINSN_trace_opt_eq: ruby_vminsn_type = 184;
+pub const YARVINSN_trace_opt_neq: ruby_vminsn_type = 185;
+pub const YARVINSN_trace_opt_lt: ruby_vminsn_type = 186;
+pub const YARVINSN_trace_opt_le: ruby_vminsn_type = 187;
+pub const YARVINSN_trace_opt_gt: ruby_vminsn_type = 188;
+pub const YARVINSN_trace_opt_ge: ruby_vminsn_type = 189;
+pub const YARVINSN_trace_opt_ltlt: ruby_vminsn_type = 190;
+pub const YARVINSN_trace_opt_and: ruby_vminsn_type = 191;
+pub const YARVINSN_trace_opt_or: ruby_vminsn_type = 192;
+pub const YARVINSN_trace_opt_aref: ruby_vminsn_type = 193;
+pub const YARVINSN_trace_opt_aset: ruby_vminsn_type = 194;
+pub const YARVINSN_trace_opt_aset_with: ruby_vminsn_type = 195;
+pub const YARVINSN_trace_opt_aref_with: ruby_vminsn_type = 196;
+pub const YARVINSN_trace_opt_length: ruby_vminsn_type = 197;
+pub const YARVINSN_trace_opt_size: ruby_vminsn_type = 198;
+pub const YARVINSN_trace_opt_empty_p: ruby_vminsn_type = 199;
+pub const YARVINSN_trace_opt_succ: ruby_vminsn_type = 200;
+pub const YARVINSN_trace_opt_not: ruby_vminsn_type = 201;
+pub const YARVINSN_trace_opt_regexpmatch2: ruby_vminsn_type = 202;
+pub const YARVINSN_trace_invokebuiltin: ruby_vminsn_type = 203;
+pub const YARVINSN_trace_opt_invokebuiltin_delegate: ruby_vminsn_type = 204;
+pub const YARVINSN_trace_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 205;
+pub const YARVINSN_trace_getlocal_WC_0: ruby_vminsn_type = 206;
+pub const YARVINSN_trace_getlocal_WC_1: ruby_vminsn_type = 207;
+pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 208;
+pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 209;
+pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 210;
+pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 211;
+pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 212;
pub type ruby_vminsn_type = u32;
pub type rb_iseq_callback = ::std::option::Option<
unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void),
@@ -1055,7 +1057,11 @@ extern "C" {
pub fn rb_str_byte_substr(str_: VALUE, beg: VALUE, len: VALUE) -> VALUE;
pub fn rb_obj_as_string_result(str_: VALUE, obj: VALUE) -> VALUE;
pub fn rb_str_concat_literals(num: usize, strary: *const VALUE) -> VALUE;
- pub fn rb_ec_str_resurrect(ec: *mut rb_execution_context_struct, str_: VALUE) -> VALUE;
+ pub fn rb_ec_str_resurrect(
+ ec: *mut rb_execution_context_struct,
+ str_: VALUE,
+ chilled: bool,
+ ) -> VALUE;
pub fn rb_to_hash_type(obj: VALUE) -> VALUE;
pub fn rb_hash_stlike_foreach(
hash: VALUE,