@@ -1292,39 +1292,63 @@ fn gen_newrange(
12921292}
12931293
12941294fn guard_object_is_heap (
1295+ ctx : & mut Context ,
12951296 asm : & mut Assembler ,
1296- object_opnd : Opnd ,
1297+ object : Opnd ,
1298+ object_opnd : YARVOpnd ,
12971299 side_exit : Target ,
12981300) {
1301+ let object_type = ctx. get_opnd_type ( object_opnd) ;
1302+ if object_type. is_heap ( ) {
1303+ return ;
1304+ }
1305+
12991306 asm. comment ( "guard object is heap" ) ;
13001307
13011308 // Test that the object is not an immediate
1302- asm. test ( object_opnd , ( RUBY_IMMEDIATE_MASK as u64 ) . into ( ) ) ;
1309+ asm. test ( object , ( RUBY_IMMEDIATE_MASK as u64 ) . into ( ) ) ;
13031310 asm. jnz ( side_exit) ;
13041311
13051312 // Test that the object is not false
1306- asm. cmp ( object_opnd , Qfalse . into ( ) ) ;
1313+ asm. cmp ( object , Qfalse . into ( ) ) ;
13071314 asm. je ( side_exit) ;
1315+
1316+ if object_type. diff ( Type :: UnknownHeap ) != usize:: MAX {
1317+ ctx. upgrade_opnd_type ( object_opnd, Type :: UnknownHeap ) ;
1318+ }
13081319}
13091320
13101321fn guard_object_is_array (
1322+ ctx : & mut Context ,
13111323 asm : & mut Assembler ,
1312- object_opnd : Opnd ,
1324+ object : Opnd ,
1325+ object_opnd : YARVOpnd ,
13131326 side_exit : Target ,
13141327) {
1328+ let object_type = ctx. get_opnd_type ( object_opnd) ;
1329+ if object_type. is_array ( ) {
1330+ return ;
1331+ }
1332+
1333+ let object_reg = match object {
1334+ Opnd :: Reg ( _) => object,
1335+ _ => asm. load ( object) ,
1336+ } ;
1337+ guard_object_is_heap ( ctx, asm, object_reg, object_opnd, side_exit) ;
1338+
13151339 asm. comment ( "guard object is array" ) ;
13161340
13171341 // Pull out the type mask
1318- let object_reg = match object_opnd {
1319- Opnd :: Reg ( _) => object_opnd,
1320- _ => asm. load ( object_opnd) ,
1321- } ;
13221342 let flags_opnd = Opnd :: mem ( VALUE_BITS , object_reg, RUBY_OFFSET_RBASIC_FLAGS ) ;
13231343 let flags_opnd = asm. and ( flags_opnd, ( RUBY_T_MASK as u64 ) . into ( ) ) ;
13241344
13251345 // Compare the result with T_ARRAY
13261346 asm. cmp ( flags_opnd, ( RUBY_T_ARRAY as u64 ) . into ( ) ) ;
13271347 asm. jne ( side_exit) ;
1348+
1349+ if object_type. diff ( Type :: TArray ) != usize:: MAX {
1350+ ctx. upgrade_opnd_type ( object_opnd, Type :: TArray ) ;
1351+ }
13281352}
13291353
13301354/// This guards that a special flag is not set on a hash.
@@ -1402,12 +1426,12 @@ fn gen_expandarray(
14021426
14031427 let side_exit = get_side_exit ( jit, ocb, ctx) ;
14041428
1405- let array_type = ctx. get_opnd_type ( StackOpnd ( 0 ) ) ;
1406- let array_opnd = ctx. stack_pop ( 1 ) ;
1429+ let array_opnd = ctx. stack_opnd ( 0 ) ;
14071430
14081431 // num is the number of requested values. If there aren't enough in the
14091432 // array then we're going to push on nils.
1410- if matches ! ( array_type, Type :: Nil ) {
1433+ if ctx. get_opnd_type ( array_opnd. into ( ) ) == Type :: Nil {
1434+ ctx. stack_pop ( 1 ) ; // pop after using the type info
14111435 // special case for a, b = nil pattern
14121436 // push N nils onto the stack
14131437 for _ in 0 ..num {
@@ -1418,23 +1442,21 @@ fn gen_expandarray(
14181442 }
14191443
14201444 // Move the array from the stack and check that it's an array.
1421- let array_reg = asm. load ( array_opnd) ;
1422- guard_object_is_heap (
1423- asm,
1424- array_reg,
1425- counted_exit ! ( ocb, side_exit, expandarray_not_array) ,
1426- ) ;
14271445 guard_object_is_array (
1446+ ctx,
14281447 asm,
1429- array_reg,
1448+ array_opnd,
1449+ array_opnd. into ( ) ,
14301450 counted_exit ! ( ocb, side_exit, expandarray_not_array) ,
14311451 ) ;
1452+ let array_opnd = ctx. stack_pop ( 1 ) ; // pop after using the type info
14321453
14331454 // If we don't actually want any values, then just return.
14341455 if num == 0 {
14351456 return KeepCompiling ;
14361457 }
14371458
1459+ let array_reg = asm. load ( array_opnd) ;
14381460 let array_len_opnd = get_array_len ( asm, array_reg) ;
14391461
14401462 // Only handle the case where the number of values in the array is greater
@@ -1989,24 +2011,14 @@ fn gen_get_ivar(
19892011 }
19902012 } ;
19912013
1992- // must be before stack_pop
1993- let recv_type = ctx. get_opnd_type ( recv_opnd) ;
1994-
1995- // Upgrade type
1996- if !recv_type. is_heap ( ) {
1997- ctx. upgrade_opnd_type ( recv_opnd, Type :: UnknownHeap ) ;
1998- }
2014+ // Guard heap object (recv_opnd must be used before stack_oop)
2015+ guard_object_is_heap ( ctx, asm, recv, recv_opnd, side_exit) ;
19992016
20002017 // Pop receiver if it's on the temp stack
20012018 if recv_opnd != SelfOpnd {
20022019 ctx. stack_pop ( 1 ) ;
20032020 }
20042021
2005- // Guard heap object
2006- if !recv_type. is_heap ( ) {
2007- guard_object_is_heap ( asm, recv, side_exit) ;
2008- }
2009-
20102022 // Compile time self is embedded and the ivar index lands within the object
20112023 let embed_test_result = unsafe { FL_TEST_RAW ( comptime_receiver, VALUE ( ROBJECT_EMBED . as_usize ( ) ) ) != VALUE ( 0 ) } ;
20122024
@@ -2221,16 +2233,12 @@ fn gen_setinstancevariable(
22212233 let mut recv = asm. load ( Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_SELF ) ) ;
22222234
22232235 let recv_opnd = SelfOpnd ;
2224- let recv_type = ctx. get_opnd_type ( recv_opnd) ;
22252236
22262237 // Generate a side exit
22272238 let side_exit = get_side_exit ( jit, ocb, ctx) ;
22282239
22292240 // Upgrade type
2230- if !recv_type. is_heap ( ) { // Must be a heap type
2231- ctx. upgrade_opnd_type ( recv_opnd, Type :: UnknownHeap ) ;
2232- guard_object_is_heap ( asm, recv, side_exit) ;
2233- }
2241+ guard_object_is_heap ( ctx, asm, recv, recv_opnd, side_exit) ;
22342242
22352243 let expected_shape = unsafe { rb_shape_get_shape_id ( comptime_receiver) } ;
22362244 let shape_id_offset = unsafe { rb_shape_id_offset ( ) } ;
@@ -5106,20 +5114,16 @@ fn get_array_ptr(asm: &mut Assembler, array_reg: Opnd) -> Opnd {
51065114/// It optimistically compiles to a static size that is the exact number of arguments
51075115/// needed for the function.
51085116fn push_splat_args ( required_args : u32 , ctx : & mut Context , asm : & mut Assembler , ocb : & mut OutlinedCb , side_exit : Target ) {
5109-
51105117 asm. comment ( "push_splat_args" ) ;
51115118
51125119 let array_opnd = ctx. stack_opnd ( 0 ) ;
51135120 let array_reg = asm. load ( array_opnd) ;
51145121
5115- guard_object_is_heap (
5116- asm,
5117- array_reg,
5118- counted_exit ! ( ocb, side_exit, send_splat_not_array) ,
5119- ) ;
51205122 guard_object_is_array (
5123+ ctx,
51215124 asm,
51225125 array_reg,
5126+ array_opnd. into ( ) ,
51235127 counted_exit ! ( ocb, side_exit, send_splat_not_array) ,
51245128 ) ;
51255129
@@ -5791,16 +5795,10 @@ fn gen_send_iseq(
57915795 // Note that you can't have side exits after this arg0 splat.
57925796 if block_arg0_splat {
57935797 let arg0_opnd = ctx. stack_opnd ( 0 ) ;
5794- let arg0_type = ctx. get_opnd_type ( arg0_opnd. into ( ) ) ;
57955798
57965799 // Only handle the case that you don't need to_ary conversion
57975800 let not_array_exit = counted_exit ! ( ocb, side_exit, invokeblock_iseq_arg0_not_array) ;
5798- if !arg0_type. is_heap ( ) {
5799- guard_object_is_heap ( asm, arg0_opnd, not_array_exit) ;
5800- }
5801- if !arg0_type. is_array ( ) {
5802- guard_object_is_array ( asm, arg0_opnd, not_array_exit) ;
5803- }
5801+ guard_object_is_array ( ctx, asm, arg0_opnd, arg0_opnd. into ( ) , not_array_exit) ;
58045802
58055803 // Only handle the same that the array length == ISEQ's lead_num (most common)
58065804 let arg0_len_opnd = get_array_len ( asm, arg0_opnd) ;
0 commit comments