@@ -338,8 +338,10 @@ pub enum Insn {
338338 GetConstantPath { ic : * const iseq_inline_constant_cache } ,
339339
340340 //NewObject?
341- //SetIvar {},
342- //GetIvar {},
341+ /// Get an instance variable `id` from `self_val`
342+ GetIvar { self_val : InsnId , id : ID , state : InsnId } ,
343+ /// Set `self_val`'s instance variable `id` to `val`
344+ SetIvar { self_val : InsnId , id : ID , val : InsnId , state : InsnId } ,
343345
344346 /// Own a FrameState so that instructions can look up their dominating FrameState when
345347 /// generating deopt side-exits and frame reconstruction metadata. Does not directly generate
@@ -395,7 +397,7 @@ impl Insn {
395397 match self {
396398 Insn :: ArraySet { .. } | Insn :: Snapshot { .. } | Insn :: Jump ( _)
397399 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. }
398- | Insn :: PatchPoint { .. } => false ,
400+ | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } => false ,
399401 _ => true ,
400402 }
401403 }
@@ -526,6 +528,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
526528 Ok ( ( ) )
527529 } ,
528530 Insn :: Snapshot { state } => write ! ( f, "Snapshot {}" , state) ,
531+ Insn :: GetIvar { self_val, id, .. } => write ! ( f, "GetIvar {self_val}, :{}" , id. contents_lossy( ) . into_owned( ) ) ,
532+ Insn :: SetIvar { self_val, id, val, .. } => write ! ( f, "SetIvar {self_val}, :{}, {val}" , id. contents_lossy( ) . into_owned( ) ) ,
529533 insn => { write ! ( f, "{insn:?}" ) }
530534 }
531535 }
@@ -866,6 +870,8 @@ impl Function {
866870 Defined { .. } => todo ! ( "find(Defined)" ) ,
867871 NewArray { elements, state } => NewArray { elements : find_vec ! ( * elements) , state : find ! ( * state) } ,
868872 ArrayMax { elements, state } => ArrayMax { elements : find_vec ! ( * elements) , state : find ! ( * state) } ,
873+ & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
874+ & SetIvar { self_val, id, val, state } => SetIvar { self_val : find ! ( self_val) , id, val, state } ,
869875 }
870876 }
871877
@@ -891,7 +897,7 @@ impl Function {
891897 Insn :: Param { .. } => unimplemented ! ( "params should not be present in block.insns" ) ,
892898 Insn :: ArraySet { .. } | Insn :: Snapshot { .. } | Insn :: Jump ( _)
893899 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. }
894- | Insn :: PatchPoint { .. } =>
900+ | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } =>
895901 panic ! ( "Cannot infer type of instruction with no output" ) ,
896902 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
897903 Insn :: Const { val : Const :: CBool ( val) } => Type :: from_cbool ( * val) ,
@@ -933,6 +939,7 @@ impl Function {
933939 Insn :: Defined { .. } => types:: BasicObject ,
934940 Insn :: GetConstantPath { .. } => types:: BasicObject ,
935941 Insn :: ArrayMax { .. } => types:: BasicObject ,
942+ Insn :: GetIvar { .. } => types:: BasicObject ,
936943 }
937944 }
938945
@@ -1439,6 +1446,15 @@ impl Function {
14391446 worklist. push_back ( state) ;
14401447 }
14411448 Insn :: CCall { args, .. } => worklist. extend ( args) ,
1449+ Insn :: GetIvar { self_val, state, .. } => {
1450+ worklist. push_back ( self_val) ;
1451+ worklist. push_back ( state) ;
1452+ }
1453+ Insn :: SetIvar { self_val, val, state, .. } => {
1454+ worklist. push_back ( self_val) ;
1455+ worklist. push_back ( val) ;
1456+ worklist. push_back ( state) ;
1457+ }
14421458 }
14431459 }
14441460 // Now remove all unnecessary instructions
@@ -2096,6 +2112,22 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
20962112 let send = fun. push_insn ( block, Insn :: Send { self_val : recv, call_info : CallInfo { method_name } , cd, blockiseq, args, state : exit_id } ) ;
20972113 state. stack_push ( send) ;
20982114 }
2115+ YARVINSN_getinstancevariable => {
2116+ let id = ID ( get_arg ( pc, 0 ) . as_u64 ( ) ) ;
2117+ // ic is in arg 1
2118+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
2119+ let self_val = fun. push_insn ( block, Insn :: PutSelf ) ;
2120+ let result = fun. push_insn ( block, Insn :: GetIvar { self_val, id, state : exit_id } ) ;
2121+ state. stack_push ( result) ;
2122+ }
2123+ YARVINSN_setinstancevariable => {
2124+ let id = ID ( get_arg ( pc, 0 ) . as_u64 ( ) ) ;
2125+ // ic is in arg 1
2126+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
2127+ let self_val = fun. push_insn ( block, Insn :: PutSelf ) ;
2128+ let val = state. stack_pop ( ) ?;
2129+ fun. push_insn ( block, Insn :: SetIvar { self_val, id, val, state : exit_id } ) ;
2130+ }
20992131 _ => return Err ( ParseError :: UnknownOpcode ( insn_name ( opcode as usize ) ) ) ,
21002132 }
21012133
@@ -3042,6 +3074,37 @@ mod tests {
30423074 Return v6
30433075 "# ] ] ) ;
30443076 }
3077+
3078+ #[ test]
3079+ fn test_getinstancevariable ( ) {
3080+ eval ( "
3081+ def test = @foo
3082+ test
3083+ " ) ;
3084+ assert_method_hir ( "test" , expect ! [ [ r#"
3085+ fn test:
3086+ bb0():
3087+ v2:BasicObject = PutSelf
3088+ v3:BasicObject = GetIvar v2, :@foo
3089+ Return v3
3090+ "# ] ] ) ;
3091+ }
3092+
3093+ #[ test]
3094+ fn test_setinstancevariable ( ) {
3095+ eval ( "
3096+ def test = @foo = 1
3097+ test
3098+ " ) ;
3099+ assert_method_hir ( "test" , expect ! [ [ r#"
3100+ fn test:
3101+ bb0():
3102+ v1:Fixnum[1] = Const Value(1)
3103+ v3:BasicObject = PutSelf
3104+ SetIvar v3, :@foo, v1
3105+ Return v1
3106+ "# ] ] ) ;
3107+ }
30453108}
30463109
30473110#[ cfg( test) ]
@@ -4097,4 +4160,33 @@ mod opt_tests {
40974160 Return v6
40984161 "# ] ] ) ;
40994162 }
4163+
4164+ #[ test]
4165+ fn test_getinstancevariable ( ) {
4166+ eval ( "
4167+ def test = @foo
4168+ " ) ;
4169+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
4170+ fn test:
4171+ bb0():
4172+ v2:BasicObject = PutSelf
4173+ v3:BasicObject = GetIvar v2, :@foo
4174+ Return v3
4175+ "# ] ] ) ;
4176+ }
4177+
4178+ #[ test]
4179+ fn test_setinstancevariable ( ) {
4180+ eval ( "
4181+ def test = @foo = 1
4182+ " ) ;
4183+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
4184+ fn test:
4185+ bb0():
4186+ v1:Fixnum[1] = Const Value(1)
4187+ v3:BasicObject = PutSelf
4188+ SetIvar v3, :@foo, v1
4189+ Return v1
4190+ "# ] ] ) ;
4191+ }
41004192}
0 commit comments