From f186f2cb70a2fe3c5a663a0a398b294347eee344 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Wed, 23 Jul 2025 10:15:51 -0400 Subject: [PATCH 1/4] Remove unused imemo_parser_strterm --- debug_counter.h | 1 - ext/objspace/objspace.c | 1 - imemo.c | 9 --------- internal/imemo.h | 9 ++++----- yjit/src/cruby_bindings.inc.rs | 9 ++++----- zjit/src/cruby_bindings.inc.rs | 9 ++++----- 6 files changed, 12 insertions(+), 26 deletions(-) diff --git a/debug_counter.h b/debug_counter.h index fada7513aa7b10..9f0649e0ac8e33 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -311,7 +311,6 @@ RB_DEBUG_COUNTER(obj_imemo_svar) RB_DEBUG_COUNTER(obj_imemo_throw_data) RB_DEBUG_COUNTER(obj_imemo_ifunc) RB_DEBUG_COUNTER(obj_imemo_memo) -RB_DEBUG_COUNTER(obj_imemo_parser_strterm) RB_DEBUG_COUNTER(obj_imemo_callinfo) RB_DEBUG_COUNTER(obj_imemo_callcache) RB_DEBUG_COUNTER(obj_imemo_constcache) diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index a61b1acbb4e341..8476c9b74752d1 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -501,7 +501,6 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self) INIT_IMEMO_TYPE_ID(imemo_iseq); INIT_IMEMO_TYPE_ID(imemo_tmpbuf); INIT_IMEMO_TYPE_ID(imemo_ast); - INIT_IMEMO_TYPE_ID(imemo_parser_strterm); INIT_IMEMO_TYPE_ID(imemo_callinfo); INIT_IMEMO_TYPE_ID(imemo_callcache); INIT_IMEMO_TYPE_ID(imemo_constcache); diff --git a/imemo.c b/imemo.c index 7ab867e647bb9b..5f24e0230129db 100644 --- a/imemo.c +++ b/imemo.c @@ -26,7 +26,6 @@ rb_imemo_name(enum imemo_type type) IMEMO_NAME(iseq); IMEMO_NAME(memo); IMEMO_NAME(ment); - IMEMO_NAME(parser_strterm); IMEMO_NAME(svar); IMEMO_NAME(throw_data); IMEMO_NAME(tmpbuf); @@ -248,8 +247,6 @@ rb_imemo_memsize(VALUE obj) case imemo_ment: size += sizeof(((rb_method_entry_t *)obj)->def); - break; - case imemo_parser_strterm: break; case imemo_svar: break; @@ -460,8 +457,6 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating) case imemo_ment: mark_and_move_method_entry((rb_method_entry_t *)obj, reference_updating); break; - case imemo_parser_strterm: - break; case imemo_svar: { struct vm_svar *svar = (struct vm_svar *)obj; @@ -657,10 +652,6 @@ rb_imemo_free(VALUE obj) rb_free_method_entry((rb_method_entry_t *)obj); RB_DEBUG_COUNTER_INC(obj_imemo_ment); - break; - case imemo_parser_strterm: - RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm); - break; case imemo_svar: RB_DEBUG_COUNTER_INC(obj_imemo_svar); diff --git a/internal/imemo.h b/internal/imemo.h index a7e01f31e19c18..dcea997ae803a7 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -38,11 +38,10 @@ enum imemo_type { imemo_iseq = 7, imemo_tmpbuf = 8, imemo_ast = 9, // Obsolete due to the universal parser - imemo_parser_strterm = 10, - imemo_callinfo = 11, - imemo_callcache = 12, - imemo_constcache = 13, - imemo_fields = 14, + imemo_callinfo = 10, + imemo_callcache = 11, + imemo_constcache = 12, + imemo_fields = 13, }; /* CREF (Class REFerence) is defined in method.h */ diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 9b871c9e7c88ed..666f5c4f28d614 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -406,11 +406,10 @@ pub const imemo_ment: imemo_type = 6; pub const imemo_iseq: imemo_type = 7; pub const imemo_tmpbuf: imemo_type = 8; pub const imemo_ast: imemo_type = 9; -pub const imemo_parser_strterm: imemo_type = 10; -pub const imemo_callinfo: imemo_type = 11; -pub const imemo_callcache: imemo_type = 12; -pub const imemo_constcache: imemo_type = 13; -pub const imemo_fields: imemo_type = 14; +pub const imemo_callinfo: imemo_type = 10; +pub const imemo_callcache: imemo_type = 11; +pub const imemo_constcache: imemo_type = 12; +pub const imemo_fields: imemo_type = 13; pub type imemo_type = u32; #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 9c860ab5092d6f..492de3a5dfae3a 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -223,11 +223,10 @@ pub const imemo_ment: imemo_type = 6; pub const imemo_iseq: imemo_type = 7; pub const imemo_tmpbuf: imemo_type = 8; pub const imemo_ast: imemo_type = 9; -pub const imemo_parser_strterm: imemo_type = 10; -pub const imemo_callinfo: imemo_type = 11; -pub const imemo_callcache: imemo_type = 12; -pub const imemo_constcache: imemo_type = 13; -pub const imemo_fields: imemo_type = 14; +pub const imemo_callinfo: imemo_type = 10; +pub const imemo_callcache: imemo_type = 11; +pub const imemo_constcache: imemo_type = 12; +pub const imemo_fields: imemo_type = 13; pub type imemo_type = u32; pub const METHOD_VISI_UNDEF: rb_method_visibility_t = 0; pub const METHOD_VISI_PUBLIC: rb_method_visibility_t = 1; From fd492a45eb747f49d1f35c09332b654ada0280dc Mon Sep 17 00:00:00 2001 From: S-H-GAMELINKS Date: Thu, 24 Jul 2025 21:59:44 +0900 Subject: [PATCH 2/4] Add DEFINED NODE locations Add keyword_defined locations to struct RNode_DEFINED --- ast.c | 4 ++++ node_dump.c | 3 ++- parse.y | 19 ++++++++++--------- rubyparser.h | 1 + test/ruby/test_ast.rb | 5 +++++ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/ast.c b/ast.c index dde42e5921f3d5..8b7ed10307060c 100644 --- a/ast.c +++ b/ast.c @@ -948,6 +948,10 @@ node_locations(VALUE ast_value, const NODE *node) location_new(&RNODE_YIELD(node)->keyword_loc), location_new(&RNODE_YIELD(node)->lparen_loc), location_new(&RNODE_YIELD(node)->rparen_loc)); + case NODE_DEFINED: + return rb_ary_new_from_args(2, + location_new(nd_code_loc(node)), + location_new(&RNODE_DEFINED(node)->keyword_loc)); case NODE_ARGS_AUX: case NODE_LAST: break; diff --git a/node_dump.c b/node_dump.c index ff5cc268ecd5f5..9822ae5fc25a3a 100644 --- a/node_dump.c +++ b/node_dump.c @@ -1105,8 +1105,9 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) ANN("defined? expression"); ANN("format: defined?([nd_head])"); ANN("example: defined?(foo)"); - LAST_NODE; F_NODE(nd_head, RNODE_DEFINED, "expr"); + LAST_NODE; + F_LOC(keyword_loc, RNODE_DEFINED); return; case NODE_POSTEXE: diff --git a/parse.y b/parse.y index 7b36caf78d1a81..dbe21332b4dd83 100644 --- a/parse.y +++ b/parse.y @@ -1156,7 +1156,7 @@ static rb_node_nil_t *rb_node_nil_new(struct parser_params *p, const YYLTYPE *lo static rb_node_true_t *rb_node_true_new(struct parser_params *p, const YYLTYPE *loc); static rb_node_false_t *rb_node_false_new(struct parser_params *p, const YYLTYPE *loc); static rb_node_errinfo_t *rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc); -static rb_node_defined_t *rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc); +static rb_node_defined_t *rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc); static rb_node_postexe_t *rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc); static rb_node_sym_t *rb_node_sym_new(struct parser_params *p, VALUE str, const YYLTYPE *loc); static rb_node_dsym_t *rb_node_dsym_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc); @@ -1264,7 +1264,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE #define NEW_TRUE(loc) (NODE *)rb_node_true_new(p,loc) #define NEW_FALSE(loc) (NODE *)rb_node_false_new(p,loc) #define NEW_ERRINFO(loc) (NODE *)rb_node_errinfo_new(p,loc) -#define NEW_DEFINED(e,loc) (NODE *)rb_node_defined_new(p,e,loc) +#define NEW_DEFINED(e,loc,k_loc) (NODE *)rb_node_defined_new(p,e,loc, k_loc) #define NEW_POSTEXE(b,loc,k_loc,o_loc,c_loc) (NODE *)rb_node_postexe_new(p,b,loc,k_loc,o_loc,c_loc) #define NEW_SYM(str,loc) (NODE *)rb_node_sym_new(p,str,loc) #define NEW_DSYM(s,l,n,loc) (NODE *)rb_node_dsym_new(p,s,l,n,loc) @@ -1470,7 +1470,7 @@ static rb_node_kw_arg_t *kwd_append(rb_node_kw_arg_t*, rb_node_kw_arg_t*); static NODE *new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc); static NODE *new_unique_key_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc); -static NODE *new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc); +static NODE *new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc, const YYLTYPE *keyword_loc); static NODE *new_regexp(struct parser_params *, NODE *, int, const YYLTYPE *, const YYLTYPE *, const YYLTYPE *, const YYLTYPE *); @@ -4041,7 +4041,7 @@ arg : asgn(arg_rhs) | keyword_defined '\n'? begin_defined arg { p->ctxt.in_defined = $3.in_defined; - $$ = new_defined(p, $4, &@$); + $$ = new_defined(p, $4, &@$, &@1); p->ctxt.has_trailing_semicolon = $3.has_trailing_semicolon; /*% ripper: defined!($:4) %*/ } @@ -4429,7 +4429,7 @@ primary : inline_primary | keyword_defined '\n'? '(' begin_defined expr rparen { p->ctxt.in_defined = $4.in_defined; - $$ = new_defined(p, $5, &@$); + $$ = new_defined(p, $5, &@$, &@1); p->ctxt.has_trailing_semicolon = $4.has_trailing_semicolon; /*% ripper: defined!($:5) %*/ } @@ -12240,10 +12240,11 @@ rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc) } static rb_node_defined_t * -rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc) +rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc) { rb_node_defined_t *n = NODE_NEWNODE(NODE_DEFINED, rb_node_defined_t, loc); n->nd_head = nd_head; + n->keyword_loc = *keyword_loc; return n; } @@ -13021,7 +13022,7 @@ kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw) } static NODE * -new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc) +new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc, const YYLTYPE *keyword_loc) { int had_trailing_semicolon = p->ctxt.has_trailing_semicolon; p->ctxt.has_trailing_semicolon = 0; @@ -13041,10 +13042,10 @@ new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc) if (had_trailing_semicolon && !nd_type_p(expr, NODE_BLOCK)) { NODE *block = NEW_BLOCK(expr, loc); - return NEW_DEFINED(block, loc); + return NEW_DEFINED(block, loc, keyword_loc); } - return NEW_DEFINED(n, loc); + return NEW_DEFINED(n, loc, keyword_loc); } static NODE* diff --git a/rubyparser.h b/rubyparser.h index c63929abb299a5..9fd6906ca60c08 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -962,6 +962,7 @@ typedef struct RNode_DEFINED { NODE node; struct RNode *nd_head; + rb_code_location_t keyword_loc; } rb_node_defined_t; typedef struct RNode_POSTEXE { diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index d22823470b41f5..d716fde519bfd8 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1655,6 +1655,11 @@ def test_yield_locations assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 20], [1, 9, 1, 14], [1, 14, 1, 15], [1, 19, 1, 20]]) end + def test_defined_locations + node = ast_parse("defined? x") + assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 0, 1, 8]]) + end + private def ast_parse(src, **options) begin From 5ef20b3a274e855b802edd03cd432464d2a49b35 Mon Sep 17 00:00:00 2001 From: Kunshan Wang Date: Sat, 19 Jul 2025 16:22:46 +0800 Subject: [PATCH 3/4] YJIT: Use raw memory write to update pointers in code Because we have set all code memory to writable before the reference updating phase, we can use raw memory writes directly. --- yjit/src/core.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 57756e86ced5f3..d42726bcc77691 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -2091,11 +2091,9 @@ pub extern "C" fn rb_yjit_iseq_update_references(iseq: IseqPtr) { // Only write when the VALUE moves, to be copy-on-write friendly. if new_addr != object { - for (byte_idx, &byte) in new_addr.as_u64().to_le_bytes().iter().enumerate() { - let byte_code_ptr = value_code_ptr.add_bytes(byte_idx); - cb.write_mem(byte_code_ptr, byte) - .expect("patching existing code should be within bounds"); - } + // SAFETY: Since we already set code memory writable before the compacting phase, + // we can use raw memory accesses directly. + unsafe { value_ptr.write_unaligned(new_addr); } } } } From b2838bef693db39960ca5e326e61408b4721b7bb Mon Sep 17 00:00:00 2001 From: ydah Date: Thu, 24 Jul 2025 23:39:39 +0900 Subject: [PATCH 4/4] Add NODE_DEFINED tests for cases with parentheses to test_ast.rb --- ast.c | 8 ++++---- test/ruby/test_ast.rb | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ast.c b/ast.c index 8b7ed10307060c..04f2d1384c5edc 100644 --- a/ast.c +++ b/ast.c @@ -822,6 +822,10 @@ node_locations(VALUE ast_value, const NODE *node) location_new(nd_code_loc(node)), location_new(&RNODE_COLON3(node)->delimiter_loc), location_new(&RNODE_COLON3(node)->name_loc)); + case NODE_DEFINED: + return rb_ary_new_from_args(2, + location_new(nd_code_loc(node)), + location_new(&RNODE_DEFINED(node)->keyword_loc)); case NODE_DOT2: return rb_ary_new_from_args(2, location_new(nd_code_loc(node)), @@ -948,10 +952,6 @@ node_locations(VALUE ast_value, const NODE *node) location_new(&RNODE_YIELD(node)->keyword_loc), location_new(&RNODE_YIELD(node)->lparen_loc), location_new(&RNODE_YIELD(node)->rparen_loc)); - case NODE_DEFINED: - return rb_ary_new_from_args(2, - location_new(nd_code_loc(node)), - location_new(&RNODE_DEFINED(node)->keyword_loc)); case NODE_ARGS_AUX: case NODE_LAST: break; diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index d716fde519bfd8..5524fa7146e035 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1415,6 +1415,14 @@ def test_colon3_locations assert_locations(node.children[-1].children[0].locations, [[1, 0, 1, 3], [1, 0, 1, 2], [1, 2, 1, 3]]) end + def test_defined_locations + node = ast_parse("defined? x") + assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 0, 1, 8]]) + + node = ast_parse("defined?(x)") + assert_locations(node.children[-1].locations, [[1, 0, 1, 11], [1, 0, 1, 8]]) + end + def test_dot2_locations node = ast_parse("1..2") assert_locations(node.children[-1].locations, [[1, 0, 1, 4], [1, 1, 1, 3]]) @@ -1655,11 +1663,6 @@ def test_yield_locations assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 20], [1, 9, 1, 14], [1, 14, 1, 15], [1, 19, 1, 20]]) end - def test_defined_locations - node = ast_parse("defined? x") - assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 0, 1, 8]]) - end - private def ast_parse(src, **options) begin