Rename putstring instruction as dupstring

As well as `putchilledstring` as `dupchilledstring`.

This is more consistent with similar `duparray` and `duphash`
instructions and better reflect it's behavior.
This commit is contained in:
Jean Boussier committed 2026-04-30 06:30:50 +09:00
1 parent 3f75e99961
commit 072a6a4a10
15 files changed
+60 -60
Notes: git 2026-04-29 21:31:26 +00:00

No files matched your search

+1 -1
View File
@@ -86,7 +86,7 @@ tests = [
[ 'putobject', %q{ /(?<x>x)/ =~ "x"; x == "x" }, ],
[ 'putspecialobject', %q{ {//=>true}[//] }, ],
[ 'putstring', %q{ "true" }, ],
[ 'dupstring', %q{ "true" }, ],
[ 'tostring / concatstrings', %q{ "#{true}" }, ],
[ 'toregexp', %q{ /#{true}/ =~ "true" && $~ }, ],
[ 'intern', %q{ :"#{true}" }, ],
+22 -22
View File
@@ -3195,7 +3195,7 @@ iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
static int
is_frozen_putstring(INSN *insn, VALUE *op)
{
if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
*op = OPERAND_AT(insn, 0);
return 1;
}
@@ -3255,8 +3255,8 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
VALUE type;
switch (INSN_OF(iobj)) {
case BIN(putstring):
case BIN(putchilledstring):
case BIN(dupstring):
case BIN(dupchilledstring):
type = INT2FIX(T_STRING);
break;
case BIN(putnil):
@@ -3454,8 +3454,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
/*
* putstring "beg"
* putstring "end"
* dupstring "beg"
* dupstring "end"
* newrange excl
*
* ==>
@@ -3670,16 +3670,16 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* =>
* jump L1
*
* putstring ".."
* dupstring ".."
* if L1
* =>
* jump L1
*
* putstring ".."
* dupstring ".."
* dup
* if L1
* =>
* putstring ".."
* dupstring ".."
* jump L1
*
*/
@@ -3694,7 +3694,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
OPERAND_AT(pobj, 0) == Qfalse :
FALSE);
}
else if (IS_INSN_ID(pobj, putstring) ||
else if (IS_INSN_ID(pobj, dupstring) ||
IS_INSN_ID(pobj, duparray) ||
IS_INSN_ID(pobj, newarray)) {
cond = IS_INSN_ID(iobj, branchif);
@@ -3732,7 +3732,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN_ID(iobj, pop)) {
/*
* putself / putnil / putobject obj / putstring "..."
* putself / putnil / putobject obj / dupstring "..."
* pop
* =>
* # do nothing
@@ -3741,8 +3741,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN(prev)) {
enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
if (previ == BIN(putobject) || previ == BIN(putnil) ||
previ == BIN(putself) || previ == BIN(putstring) ||
previ == BIN(putchilledstring) ||
previ == BIN(putself) || previ == BIN(dupstring) ||
previ == BIN(dupchilledstring) ||
previ == BIN(dup) ||
previ == BIN(getlocal) ||
previ == BIN(getblockparam) ||
@@ -3884,10 +3884,10 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
(IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
/*
* putstring ""
* dupstring ""
* concatstrings N
* =>
* concatstrings N-1
@@ -4222,7 +4222,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
}
}
}
else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
IS_NEXT_INSN_ID(&niobj->link, send)) {
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
@@ -4235,9 +4235,9 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
return COMPILE_OK;
}
}
// newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
// -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
// newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
// -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
(IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
(niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
@@ -4260,7 +4260,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
// Break the "else if" chain since some prior checks abort after sub-ifs.
// We already found "newarray". To match `[...].include?(arg)` we look for
// the instruction(s) representing the argument followed by a "send".
if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
IS_INSN_ID(niobj, putobject) ||
IS_INSN_ID(niobj, putself) ||
IS_INSN_ID(niobj, getlocal) ||
@@ -4729,7 +4729,7 @@ compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
int cnt;
if (!RNODE_DSTR(node)->nd_next) {
VALUE lit = rb_node_dstr_string_val(node);
ADD_INSN1(ret, node, putstring, lit);
ADD_INSN1(ret, node, dupstring, lit);
RB_OBJ_SET_SHAREABLE(lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -11250,10 +11250,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
switch (option->frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
ADD_INSN1(ret, node, putchilledstring, lit);
ADD_INSN1(ret, node, dupchilledstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
ADD_INSN1(ret, node, putstring, lit);
ADD_INSN1(ret, node, dupstring, lit);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
ADD_INSN1(ret, node, putobject, lit);
+4 -4
View File
@@ -6,12 +6,12 @@
__END__
putobject putobject
putobject putstring
putobject dupstring
putobject setlocal
putstring putstring
putstring putobject
putstring setlocal
dupstring dupstring
dupstring putobject
dupstring setlocal
# putnil end
+1 -1
View File
@@ -18,7 +18,7 @@ The supported dump items:
$ ruby --dump=insns t.rb
== disasm: #<ISeq:<main>@t.rb:1 (1,0)-(1,10)> (catch: FALSE)
0000 putself ( 1)[Li]
0001 putstring "Foo"
0001 dupstring "Foo"
0003 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0005 leave
```
+2 -2
View File
@@ -373,7 +373,7 @@ putspecialobject
/* put string val. string will be copied. */
DEFINE_INSN
putstring
dupstring
(VALUE str)
()
(VALUE val)
@@ -383,7 +383,7 @@ putstring
/* put chilled string val. string will be copied but frozen in the future. */
DEFINE_INSN
putchilledstring
dupchilledstring
(VALUE str)
()
(VALUE val)
+1 -1
View File
@@ -3266,7 +3266,7 @@ iseqw_s_of(VALUE klass, VALUE body)
* 0000 trace 8 ( 1)
* 0002 trace 1 ( 2)
* 0004 putself
* 0005 putstring "hello, world"
* 0005 dupstring "hello, world"
* 0007 send :puts, 1, nil, 8, <ic:0>
* 0013 trace 16 ( 3)
* 0015 leave ( 2)
+1 -1
View File
@@ -5074,7 +5074,7 @@ pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_inte
* PM_NODE_FLAG_STATIC_LITERAL indicates that the node should be treated as a
* single static literal string that can be pushed onto the stack on its own.
* Note that this doesn't necessarily mean that the string will be frozen or
* not; the instructions in CRuby will be either putobject or putstring,
* not; the instructions in CRuby will be either putobject, dupstring or dupchilledstring,
* depending on the combination of `--enable-frozen-string-literal`,
* `# frozen_string_literal: true`, and whether or not there is interpolation.
*
+8 -8
View File
@@ -774,9 +774,9 @@ pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const
if (frozen_result) {
PUSH_INSN1(ret, current_location, putobject, current_string);
} else if (mutable_result || interpolated) {
PUSH_INSN1(ret, current_location, putstring, current_string);
PUSH_INSN1(ret, current_location, dupstring, current_string);
} else {
PUSH_INSN1(ret, current_location, putchilledstring, current_string);
PUSH_INSN1(ret, current_location, dupchilledstring, current_string);
}
} else {
PUSH_INSN1(ret, current_location, putobject, current_string);
@@ -9677,10 +9677,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, string);
PUSH_INSN1(ret, location, dupstring, string);
}
else {
PUSH_INSN1(ret, location, putchilledstring, string);
PUSH_INSN1(ret, location, dupchilledstring, string);
}
}
}
@@ -10395,10 +10395,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, string);
PUSH_INSN1(ret, location, dupstring, string);
}
else {
PUSH_INSN1(ret, location, putchilledstring, string);
PUSH_INSN1(ret, location, dupchilledstring, string);
}
}
return;
@@ -10452,10 +10452,10 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, putobject, value);
}
else if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, value);
PUSH_INSN1(ret, location, dupstring, value);
}
else {
PUSH_INSN1(ret, location, putchilledstring, value);
PUSH_INSN1(ret, location, dupchilledstring, value);
}
}
return;
+1 -1
View File
@@ -728,7 +728,7 @@ class TestRubyOptimization < Test::Unit::TestCase
insn = iseq.disasm
assert_match %r{putobject\s+#{Regexp.quote('"1.8.0"..."1.8.8"')}}, insn
assert_match %r{putobject\s+#{Regexp.quote('"2.0.0".."2.3.2"')}}, insn
assert_no_match(/putstring/, insn)
assert_no_match(/dupstring/, insn)
assert_no_match(/newrange/, insn)
end
end
+4 -4
View File
@@ -2764,7 +2764,7 @@ fn gen_newhash(
Some(KeepCompiling)
}
fn gen_putstring(
fn gen_dupstring(
jit: &mut JITState,
asm: &mut Assembler,
) -> Option<CodegenStatus> {
@@ -2784,7 +2784,7 @@ fn gen_putstring(
Some(KeepCompiling)
}
fn gen_putchilledstring(
fn gen_dupchilledstring(
jit: &mut JITState,
asm: &mut Assembler,
) -> Option<CodegenStatus> {
@@ -10814,8 +10814,8 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
YARVINSN_concattoarray => Some(gen_concattoarray),
YARVINSN_pushtoarray => Some(gen_pushtoarray),
YARVINSN_newrange => Some(gen_newrange),
YARVINSN_putstring => Some(gen_putstring),
YARVINSN_putchilledstring => Some(gen_putchilledstring),
YARVINSN_dupstring => Some(gen_dupstring),
YARVINSN_dupchilledstring => Some(gen_dupchilledstring),
YARVINSN_expandarray => Some(gen_expandarray),
YARVINSN_defined => Some(gen_defined),
YARVINSN_definedivar => Some(gen_definedivar),
+4 -4
View File
@@ -723,8 +723,8 @@ pub const YARVINSN_putnil: ruby_vminsn_type = 17;
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_putchilledstring: ruby_vminsn_type = 22;
pub const YARVINSN_dupstring: ruby_vminsn_type = 21;
pub const YARVINSN_dupchilledstring: 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;
@@ -836,8 +836,8 @@ pub const YARVINSN_trace_putnil: ruby_vminsn_type = 130;
pub const YARVINSN_trace_putself: ruby_vminsn_type = 131;
pub const YARVINSN_trace_putobject: ruby_vminsn_type = 132;
pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 133;
pub const YARVINSN_trace_putstring: ruby_vminsn_type = 134;
pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 135;
pub const YARVINSN_trace_dupstring: ruby_vminsn_type = 134;
pub const YARVINSN_trace_dupchilledstring: ruby_vminsn_type = 135;
pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 136;
pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 137;
pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 138;
+4 -4
View File
@@ -69,22 +69,22 @@ fn test_putobject() {
}
#[test]
fn test_putstring() {
fn test_dupstring() {
eval(r##"
def test = "#{""}"
test
"##);
assert_contains_opcode("test", YARVINSN_putstring);
assert_contains_opcode("test", YARVINSN_dupstring);
assert_snapshot!(assert_compiles(r##"test"##), @r#""""#);
}
#[test]
fn test_putchilledstring() {
fn test_dupchilledstring() {
eval(r#"
def test = ""
test
"#);
assert_contains_opcode("test", YARVINSN_putchilledstring);
assert_contains_opcode("test", YARVINSN_dupchilledstring);
assert_snapshot!(assert_compiles(r#"test"#), @r#""""#);
}
+4 -4
View File
@@ -1589,8 +1589,8 @@ pub const YARVINSN_putnil: ruby_vminsn_type = 17;
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_putchilledstring: ruby_vminsn_type = 22;
pub const YARVINSN_dupstring: ruby_vminsn_type = 21;
pub const YARVINSN_dupchilledstring: 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;
@@ -1702,8 +1702,8 @@ pub const YARVINSN_trace_putnil: ruby_vminsn_type = 130;
pub const YARVINSN_trace_putself: ruby_vminsn_type = 131;
pub const YARVINSN_trace_putobject: ruby_vminsn_type = 132;
pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 133;
pub const YARVINSN_trace_putstring: ruby_vminsn_type = 134;
pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 135;
pub const YARVINSN_trace_dupstring: ruby_vminsn_type = 134;
pub const YARVINSN_trace_dupchilledstring: ruby_vminsn_type = 135;
pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 136;
pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 137;
pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 138;
+2 -2
View File
@@ -6984,12 +6984,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
};
state.stack_push(fun.push_insn(block, insn));
}
YARVINSN_putstring => {
YARVINSN_dupstring => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let insn_id = fun.push_insn(block, Insn::StringCopy { val, chilled: false, state: exit_id });
state.stack_push(insn_id);
}
YARVINSN_putchilledstring => {
YARVINSN_dupchilledstring => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let insn_id = fun.push_insn(block, Insn::StringCopy { val, chilled: true, state: exit_id });
state.stack_push(insn_id);
+1 -1
View File
@@ -744,7 +744,7 @@ pub(crate) mod hir_build_tests {
#[test]
fn test_string_copy() {
eval("def test = \"hello\"");
assert_contains_opcode("test", YARVINSN_putchilledstring);
assert_contains_opcode("test", YARVINSN_dupchilledstring);
assert_snapshot!(hir_string("test"), @"
fn test@<compiled>:1:
bb1():