@@ -62,29 +62,27 @@ static bool blockNeedsGCPoll(BasicBlock* block)
6262
6363PhaseStatus Compiler::fgInsertClsInitChecks ()
6464{
65- 
66-     if  (!strcmp (info.compMethodName , " Test" 
67-     {
68-         fgDispBasicBlocks (true );
69-     }
70- 
7165    if  (!opts.OptimizationEnabled ())
7266    {
7367        return  PhaseStatus::MODIFIED_NOTHING;
7468    }
7569
7670    bool         modified = false ;
7771    BasicBlock* block;
72+ 
73+     BasicBlock* prevBb = nullptr ;
7874    for  (block = fgFirstBB; block; block = block->bbNext )
7975    {
80-         if  (!block->isRunRarely () && block-> bbFlags )
76+         if  (!block->isRunRarely ())
8177        {
8278            for  (Statement* stmt : block->Statements ())
8379            {
8480                for  (GenTree* tree = stmt->GetTreeList (); tree != nullptr ; tree = tree->gtNext )
8581                {
86-                     if  (!tree->IsCall ())
82+                     //  we only need GT_CALL nodes with helper funcs
83+                     if  (!tree->IsCall () || (tree->gtFlags  & GTF_CALL_HOISTABLE))
8784                    {
85+                         //  TODO: remove that GTF_CALL_HOISTABLE check
8886                        continue ;
8987                    }
9088
@@ -95,20 +93,46 @@ PhaseStatus Compiler::fgInsertClsInitChecks()
9593                    }
9694
9795                    CorInfoHelpFunc helpFunc = eeGetHelperNum (call->gtCallMethHnd );
98-                     if  (helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE)
96+                     if  ((helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE) ||
97+                         (call->fgArgInfo ->ArgCount () != 2 ))
9998                    {
10099                        continue ;
101100                    }
102101
103-                     GenTree* moduleIdArg = call->LateArgs (). begin ()-> GetNode ( );
104-                     GenTree* clsIdArg    = call->LateArgs (). begin ()-> GetNext ()-> GetNode ( );
102+                     GenTree* moduleIdArg = call->fgArgInfo -> GetArgNode ( 0 );
103+                     GenTree* clsIdArg    = call->fgArgInfo -> GetArgNode ( 1 );
105104
106105                    if  (!moduleIdArg->IsCnsIntOrI () || !clsIdArg->IsCnsIntOrI ())
107106                    {
108107                        //  Looks like moduleId or/and clsId were passed as indirect loads
109108                        continue ;
110109                    }
111110
111+                     if  (clsIdArg->AsIntCon ()->IconValue () < 0 )
112+                     {
113+                         //  Unknown clsId
114+                         continue ;
115+                     }
116+ 
117+                     if  (prevBb == nullptr )
118+                     {
119+                         //  We're going to emit a BB in front of fgFirstBB 
120+                         fgEnsureFirstBBisScratch ();
121+                         prevBb = fgFirstBB;
122+                         if  (prevBb == block)
123+                         {
124+                             continue ;
125+                         }
126+                     }
127+ 
128+                     //  So, we found a helper call inside the "block" - let's extract it to a
129+                     //  separate block "callInitBb" and guard it with a fast "isInitedBb" bb.
130+                     //  The final layout should look like this:
131+ 
132+                     //  BB0 "prevBb":
133+                     //      ...
134+                     // 
135+                     //  BB1 "isInitedBb":    (preds: BB0 + %current preds of BB3%)
112136                    // 
113137                    //   *  JTRUE     void
114138                    //   \--*  NE        int
@@ -118,62 +142,119 @@ PhaseStatus Compiler::fgInsertClsInitChecks()
118142                    //      |  \--*  CNS_INT   int    isInitMask
119143                    //      \--*  CNS_INT   int    0
120144                    // 
145+                     // 
146+                     //  BB2 "callInitBb":    (preds: BB1)
147+                     // 
121148                    //   *  CALL help long   HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
122149                    //   +--*  CNS_INT   long   moduleIdArg
123150                    //   \--*  CNS_INT   int    clsIdArg
124151                    // 
125-                                        
152+                     //  BB3 "block"          (preds: BB1, BB2)
153+                     //      ...
154+                     // 
155+ 
156+ 
157+                     //  Let's start from emitting that BB2 "callInitBb"
126158                    BasicBlock* callInitBb = fgNewBBbefore (BBJ_NONE, block, true );
127-                     fgAddRefPred (block, callInitBb); 
159+                     //  it's executed only once so can be marked as cold 
128160                    callInitBb->bbSetRunRarely ();
129-                     callInitBb->bbFlags  |= block->bbFlags  & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_HAS_CALL);
130- 
161+                     callInitBb->bbFlags  |= (BBF_INTERNAL | BBF_HAS_CALL | BBF_HAS_LABEL);
131162                    GenTree* clonedHelperCall = gtCloneExprCallHelper (call);
132163                    clonedHelperCall->gtFlags  |= call->gtFlags ;
133-                     fgInsertStmtAtEnd (callInitBb, fgNewStmtFromTree (clonedHelperCall));
134164
165+                     Statement* callStmt = fgNewStmtFromTree (clonedHelperCall);
166+                     if  (fgStmtListThreaded)
167+                     {
168+                         gtSetStmtInfo (callStmt);
169+                         fgSetStmtSeq (callStmt);
170+                     }
171+                     fgInsertStmtAtEnd (callInitBb, callStmt);
172+                     gtUpdateStmtSideEffects (callStmt);
173+ 
174+                     //  BB1 "isInitedBb"
135175                    BasicBlock* isInitedBb = fgNewBBbefore (BBJ_COND, callInitBb, true );
136-                     fgAddRefPred (callInitBb, isInitedBb);
137-                     fgAddRefPred (block, isInitedBb);
138176                    isInitedBb->inheritWeight (block);
139-                     isInitedBb->bbFlags  |= block-> bbFlags  & (BBF_SPLIT_GAINED  | BBF_IMPORTED  | BBF_HAS_CALL );
177+                     isInitedBb->bbFlags  |= (BBF_INTERNAL  | BBF_HAS_LABEL  | BBF_HAS_JMP );
140178
141179                    //  TODO: ask VM for these constants:
142-                     const  int  dataBlobOffset = 48 ;
143-                     const  int  isInitMask     = 1 ;
180+                     const  int  dataBlobOffset = 48 ;  //  DomainLocalModule::GetOffsetOfDataBlob() 
181+                     const  int  isInitMask     = 1 ;   //  ClassInitFlags::INITIALIZED_FLAG; 
144182
145183                    size_t    address = moduleIdArg->AsIntCon ()->IconValue () + dataBlobOffset + clsIdArg->AsIntCon ()->IconValue ();
146184                    GenTree* indir   = gtNewIndir (TYP_UBYTE, gtNewIconNode (address, TYP_I_IMPL));
147185                    indir->gtFlags  = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
148186
149187                    GenTree* isInitedMask = gtNewOperNode (GT_AND, TYP_INT, indir, gtNewIconNode (isInitMask));
150-                     GenTree* isInitedCmp  = gtNewOperNode (GT_NE, TYP_INT, isInitedMask, gtNewIconNode (0 ));
188+                     GenTree* isInitedCmp  = gtNewOperNode (GT_GT, TYP_INT, isInitedMask, gtNewIconNode (0 ));
189+                     isInitedCmp->gtFlags  |= (GTF_UNSIGNED | GTF_RELOP_JMP_USED);
151190
152-                     fgInsertStmtAtEnd (isInitedBb, fgNewStmtFromTree (gtNewOperNode (GT_JTRUE, TYP_VOID, isInitedCmp)));
191+                     Statement* isInitedStmt = fgNewStmtFromTree (gtNewOperNode (GT_JTRUE, TYP_VOID, isInitedCmp));
192+                     if  (fgStmtListThreaded)
193+                     {
194+                         gtSetStmtInfo (isInitedStmt);
195+                         fgSetStmtSeq (isInitedStmt);
196+                     }
197+ 
198+                     fgInsertStmtAtEnd (isInitedBb, isInitedStmt);
153199                    isInitedBb->bbJumpDest  = block;
154-                     gtReplaceTree (stmt, call, gtNewNothingNode ());
200+                     block->bbFlags  |= BBF_JMP_TARGET;
201+ 
202+                     //  Now we can remove the call from the current block
203+                     //  We're going to replace the call with just "moduleId" node (it's what it was supposed to return)
204+                     gtReplaceTree (stmt, call, gtNewIconNode (moduleIdArg->AsIntCon ()->IconValue (), call->TypeGet ()));
205+ 
206+                     //  Now we need to fix all the preds:
207+ 
208+                     //  isInitedBb is a pred of callInitBb
209+                     fgAddRefPred (callInitBb, isInitedBb);
210+                     for  (flowList* pred = block->bbPreds ; pred != nullptr ; pred = pred->flNext )
211+                     {
212+                         //  Redirect all the preds from the current block to isInitedBb
213+ 
214+                         //  TODO: should I check EH region here?
215+                         //  TODO: should I update some loop info if I'm inside a loop?
216+ 
217+                         BasicBlock* predBlock = pred->getBlock ();
218+                         if  (predBlock->bbJumpDest  == block)
219+                         {
220+                             predBlock->bbJumpDest  = isInitedBb;
221+                             isInitedBb->bbFlags  |= BBF_JMP_TARGET;
222+                         }
223+                         fgRemoveRefPred (block, predBlock);
224+                         fgAddRefPred (isInitedBb, predBlock);
225+                     }
226+                     //  Both callInitBb and isInitedBb are preds of block now
227+                     fgAddRefPred (block, callInitBb);
228+                     fgAddRefPred (block, isInitedBb);
155229
230+                     //  Make sure all three basic blocks are in the same EH region:
231+                     BasicBlock::sameEHRegion (callInitBb, block);
232+                     BasicBlock::sameEHRegion (isInitedBb, block);
156233
157234                    modified = true ;
158235                }
159236                if  (modified)
160237                {
161-                     //  clear GTF_CALL and GTF_EXC flags
238+                     //  clear GTF_CALL and GTF_EXC flags (we've just removed a call) 
162239                    gtUpdateStmtSideEffects (stmt);
163240                }
164241            }
165242        }
166-     }
167- 
168-     if  (!strcmp (info.compMethodName , " Test" 
169-     {
170-         fgDispBasicBlocks (true );
243+         prevBb = block;
171244    }
172245
173246    if  (modified)
174247    {
248+ #ifdef  DEBUG
249+         if  (verbose)
250+         {
251+             printf (" \n After fgInsertClsInitChecks:" 
252+             fgDispBasicBlocks (true );
253+         }
254+ #endif  //  DEBUG
175255        fgReorderBlocks ();
176-         fgUpdateChangedFlowGraph (false );
256+         constexpr  bool  computeDoms = false ;
257+         fgUpdateChangedFlowGraph (computeDoms);
177258        return  PhaseStatus::MODIFIED_EVERYTHING;
178259    }
179260    return  PhaseStatus::MODIFIED_NOTHING;
0 commit comments