@@ -327,6 +327,8 @@ pub enum Insn {
327327 StringIntern { val : InsnId } ,
328328
329329 NewArray { elements : Vec < InsnId > , state : InsnId } ,
330+ /// NewHash contains a vec of (key, value) pairs
331+ NewHash { elements : Vec < ( InsnId , InsnId ) > , state : InsnId } ,
330332 ArraySet { array : InsnId , idx : usize , val : InsnId } ,
331333 ArrayDup { val : InsnId , state : InsnId } ,
332334 ArrayMax { elements : Vec < InsnId > , state : InsnId } ,
@@ -425,6 +427,7 @@ impl Insn {
425427 Insn :: Param { .. } => false ,
426428 Insn :: StringCopy { .. } => false ,
427429 Insn :: NewArray { .. } => false ,
430+ Insn :: NewHash { .. } => false ,
428431 Insn :: ArrayDup { .. } => false ,
429432 Insn :: HashDup { .. } => false ,
430433 Insn :: Test { .. } => false ,
@@ -467,6 +470,15 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
467470 }
468471 Ok ( ( ) )
469472 }
473+ Insn :: NewHash { elements, .. } => {
474+ write ! ( f, "NewHash" ) ?;
475+ let mut prefix = " " ;
476+ for ( key, value) in elements {
477+ write ! ( f, "{prefix}{key}: {value}" ) ?;
478+ prefix = ", " ;
479+ }
480+ Ok ( ( ) )
481+ }
470482 Insn :: ArrayMax { elements, .. } => {
471483 write ! ( f, "ArrayMax" ) ?;
472484 let mut prefix = " " ;
@@ -874,6 +886,13 @@ impl Function {
874886 & CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun : cfun, args : args. iter ( ) . map ( |arg| find ! ( * arg) ) . collect ( ) , name : name, return_type : return_type, elidable } ,
875887 Defined { .. } => todo ! ( "find(Defined)" ) ,
876888 NewArray { elements, state } => NewArray { elements : find_vec ! ( * elements) , state : find ! ( * state) } ,
889+ & NewHash { ref elements, state } => {
890+ let mut found_elements = vec ! [ ] ;
891+ for & ( key, value) in elements {
892+ found_elements. push ( ( find ! ( key) , find ! ( value) ) ) ;
893+ }
894+ NewHash { elements : found_elements, state : find ! ( state) }
895+ }
877896 ArrayMax { elements, state } => ArrayMax { elements : find_vec ! ( * elements) , state : find ! ( * state) } ,
878897 & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
879898 & SetIvar { self_val, id, val, state } => SetIvar { self_val : find ! ( self_val) , id, val, state } ,
@@ -923,6 +942,7 @@ impl Function {
923942 Insn :: StringIntern { .. } => types:: StringExact ,
924943 Insn :: NewArray { .. } => types:: ArrayExact ,
925944 Insn :: ArrayDup { .. } => types:: ArrayExact ,
945+ Insn :: NewHash { .. } => types:: HashExact ,
926946 Insn :: HashDup { .. } => types:: HashExact ,
927947 Insn :: CCall { return_type, .. } => * return_type,
928948 Insn :: GuardType { val, guard_type, .. } => self . type_of ( * val) . intersection ( * guard_type) ,
@@ -1396,6 +1416,13 @@ impl Function {
13961416 worklist. extend ( elements) ;
13971417 worklist. push_back ( state) ;
13981418 }
1419+ Insn :: NewHash { elements, state } => {
1420+ for ( key, value) in elements {
1421+ worklist. push_back ( key) ;
1422+ worklist. push_back ( value) ;
1423+ }
1424+ worklist. push_back ( state) ;
1425+ }
13991426 Insn :: StringCopy { val }
14001427 | Insn :: StringIntern { val }
14011428 | Insn :: Return { val }
@@ -1929,6 +1956,20 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
19291956 let insn_id = fun. push_insn ( block, Insn :: ArrayDup { val, state : exit_id } ) ;
19301957 state. stack_push ( insn_id) ;
19311958 }
1959+ YARVINSN_newhash => {
1960+ let count = get_arg ( pc, 0 ) . as_usize ( ) ;
1961+ assert ! ( count % 2 == 0 , "newhash count should be even" ) ;
1962+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
1963+ let mut elements = vec ! [ ] ;
1964+ eprintln ! ( "count: {count}, state before: {state}" ) ;
1965+ for _ in 0 ..( count/2 ) {
1966+ let value = state. stack_pop ( ) ?;
1967+ let key = state. stack_pop ( ) ?;
1968+ elements. push ( ( key, value) ) ;
1969+ }
1970+ elements. reverse ( ) ;
1971+ state. stack_push ( fun. push_insn ( block, Insn :: NewHash { elements, state : exit_id } ) ) ;
1972+ }
19321973 YARVINSN_duphash => {
19331974 let val = fun. push_insn ( block, Insn :: Const { val : Const :: Value ( get_arg ( pc, 0 ) ) } ) ;
19341975 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -2517,7 +2558,29 @@ mod tests {
25172558 "# ] ] ) ;
25182559 }
25192560
2520- // TODO(max): Test newhash when we have it
2561+ #[ test]
2562+ fn test_new_hash_empty ( ) {
2563+ eval ( "def test = {}" ) ;
2564+ assert_method_hir ( "test" , expect ! [ [ r#"
2565+ fn test:
2566+ bb0():
2567+ v2:HashExact = NewHash
2568+ Return v2
2569+ "# ] ] ) ;
2570+ }
2571+
2572+ #[ test]
2573+ fn test_new_hash_with_elements ( ) {
2574+ eval ( "def test(aval, bval) = {a: aval, b: bval}" ) ;
2575+ assert_method_hir ( "test" , expect ! [ [ r#"
2576+ fn test:
2577+ bb0(v0:BasicObject, v1:BasicObject):
2578+ v3:StaticSymbol[VALUE(0x1000)] = Const Value(VALUE(0x1000))
2579+ v4:StaticSymbol[VALUE(0x1008)] = Const Value(VALUE(0x1008))
2580+ v6:HashExact = NewHash v3: v0, v4: v1
2581+ Return v6
2582+ "# ] ] ) ;
2583+ }
25212584
25222585 #[ test]
25232586 fn test_string_copy ( ) {
@@ -3573,7 +3636,6 @@ mod opt_tests {
35733636 "# ] ] ) ;
35743637 }
35753638
3576-
35773639 #[ test]
35783640 fn test_eliminate_new_array ( ) {
35793641 eval ( "
@@ -3608,6 +3670,38 @@ mod opt_tests {
36083670 "# ] ] ) ;
36093671 }
36103672
3673+ #[ test]
3674+ fn test_eliminate_new_hash ( ) {
3675+ eval ( "
3676+ def test()
3677+ c = {}
3678+ 5
3679+ end
3680+ " ) ;
3681+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3682+ fn test:
3683+ bb0():
3684+ v4:Fixnum[5] = Const Value(5)
3685+ Return v4
3686+ "# ] ] ) ;
3687+ }
3688+
3689+ #[ test]
3690+ fn test_eliminate_new_hash_with_elements ( ) {
3691+ eval ( "
3692+ def test(aval, bval)
3693+ c = {a: aval, b: bval}
3694+ 5
3695+ end
3696+ " ) ;
3697+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3698+ fn test:
3699+ bb0(v0:BasicObject, v1:BasicObject):
3700+ v8:Fixnum[5] = Const Value(5)
3701+ Return v8
3702+ "# ] ] ) ;
3703+ }
3704+
36113705 #[ test]
36123706 fn test_eliminate_array_dup ( ) {
36133707 eval ( "
0 commit comments