[Feature #20205]

As a path toward enabling frozen string literals by default in the future,
this commit introduce "chilled strings". From a user perspective chilled
strings pretend to be frozen, but on the first attempt to mutate them,
they lose their frozen status and emit a warning rather than to raise a
`FrozenError`.

Implementation wise, `rb_compile_option_struct.frozen_string_literal` is
no longer a boolean but a tri-state of `enabled/disabled/unset`.

When code is compiled with frozen string literals neither explictly enabled
or disabled, string literals are compiled with a new `putchilledstring`
instruction. This instruction is identical to `putstring` except it marks
the String with the `STR_CHILLED (FL_USER3)` and `FL_FREEZE` flags.

Chilled strings have the `FL_FREEZE` flag as to minimize the need to check
for chilled strings across the codebase, and to improve compatibility with
C extensions.

Notes:
  - `String#freeze`: clears the chilled flag.
  - `String#-@`: acts as if the string was mutable.
  - `String#+@`: acts as if the string was mutable.
  - `String#clone`: copies the chilled flag.

Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
Étienne Barrié 2023-12-01 11:33:00 +01:00 коммит произвёл Jean Boussier
Родитель 86b15316a7
Коммит 12be40ae6b
36 изменённых файлов: 714 добавлений и 282 удалений

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

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

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

@ -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)
}

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

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

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

@ -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");
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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 */

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

@ -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)
@ -108,6 +109,26 @@ STR_SHARED_P(VALUE str)
return FL_ALL_RAW(str, STR_NOEMBED | STR_SHARED);
}
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)
{

31
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)) {

6
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;

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

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

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

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

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

@ -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);

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

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

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

@ -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);

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

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

2
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));

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

@ -0,0 +1,4 @@
# frozen_string_literal: true
frozen = "test".frozen?
interned = "test".equal?("test")
puts "frozen:#{frozen} interned:#{interned}"

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

@ -0,0 +1,4 @@
# frozen_string_literal: false
frozen = "test".frozen?
interned = "test".equal?("test")
puts "frozen:#{frozen} interned:#{interned}"

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

@ -0,0 +1,3 @@
frozen = "test".frozen?
interned = "test".equal?("test")
puts "frozen:#{frozen} interned:#{interned}"

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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)
assert_prism_eval(<<-'RUBY')
# frozen_string_literal: true
("a""b").frozen?
CODE
assert_prism_eval(<<-CODE)
!("a""b""#{1}").frozen?
RUBY
assert_prism_eval(<<-'RUBY')
# frozen_string_literal: true
("a""b""#{1}").frozen?
CODE
assert_prism_eval(<<-CODE)
# 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

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

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

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

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

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

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

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

@ -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),

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

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