@@ -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,19 @@ 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+ for _ in 0 ..( count/2 ) {
1965+ let value = state. stack_pop ( ) ?;
1966+ let key = state. stack_pop ( ) ?;
1967+ elements. push ( ( key, value) ) ;
1968+ }
1969+ elements. reverse ( ) ;
1970+ state. stack_push ( fun. push_insn ( block, Insn :: NewHash { elements, state : exit_id } ) ) ;
1971+ }
19321972 YARVINSN_duphash => {
19331973 let val = fun. push_insn ( block, Insn :: Const { val : Const :: Value ( get_arg ( pc, 0 ) ) } ) ;
19341974 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -2517,7 +2557,29 @@ mod tests {
25172557 "# ] ] ) ;
25182558 }
25192559
2520- // TODO(max): Test newhash when we have it
2560+ #[ test]
2561+ fn test_new_hash_empty ( ) {
2562+ eval ( "def test = {}" ) ;
2563+ assert_method_hir ( "test" , expect ! [ [ r#"
2564+ fn test:
2565+ bb0():
2566+ v2:HashExact = NewHash
2567+ Return v2
2568+ "# ] ] ) ;
2569+ }
2570+
2571+ #[ test]
2572+ fn test_new_hash_with_elements ( ) {
2573+ eval ( "def test(aval, bval) = {a: aval, b: bval}" ) ;
2574+ assert_method_hir ( "test" , expect ! [ [ r#"
2575+ fn test:
2576+ bb0(v0:BasicObject, v1:BasicObject):
2577+ v3:StaticSymbol[VALUE(0x1000)] = Const Value(VALUE(0x1000))
2578+ v4:StaticSymbol[VALUE(0x1008)] = Const Value(VALUE(0x1008))
2579+ v6:HashExact = NewHash v3: v0, v4: v1
2580+ Return v6
2581+ "# ] ] ) ;
2582+ }
25212583
25222584 #[ test]
25232585 fn test_string_copy ( ) {
@@ -3573,7 +3635,6 @@ mod opt_tests {
35733635 "# ] ] ) ;
35743636 }
35753637
3576-
35773638 #[ test]
35783639 fn test_eliminate_new_array ( ) {
35793640 eval ( "
@@ -3608,6 +3669,38 @@ mod opt_tests {
36083669 "# ] ] ) ;
36093670 }
36103671
3672+ #[ test]
3673+ fn test_eliminate_new_hash ( ) {
3674+ eval ( "
3675+ def test()
3676+ c = {}
3677+ 5
3678+ end
3679+ " ) ;
3680+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3681+ fn test:
3682+ bb0():
3683+ v4:Fixnum[5] = Const Value(5)
3684+ Return v4
3685+ "# ] ] ) ;
3686+ }
3687+
3688+ #[ test]
3689+ fn test_eliminate_new_hash_with_elements ( ) {
3690+ eval ( "
3691+ def test(aval, bval)
3692+ c = {a: aval, b: bval}
3693+ 5
3694+ end
3695+ " ) ;
3696+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
3697+ fn test:
3698+ bb0(v0:BasicObject, v1:BasicObject):
3699+ v8:Fixnum[5] = Const Value(5)
3700+ Return v8
3701+ "# ] ] ) ;
3702+ }
3703+
36113704 #[ test]
36123705 fn test_eliminate_array_dup ( ) {
36133706 eval ( "
0 commit comments