diff options
author | Jean Boussier <byroot@ruby-lang.org> | 2024-04-10 10:50:18 +0200 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2024-04-11 09:04:31 +0200 |
commit | 1b830740ba8371c4bcfdfc6eb2cb7e0ae81a84e0 (patch) | |
tree | 7f4b1c983035adaaa52bf966e54f1f4738098d4c | |
parent | ed303cd56cfc7889ce371ee390e9fd36f86814ea (diff) | |
download | ruby-1b830740ba8371c4bcfdfc6eb2cb7e0ae81a84e0.tar.gz |
compile.c: use rb_enc_interned_str to reduce allocations
The `rb_fstring(rb_enc_str_new())` pattern is inneficient because:
- It passes a mutable string to `rb_fstring` so if it has to be interned
it will first be duped.
- It an equivalent interned string already exists, we allocated the string
for nothing.
With `rb_enc_interned_str` we either directly get the pre-existing string
with 0 allocations, or efficiently directly intern the one we create
without first duping it.
-rw-r--r-- | compile.c | 32 | ||||
-rw-r--r-- | internal/ruby_parser.h | 1 | ||||
-rw-r--r-- | parse.y | 2 | ||||
-rw-r--r-- | ruby_parser.c | 8 | ||||
-rw-r--r-- | test/ruby/test_shapes.rb | 2 |
5 files changed, 24 insertions, 21 deletions
@@ -4338,7 +4338,7 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons while (list) { const NODE *const head = list->nd_head; if (nd_type_p(head, NODE_STR)) { - lit = rb_fstring(rb_node_str_string_val(head)); + lit = rb_node_str_string_val(head); ADD_INSN1(ret, head, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); lit = Qnil; @@ -4377,7 +4377,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_fstring(rb_node_dstr_string_val(node)); + VALUE lit = rb_node_dstr_string_val(node); ADD_INSN1(ret, node, putstring, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); } @@ -4765,14 +4765,13 @@ static_literal_value(const NODE *node, rb_iseq_t *iseq) case NODE_FILE: case NODE_STR: if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) { - VALUE lit; VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node))); - lit = rb_str_dup(get_string_value(node)); + VALUE lit = rb_str_dup(get_string_value(node)); rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info)); return rb_str_freeze(lit); } else { - return rb_fstring(get_string_value(node)); + return get_string_value(node); } default: rb_bug("unexpected node: %s", ruby_node_name(nd_type(node))); @@ -5142,9 +5141,9 @@ rb_node_case_when_optimizable_literal(const NODE *const node) case NODE_LINE: return rb_node_line_lineno_val(node); case NODE_STR: - return rb_fstring(rb_node_str_string_val(node)); + return rb_node_str_string_val(node); case NODE_FILE: - return rb_fstring(rb_node_file_path_val(node)); + return rb_node_file_path_val(node); } return Qundef; } @@ -5166,7 +5165,7 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals, if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) { debugp_param("nd_lit", get_string_value(val)); - lit = rb_fstring(get_string_value(val)); + lit = get_string_value(val); ADD_INSN1(cond_seq, val, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); } @@ -8445,7 +8444,7 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE get_nd_args(node) == NULL && ISEQ_COMPILE_DATA(iseq)->current_block == NULL && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) { - VALUE str = rb_fstring(get_string_value(get_nd_recv(node))); + VALUE str = get_string_value(get_nd_recv(node)); if (get_node_call_nd_mid(node) == idUMinus) { ADD_INSN2(ret, line_node, opt_str_uminus, str, new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE)); @@ -8469,7 +8468,7 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE ISEQ_COMPILE_DATA(iseq)->current_block == NULL && !frozen_string_literal_p(iseq) && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) { - VALUE str = rb_fstring(get_string_value(RNODE_LIST(get_nd_args(node))->nd_head)); + VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head); CHECK(COMPILE(ret, "recv", get_nd_recv(node))); ADD_INSN2(ret, line_node, opt_aref_with, str, new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE)); @@ -9746,7 +9745,7 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node !frozen_string_literal_p(iseq) && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) { - VALUE str = rb_fstring(get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)); + VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head); CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv)); CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head)); if (!popped) { @@ -9971,7 +9970,7 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa return COMPILE_OK; case NODE_STR:{ - VALUE lit = rb_fstring(rb_node_str_string_val(node)); + VALUE lit = rb_node_str_string_val(node); ADD_INSN1(ret, node, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); *value_p = lit; @@ -9981,7 +9980,7 @@ compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_pa } case NODE_FILE:{ - VALUE lit = rb_fstring(rb_node_file_path_val(node)); + VALUE lit = rb_node_file_path_val(node); ADD_INSN1(ret, node, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); *value_p = lit; @@ -10576,12 +10575,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no VALUE lit = get_string_value(node); 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); break; @@ -10592,9 +10589,6 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info)); lit = rb_str_freeze(lit); } - else { - lit = rb_fstring(lit); - } ADD_INSN1(ret, node, putobject, lit); RB_OBJ_WRITTEN(iseq, Qundef, lit); break; @@ -10614,7 +10608,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } case NODE_XSTR:{ ADD_CALL_RECEIVER(ret, node); - VALUE str = rb_fstring(rb_node_str_string_val(node)); + VALUE str = rb_node_str_string_val(node); ADD_INSN1(ret, node, putobject, str); RB_OBJ_WRITTEN(iseq, Qundef, str); ADD_CALL(ret, node, idBackquote, INT2FIX(1)); diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h index 7dc6a46d4f..0a00075211 100644 --- a/internal/ruby_parser.h +++ b/internal/ruby_parser.h @@ -19,6 +19,7 @@ VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int); VALUE rb_parser_new(void); rb_ast_t *rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line); VALUE rb_str_new_parser_string(rb_parser_string_t *str); +VALUE rb_str_new_mutable_parser_string(rb_parser_string_t *str); VALUE rb_node_str_string_val(const NODE *); VALUE rb_node_sym_string_val(const NODE *); @@ -7959,7 +7959,7 @@ nextline(struct parser_params *p, int set_encoding) } #ifndef RIPPER if (p->debug_lines) { - VALUE v = rb_str_new_parser_string(str); + VALUE v = rb_str_new_mutable_parser_string(str); if (set_encoding) rb_enc_associate(v, p->enc); rb_ary_push(p->debug_lines, v); } diff --git a/ruby_parser.c b/ruby_parser.c index 12bfb18b1a..40c469f14b 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -742,6 +742,14 @@ rb_parser_set_yydebug(VALUE vparser, VALUE flag) VALUE rb_str_new_parser_string(rb_parser_string_t *str) { + VALUE string = rb_enc_interned_str(str->ptr, str->len, str->enc); + rb_enc_str_coderange(string); + return string; +} + +VALUE +rb_str_new_mutable_parser_string(rb_parser_string_t *str) +{ return rb_enc_str_new(str->ptr, str->len, str->enc); } diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb index bbea03344e..9b02504384 100644 --- a/test/ruby/test_shapes.rb +++ b/test/ruby/test_shapes.rb @@ -1006,7 +1006,7 @@ class TestShapes < Test::Unit::TestCase end def test_freezing_and_cloning_string - str = "str".freeze + str = ("str" + "str").freeze str2 = str.clone(freeze: true) assert_predicate(str2, :frozen?) assert_shape_equal(RubyVM::Shape.of(str), RubyVM::Shape.of(str2)) |