зеркало из https://github.com/github/ruby.git
Implement chilled strings
[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:
Родитель
86b15316a7
Коммит
12be40ae6b
6
NEWS.md
6
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
5
class.c
5
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");
|
||||
}
|
||||
}
|
||||
|
|
17
compile.c
17
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;
|
||||
|
|
6
error.c
6
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": ",
|
||||
|
|
|
@ -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.
|
||||
|
|
12
insns.def
12
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 */
|
||||
|
|
|
@ -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
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
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;
|
||||
|
|
5
object.c
5
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
16
ractor.c
16
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;
|
||||
|
|
2
ruby.c
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"
|
||||
|
|
18
string.c
18
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
|
||||
|
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче