@@ -1600,6 +1600,10 @@ fn compute_jump_targets(iseq: *const rb_iseq_t) -> Vec<u32> {
16001600 let offset = get_arg ( pc, 0 ) . as_i64 ( ) ;
16011601 jump_targets. insert ( insn_idx_at_offset ( insn_idx, offset) ) ;
16021602 }
1603+ YARVINSN_opt_new => {
1604+ let offset = get_arg ( pc, 1 ) . as_i64 ( ) ;
1605+ jump_targets. insert ( insn_idx_at_offset ( insn_idx, offset) ) ;
1606+ }
16031607 YARVINSN_leave | YARVINSN_opt_invokebuiltin_delegate_leave => {
16041608 if insn_idx < iseq_size {
16051609 jump_targets. insert ( insn_idx) ;
@@ -1800,6 +1804,17 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
18001804 } ) ;
18011805 queue. push_back ( ( state. clone ( ) , target, target_idx) ) ;
18021806 }
1807+ YARVINSN_opt_new => {
1808+ let offset = get_arg ( pc, 1 ) . as_i64 ( ) ;
1809+ // TODO(max): Check interrupts
1810+ let target_idx = insn_idx_at_offset ( insn_idx, offset) ;
1811+ let target = insn_idx_to_block[ & target_idx] ;
1812+ // Skip the fast-path and go straight to the fallback code. We will let the
1813+ // optimizer take care of the converting Class#new->alloc+initialize instead.
1814+ fun. push_insn ( block, Insn :: Jump ( BranchEdge { target, args : state. as_args ( ) } ) ) ;
1815+ queue. push_back ( ( state. clone ( ) , target, target_idx) ) ;
1816+ break ; // Don't enqueue the next block as a successor
1817+ }
18031818 YARVINSN_jump => {
18041819 let offset = get_arg ( pc, 0 ) . as_i64 ( ) ;
18051820 // TODO(max): Check interrupts
@@ -2796,6 +2811,26 @@ mod tests {
27962811 " ) ;
27972812 assert_compile_fails ( "test" , ParseError :: UnknownOpcode ( "sendforward" . into ( ) ) )
27982813 }
2814+
2815+ #[ test]
2816+ fn test_opt_new ( ) {
2817+ eval ( "
2818+ class C; end
2819+ def test = C.new
2820+ " ) ;
2821+ assert_method_hir ( "test" , expect ! [ [ r#"
2822+ fn test:
2823+ bb0():
2824+ v1:BasicObject = GetConstantPath 0x1000
2825+ v2:NilClassExact = Const Value(nil)
2826+ Jump bb1(v2, v1)
2827+ bb1(v4:NilClassExact, v5:BasicObject):
2828+ v8:BasicObject = SendWithoutBlock v5, :new
2829+ Jump bb2(v8, v4)
2830+ bb2(v10:BasicObject, v11:NilClassExact):
2831+ Return v10
2832+ "# ] ] ) ;
2833+ }
27992834}
28002835
28012836#[ cfg( test) ]
@@ -3688,4 +3723,55 @@ mod opt_tests {
36883723 Return v5
36893724 "# ] ] ) ;
36903725 }
3726+
3727+ #[ test]
3728+ fn test_opt_new_no_initialize ( ) {
3729+ eval ( "
3730+ class C; end
3731+ def test = C.new
3732+ test
3733+ " ) ;
3734+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3735+ fn test:
3736+ bb0():
3737+ PatchPoint SingleRactorMode
3738+ PatchPoint StableConstantNames(0x1000, C)
3739+ v16:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3740+ v2:NilClassExact = Const Value(nil)
3741+ Jump bb1(v2, v16)
3742+ bb1(v4:NilClassExact, v5:BasicObject[VALUE(0x1008)]):
3743+ v8:BasicObject = SendWithoutBlock v5, :new
3744+ Jump bb2(v8, v4)
3745+ bb2(v10:BasicObject, v11:NilClassExact):
3746+ Return v10
3747+ "# ] ] ) ;
3748+ }
3749+
3750+ #[ test]
3751+ fn test_opt_new_initialize ( ) {
3752+ eval ( "
3753+ class C
3754+ def initialize x
3755+ @x = x
3756+ end
3757+ end
3758+ def test = C.new 1
3759+ test
3760+ " ) ;
3761+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3762+ fn test:
3763+ bb0():
3764+ PatchPoint SingleRactorMode
3765+ PatchPoint StableConstantNames(0x1000, C)
3766+ v18:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3767+ v2:NilClassExact = Const Value(nil)
3768+ v3:Fixnum[1] = Const Value(1)
3769+ Jump bb1(v2, v18, v3)
3770+ bb1(v5:NilClassExact, v6:BasicObject[VALUE(0x1008)], v7:Fixnum[1]):
3771+ v10:BasicObject = SendWithoutBlock v6, :new, v7
3772+ Jump bb2(v10, v5)
3773+ bb2(v12:BasicObject, v13:NilClassExact):
3774+ Return v12
3775+ "# ] ] ) ;
3776+ }
36913777}
0 commit comments