P icon indicating copy to clipboard operation
P copied to clipboard

Implement copy propagation optimisation pass?

Open dijkstracula opened this issue 2 years ago • 7 comments

In the following event handler (part of the ClientServer tutorial),

103     on eWithDrawResp do (resp: tWithDrawResp) {
104       assert resp.rId in pendingWDReqs,
105         format ("unexpected rId: {0} received, expected one of {1}", resp.rId, pendingWDReqs);
106       pendingWDReqs -= (resp.rId);
107    ...

The following backend code is generated:

            TMP_tmp0_3 = ((Integer)resp_1.get("rId"));
            TMP_tmp1_2 = pendingWDReqs.contains(TMP_tmp0_3);
            TMP_tmp2_2 = ((Integer)resp_1.get("rId"));
            TMP_tmp3_2 = (HashSet<Integer>)Values.clone(pendingWDReqs);
            TMP_tmp4_2 = MessageFormat.format("unexpected rId: {0} received, expected one of {1}", TMP_tmp2_2, TMP_tmp3_2);
            tryAssert(TMP_tmp1_2, TMP_tmp4_2);
            TMP_tmp5_2 = ((Integer)resp_1.get("rId"));
            pendingWDReqs.remove(TMP_tmp5_2);

Of course, TMP_tmp0_3, TMP_tmp2_2, and TMP_tmp5_2 are all redundant accesses. I wonder how feasible it would be to implement copy propagation or common subexpression elimination as an IR transformer?

dijkstracula avatar Jun 06 '22 19:06 dijkstracula

Good point! I have always been scared of adding any optimization into the compiler until really needed. Performance has never been a concern for the generated code so far (not any more as we start using P generated code outside testing).

But correctness would need to be thoroughly tested if we add optimizations.

Do you have a plan or design?

ankushdesai avatar Jun 06 '22 19:06 ankushdesai

Yep, strong agree that adding an optimisation that breaks the compiler would be a bad idea!

I also wonder whether the CLR and JVM's JITs (or even javac) are smart enough to elide those redundant accesses; running a quick experiment there might be the first thing to try before we try anything fancy on our end.

But, given that the IR is already in SSA, I think there are straightforward procedures for doing this? Let me investigate and come up with a concrete proposal if they're not elided at runtime.

dijkstracula avatar Jun 06 '22 20:06 dijkstracula

Thank you!

ankushdesai avatar Jun 06 '22 20:06 ankushdesai

OK, I did some splunking with the following P example from the Tutorial:

 19   state WaitForEvents {
 20     on ePrepareResp do (resp: tPrepareResp){
 21       var transId: int;
 22       transId = resp.transId;
 23
 24       if(!(transId in participantsResponse))
 25       {
 26         participantsResponse[transId] = default(map[tTransStatus, int]);
 27         participantsResponse[transId][SUCCESS] = 0;
 28         participantsResponse[transId][ERROR] = 0;
 29       }
 30       participantsResponse[transId][resp.status] = participantsResponse[transId][resp.status] + 1;
 31     }

The P IR emits a bunch of extraneous SSA nodes for map[tTransStatus, int], which in the Java extracted code appear as HashMap<Integer, Integer> types:

        private void Anon_2(eWriteTransResp pEvent) {
            Gen_PTuple_2 resp_1 = pEvent.payload;
            int TMP_tmp0_1 = 0;
            boolean TMP_tmp1_1 = false;
            int TMP_tmp2_1 = 0;
            boolean TMP_tmp3_1 = false;
            boolean TMP_tmp4_1 = false;
            String TMP_tmp5_1 = "";
            int TMP_tmp6_1 = 0;
            boolean TMP_tmp7_1 = false;
            int TMP_tmp8_1 = 0;
            HashMap<Integer,Integer> TMP_tmp9_1 = new HashMap<Integer,Integer>();
            int TMP_tmp10 = 0;
            boolean TMP_tmp11 = false;
            String TMP_tmp12 = "";
            int TMP_tmp13 = 0;
            HashMap<Integer,Integer> TMP_tmp14 = new HashMap<Integer,Integer>();
            int TMP_tmp15 = 0;
            int TMP_tmp16 = 0;
            HashMap<Integer,Integer> TMP_tmp17 = new HashMap<Integer,Integer>();
            int TMP_tmp18 = 0;
            String TMP_tmp19 = "";
            String TMP_tmp20 = "";
            int TMP_tmp21 = 0;
            boolean TMP_tmp22 = false;
            int TMP_tmp23 = 0;
            HashMap<Integer,Integer> TMP_tmp24 = new HashMap<Integer,Integer>();
            int TMP_tmp25 = 0;
            boolean TMP_tmp26 = false;
            int TMP_tmp27 = 0;
            String TMP_tmp28 = "";
            int TMP_tmp29 = 0;
            HashMap<Integer,Integer> TMP_tmp30 = new HashMap<Integer,Integer>();
            int TMP_tmp31 = 0;
            int TMP_tmp32 = 0;
            HashMap<Integer,Integer> TMP_tmp33 = new HashMap<Integer,Integer>();
            int TMP_tmp34 = 0;
            String TMP_tmp35 = "";
            String TMP_tmp36 = "";
            int TMP_tmp37 = 0;

            TMP_tmp0_1 = resp_1.transId;
            TMP_tmp1_1 = participantsResponse.containsKey(TMP_tmp0_1);
            TMP_tmp4_1 = TMP_tmp1_1;
            if (TMP_tmp4_1) {} else
            {
                TMP_tmp2_1 = resp_1.status;
                TMP_tmp3_1 = (TMP_tmp2_1 == tTransStatus.TIMEOUT);
                TMP_tmp4_1 = TMP_tmp3_1;
            }
...

Briefly: we have to check three compilers to see if these unnecessary allocations disappear. The first is of course the javac bytecode output, but also HotSpot has two JIT compilers: the Client Compiler (called "c1" internally) and the Server Compiler ("c2"). Both are used at runtime to generate native assembly with the so-called "tiered compilation" approach: C1 is optimised for compilation speed and C2 is optimised for code quality, so C2 is used for hot code; infrequently-called code may not ever hit the server compiler (though this is configurable of course). To dump JIT output, the -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*.Anon_2 flags were passed to Java.

The thing we'd like to see from all this output is assembly for Anon_2 that basically just calls containsKey() right away and avoids all the Hashmap.init() calls.

javac bytecode

No dice.

  private void Anon_2(TutorialIntegrationTests.TwoPhaseCommit$eWriteTransResp);
    Code:
       0: aload_1
       1: getfield      #69                 // Field TutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp.payload:LTutorialIntegrationTests/TwoPhaseCommit$Gen_PTup
le_2;
...
      54: new           #21                 // class java/util/HashMap
      57: dup
      58: invokespecial #23                 // Method java/util/HashMap."<init>":()V
      61: astore        17
      63: iconst_0
      64: istore        18
      66: iconst_0
      67: istore        19
      69: new           #21                 // class java/util/HashMap
      72: dup
      73: invokespecial #23                 // Method java/util/HashMap."<init>":()V
      76: astore        20
      78: iconst_0
      79: istore        21
      81: ldc           #74                 // String
      83: astore        22
      85: ldc           #74                 // String
      87: astore        23
      89: iconst_0
      90: istore        24
      92: iconst_0
      93: istore        25
      95: iconst_0
      96: istore        26
      98: new           #21                 // class java/util/HashMap
     101: dup
     102: invokespecial #23                 // Method java/util/HashMap."<init>":()V

C1

No dice.

============================= C1-compiled nmethod ==============================
----------------------------------- Assembly -----------------------------------

Compiled method (c1)   14044 13335       3       TutorialIntegrationTests.TwoPhaseCommit$AtomicityInvariant::Anon_2 (685 bytes)
 total in heap  [0x000000011899c510,0x00000001189a2028] = 23320
 relocation     [0x000000011899c670,0x000000011899cb68] = 1272
 main code      [0x000000011899cb80,0x00000001189a0460] = 14560
 stub code      [0x00000001189a0460,0x00000001189a0780] = 800
 oops           [0x00000001189a0780,0x00000001189a07a8] = 40
 metadata       [0x00000001189a07a8,0x00000001189a07f0] = 72
 scopes data    [0x00000001189a07f0,0x00000001189a1538] = 3400
 scopes pcs     [0x00000001189a1538,0x00000001189a1ef8] = 2496
 dependencies   [0x00000001189a1ef8,0x00000001189a1f08] = 16
 nul chk table  [0x00000001189a1f08,0x00000001189a2028] = 288

[Constant Pool (empty)]

[MachCode]
[Entry Point]
  # {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant'
  # this:     rsi:rsi   = 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant'
  # parm0:    rdx:rdx   = 'TutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp'
  #           [sp+0x150]  (sp of caller)
  0x000000011899cb80: 448b 5608 | 49bb 0000 | 0000 0800 | 0000 4d03 | d34c 3bd0 

  0x000000011899cb94: ;   {runtime_call ic_miss_stub}
  0x000000011899cb94: 0f85 e6ab | 9fff 660f | 1f44 0000 
[Verified Entry Point]
  0x000000011899cba0: 8984 2400 | c0fe ff55 | 4881 ec40 | 0100 0048 | 8974 2470 

  0x000000011899cbb4: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899cbb4: 48bf 5853 | b60d 0100 | 0000 8b87 | ac00 0000 | 83c0 0289 | 87ac 0000 | 00e9 bf30 | 0000 4883 
  0x000000011899cbd4: fa00 0f84 | d630 0000 | 0f1f 4000 

  0x000000011899cbe0: ; implicit exception: dispatches to 0x000000011899fcbf
  0x000000011899cbe0: e9ea 3000 | 0090 48c1 | e303 4889 

  0x000000011899cbec: ;   {metadata('java/util/HashMap')}
  0x000000011899cbec: 5c24 6848 | bab8 800f | 0008 0000 | 004c 8bc6 | 498b 8708 | 0100 0048 | 8d78 3049 | 3bbf 1801 
  0x000000011899cc0c: 0000 0f87 | c530 0000 | 4989 bf08 | 0100 0048 | c700 0100 | 0000 488b | ca49 ba00 | 0000 0008 
  0x000000011899cc2c: 0000 0049 | 2bca 8948 | 0848 33c9 | 8948 0c48 | 33c9 4889 | 4810 4889 | 4818 4889 | 4820 4889 
  0x000000011899cc4c: 4828 488b 

  0x000000011899cc50: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899cc50: d048 be58 | 53b6 0d01 | 0000 0048 | 8386 f000 

  0x000000011899cc60: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cc60: 0000 0148 | ba20 8341 | 0d01 0000 | 008b b2ac | 0000 0083 | c602 89b2 | ac00 0000 | 81e6 feff 
  0x000000011899cc80: 1f00 83fe | 000f 845b | 3000 0048 

  0x000000011899cc8c: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cc8c: 8bd0 48be | 2083 410d | 0100 0000 | 4883 86f0 | 0000 0001 

  0x000000011899cca0: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899cca0: 48ba 5084 | 410d 0100 | 0000 8bb2 | ac00 0000 | 83c6 0289 | b2ac 0000 | 0081 e6fe | ff1f 0083 
  0x000000011899ccc0: fe00 0f84 | 3f30 0000 

  0x000000011899ccc8: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899ccc8: 488b d048 | be50 8441 | 0d01 0000 | 0048 8386 | f000 0000 

  0x000000011899ccdc: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899ccdc: 0148 bab8 | 3640 0d01 | 0000 008b | b2ac 0000 | 0083 c602 | 89b2 ac00 | 0000 81e6 | feff 1f00 
  0x000000011899ccfc: 83fe 000f | 8423 3000 | 00c7 4020 | 0000 403f 

  0x000000011899cd0c: ;   {metadata('java/util/HashMap')}
  0x000000011899cd0c: 48ba b880 | 0f00 0800 | 0000 498b | 8708 0100 | 0048 8d78 | 3049 3bbf | 1801 0000 | 0f87 1b30 
  0x000000011899cd2c: 0000 4989 | bf08 0100 | 0048 c700 | 0100 0000 | 488b ca49 | ba00 0000 | 0008 0000 | 0049 2bca 
  0x000000011899cd4c: 8948 0848 | 33c9 8948 | 0c48 33c9 | 4889 4810 | 4889 4818 | 4889 4820 | 4889 4828 

  0x000000011899cd68: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899cd68: 488b d048 | be58 53b6 | 0d01 0000 | 0048 8386 | 0001 0000 

  0x000000011899cd7c: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cd7c: 0148 ba20 | 8341 0d01 | 0000 008b | b2ac 0000 | 0083 c602 | 89b2 ac00 | 0000 81e6 | feff 1f00 
  0x000000011899cd9c: 83fe 000f | 84b1 2f00 | 0048 8bd0 

  0x000000011899cda8: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cda8: 48be 2083 | 410d 0100 | 0000 4883 | 86f0 0000 

  0x000000011899cdb8: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899cdb8: 0001 48ba | 5084 410d | 0100 0000 | 8bb2 ac00 | 0000 83c6 | 0289 b2ac | 0000 0081 | e6fe ff1f 
  0x000000011899cdd8: 0083 fe00 | 0f84 952f | 0000 488b 

  0x000000011899cde4: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899cde4: d048 be50 | 8441 0d01 | 0000 0048 | 8386 f000 

  0x000000011899cdf4: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899cdf4: 0000 0148 | bab8 3640 | 0d01 0000 | 008b b2ac | 0000 0083 | c602 89b2 | ac00 0000 | 81e6 feff 
  0x000000011899ce14: 1f00 83fe | 000f 8479 | 2f00 00c7 | 4020 0000 

  0x000000011899ce24: ;   {metadata('java/util/HashMap')}
  0x000000011899ce24: 403f 48ba | b880 0f00 | 0800 0000 | 498b 8708 | 0100 0048 | 8d78 3049 | 3bbf 1801 | 0000 0f87 
  0x000000011899ce44: 712f 0000 | 4989 bf08 | 0100 0048 | c700 0100 | 0000 488b | ca49 ba00 | 0000 0008 | 0000 0049 
  0x000000011899ce64: 2bca 8948 | 0848 33c9 | 8948 0c48 | 33c9 4889 | 4810 4889 | 4818 4889 | 4820 4889 | 4828 488b 
  0x000000011899ce84: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899ce84: d048 be58 | 53b6 0d01 | 0000 0048 | 8386 1001 

  0x000000011899ce94: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899ce94: 0000 0148 | ba20 8341 | 0d01 0000 | 008b b2ac | 0000 0083 | c602 89b2 | ac00 0000 | 81e6 feff 
  0x000000011899ceb4: 1f00 83fe | 000f 8407 | 2f00 0048 

  0x000000011899cec0: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cec0: 8bd0 48be | 2083 410d | 0100 0000 | 4883 86f0 | 0000 0001 

  0x000000011899ced4: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899ced4: 48ba 5084 | 410d 0100 | 0000 8bb2 | ac00 0000 | 83c6 0289 | b2ac 0000 | 0081 e6fe | ff1f 0083 
  0x000000011899cef4: fe00 0f84 | eb2e 0000 

  0x000000011899cefc: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899cefc: 488b d048 | be50 8441 | 0d01 0000 | 0048 8386 | f000 0000 

  0x000000011899cf10: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899cf10: 0148 bab8 | 3640 0d01 | 0000 008b | b2ac 0000 | 0083 c602 | 89b2 ac00 | 0000 81e6 | feff 1f00 
  0x000000011899cf30: 83fe 000f | 84cf 2e00 | 00c7 4020 | 0000 403f 

  0x000000011899cf40: ;   {metadata('java/util/HashMap')}
  0x000000011899cf40: 48ba b880 | 0f00 0800 | 0000 498b | 8708 0100 | 0048 8d78 | 3049 3bbf | 1801 0000 | 0f87 c72e 
  0x000000011899cf60: 0000 4989 | bf08 0100 | 0048 c700 | 0100 0000 | 488b ca49 | ba00 0000 | 0008 0000 | 0049 2bca 
  0x000000011899cf80: 8948 0848 | 33c9 8948 | 0c48 33c9 | 4889 4810 | 4889 4818 | 4889 4820 | 4889 4828 

  0x000000011899cf9c: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899cf9c: 488b d048 | be58 53b6 | 0d01 0000 | 0048 8386 | 2001 0000 

  0x000000011899cfb0: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cfb0: 0148 ba20 | 8341 0d01 | 0000 008b | b2ac 0000 | 0083 c602 | 89b2 ac00 | 0000 81e6 | feff 1f00 
  0x000000011899cfd0: 83fe 000f | 845d 2e00 | 0048 8bd0 

  0x000000011899cfdc: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899cfdc: 48be 2083 | 410d 0100 | 0000 4883 | 86f0 0000 

  0x000000011899cfec: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899cfec: 0001 48ba | 5084 410d | 0100 0000 | 8bb2 ac00 | 0000 83c6 | 0289 b2ac | 0000 0081 | e6fe ff1f 
  0x000000011899d00c: 0083 fe00 | 0f84 412e | 0000 488b 

  0x000000011899d018: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899d018: d048 be50 | 8441 0d01 | 0000 0048 | 8386 f000 

  0x000000011899d028: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899d028: 0000 0148 | bab8 3640 | 0d01 0000 | 008b b2ac | 0000 0083 | c602 89b2 | ac00 0000 | 81e6 feff 
  0x000000011899d048: 1f00 83fe | 000f 8425 | 2e00 00c7 | 4020 0000 

  0x000000011899d058: ;   {metadata('java/util/HashMap')}
  0x000000011899d058: 403f 48ba | b880 0f00 | 0800 0000 | 498b 8708 | 0100 0048 | 8d78 3049 | 3bbf 1801 | 0000 0f87 
  0x000000011899d078: 1d2e 0000 | 4989 bf08 | 0100 0048 | c700 0100 | 0000 488b | ca49 ba00 | 0000 0008 | 0000 0049 
  0x000000011899d098: 2bca 8948 | 0848 33c9 | 8948 0c48 | 33c9 4889 | 4810 4889 | 4818 4889 | 4820 4889 | 4828 488b 
  0x000000011899d0b8: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899d0b8: d048 be58 | 53b6 0d01 | 0000 0048 | 8386 3001 

  0x000000011899d0c8: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899d0c8: 0000 0148 | ba20 8341 | 0d01 0000 | 008b b2ac | 0000 0083 | c602 89b2 | ac00 0000 | 81e6 feff 
  0x000000011899d0e8: 1f00 83fe | 000f 84b3 | 2d00 0048 

  0x000000011899d0f4: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899d0f4: 8bd0 48be | 2083 410d | 0100 0000 | 4883 86f0 | 0000 0001 

  0x000000011899d108: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899d108: 48ba 5084 | 410d 0100 | 0000 8bb2 | ac00 0000 | 83c6 0289 | b2ac 0000 | 0081 e6fe | ff1f 0083 
  0x000000011899d128: fe00 0f84 | 972d 0000 

  0x000000011899d130: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899d130: 488b d048 | be50 8441 | 0d01 0000 | 0048 8386 | f000 0000 

  0x000000011899d144: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899d144: 0148 bab8 | 3640 0d01 | 0000 008b | b2ac 0000 | 0083 c602 | 89b2 ac00 | 0000 81e6 | feff 1f00 
  0x000000011899d164: 83fe 000f | 847b 2d00 | 00c7 4020 | 0000 403f 

  0x000000011899d174: ;   {metadata('java/util/HashMap')}
  0x000000011899d174: 48ba b880 | 0f00 0800 | 0000 498b | 8708 0100 | 0048 8d78 | 3049 3bbf | 1801 0000 | 0f87 732d 
  0x000000011899d194: 0000 4989 | bf08 0100 | 0048 c700 | 0100 0000 | 488b ca49 | ba00 0000 | 0008 0000 | 0049 2bca 
  0x000000011899d1b4: 8948 0848 | 33c9 8948 | 0c48 33c9 | 4889 4810 | 4889 4818 | 4889 4820 | 4889 4828 

  0x000000011899d1d0: ;   {metadata(method data for {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant')}
  0x000000011899d1d0: 488b f048 | bf58 53b6 | 0d01 0000 | 0048 8387 | 4001 0000 

  0x000000011899d1e4: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899d1e4: 0148 be20 | 8341 0d01 | 0000 008b | beac 0000 | 0083 c702 | 89be ac00 | 0000 81e7 | feff 1f00 
  0x000000011899d204: 83ff 000f | 8409 2d00 | 0048 8bf0 

  0x000000011899d210: ;   {metadata(method data for {method} {0x000000080037d5e8} '<init>' '()V' in 'java/util/HashMap')}
  0x000000011899d210: 48bf 2083 | 410d 0100 | 0000 4883 | 87f0 0000 

  0x000000011899d220: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899d220: 0001 48be | 5084 410d | 0100 0000 | 8bbe ac00 | 0000 83c7 | 0289 beac | 0000 0081 | e7fe ff1f 
  0x000000011899d240: 0083 ff00 | 0f84 ed2c | 0000 488b 

  0x000000011899d24c: ;   {metadata(method data for {method} {0x00000008003d11f8} '<init>' '()V' in 'java/util/AbstractMap')}
  0x000000011899d24c: f048 bf50 | 8441 0d01 | 0000 0048 | 8387 f000 

  0x000000011899d25c: ;   {metadata(method data for {method} {0x0000000800444540} '<init>' '()V' in 'java/lang/Object')}
  0x000000011899d25c: 0000 0148 | beb8 3640 | 0d01 0000 | 008b beac | 0000 0083 | c702 89be | ac00 0000 | 81e7 feff 
  0x000000011899d27c: 1f00 83ff | 000f 84d1 | 2c00 00c7 | 4020 0000 | 403f 4883 | fb00 0f84 | e12c 0000 

C2:

Aha!

============================= C2-compiled nmethod ==============================
----------------------------------- Assembly -----------------------------------

Compiled method (c2)   15255 14110       4       TutorialIntegrationTests.TwoPhaseCommit$AtomicityInvariant::Anon_2 (685 bytes)
 total in heap  [0x000000012025b910,0x000000012025d428] = 6936
 relocation     [0x000000012025ba70,0x000000012025bb68] = 248
 main code      [0x000000012025bb80,0x000000012025c6a0] = 2848
 stub code      [0x000000012025c6a0,0x000000012025c6d8] = 56
 oops           [0x000000012025c6d8,0x000000012025c708] = 48
 metadata       [0x000000012025c708,0x000000012025c748] = 64
 scopes data    [0x000000012025c748,0x000000012025cf38] = 2032
 scopes pcs     [0x000000012025cf38,0x000000012025d1f8] = 704
 dependencies   [0x000000012025d1f8,0x000000012025d208] = 16
 handler table  [0x000000012025d208,0x000000012025d3d0] = 456
 nul chk table  [0x000000012025d3d0,0x000000012025d428] = 88

[Constant Pool (empty)]

[MachCode]
[Entry Point]
  # {method} {0x000000010d89e528} 'Anon_2' '(LTutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp;)V' in 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant'
  # this:     rsi:rsi   = 'TutorialIntegrationTests/TwoPhaseCommit$AtomicityInvariant'
  # parm0:    rdx:rdx   = 'TutorialIntegrationTests/TwoPhaseCommit$eWriteTransResp'
  #           [sp+0x50]  (sp of caller)
  0x000000012025bb80: 448b 5608 | 49bb 0000 | 0000 0800 | 0000 4d03 | d349 3bc2 

  0x000000012025bb94: ;   {runtime_call ic_miss_stub}
  0x000000012025bb94: 0f85 e6bb | 13f8 6690 | 0f1f 4000 
[Verified Entry Point]
  0x000000012025bba0: 8984 2400 | c0fe ff55 | 4883 ec40 

  0x000000012025bbac: ; implicit exception: dispatches to 0x000000012025c5a0
  0x000000012025bbac: 448b 420c 

  0x000000012025bbb0: ; implicit exception: dispatches to 0x000000012025c5ac
  0x000000012025bbb0: 438b 4cc4 | 0c44 8b4e | 2044 8bd9 | 4181 c380 | 0000 004b | 8d1c c441 | 81fb 0001 | 0000 0f83 
  0x000000012025bbd0: 6003 0000 

  0x000000012025bbd4: ;   {oop(a 'java/lang/Integer'[256] {0x00000007ffc77a00})}
  0x000000012025bbd4: 4c63 d149 | bb00 7ac7 | ff07 0000 | 0047 8b9c | 9310 0200 | 004b 8d14 | dc45 85c9 | 0f84 5c08 
  0x000000012025bbf4: 0000 4889 | 5c24 0844 | 8904 2448 | 8bee 4b8d 

  0x000000012025bc04: ;   {optimized virtual_call}
  0x000000012025bc04: 34cc 90e8 

  0x000000012025bc08: ; ImmutableOopMap {rbp=Oop [0]=NarrowOop [8]=Oop }
                      ;*invokevirtual getNode {reexecute=0 rethrow=0 return_oop=1}
                      ; - java.util.HashMap::containsKey@2 (line 594)
                      ; - TutorialIntegrationTests.TwoPhaseCommit$AtomicityInvariant::Anon_2@174 (line 409)
  0x000000012025bc08: 74be 13f8 | 448b 0c24 | 438b 4ccc | 1048 85c0 | 0f84 7f04 | 0000 4885 | c041 0f95 | c245 0fb6 
  0x000000012025bc28: d245 85d2 | 0f84 2e08 | 0000 4c8b | c545 8b58 | 2043 8b6c | cc0c 498b | fb48 c1e7 | 034c 63d5 
  0x000000012025bc48: 8bdd 81c3 | 8000 0000 | 85c9 0f85 | 5604 0000 | 81fb 0001 | 0000 0f83 | 1003 0000 

So, we have to hit the highest-optimising compiler for these allocations to disappear. C2 does some pretty aggressive dataflow analysis so I would have been surprised if it didn't elide those allocations, but I'm a bit surprised C1 didn't.

dijkstracula avatar Jun 08 '22 19:06 dijkstracula

This is so cool! thanks for the study @dijkstracula, love it!

ankushdesai avatar Jun 08 '22 20:06 ankushdesai

Are there similar optimization flags that we can use for C# compiler as well?

ankushdesai avatar Jun 08 '22 20:06 ankushdesai

Couldn't say for sure, but this suggests that you can so long as you're using non-VS Code Visual Studio. This suggests such functionality isn't present in Rider (at least at the time).

Edit: Update: found this, which at least doesn't require GUI tooling but still looks a bit gnarly.

dijkstracula avatar Jun 08 '22 20:06 dijkstracula