@@ -52,6 +52,133 @@ static bool blockNeedsGCPoll(BasicBlock* block)
52
52
return blockMayNeedGCPoll;
53
53
}
54
54
55
+ // ------------------------------------------------------------------------------
56
+ // fgInsertClsInitChecks : Wraps static init helper calls with "is class statically initialized"
57
+ // inlined checks.
58
+ //
59
+ // Returns:
60
+ // PhaseStatus indicating what, if anything, was changed.
61
+ //
62
+
63
+ PhaseStatus Compiler::fgInsertClsInitChecks ()
64
+ {
65
+
66
+ if (!strcmp (info.compMethodName , " Test" ))
67
+ {
68
+ fgDispBasicBlocks (true );
69
+ }
70
+
71
+ if (!opts.OptimizationEnabled ())
72
+ {
73
+ return PhaseStatus::MODIFIED_NOTHING;
74
+ }
75
+
76
+ bool modified = false ;
77
+ BasicBlock* block;
78
+ for (block = fgFirstBB; block; block = block->bbNext )
79
+ {
80
+ if (!block->isRunRarely () && block->bbFlags )
81
+ {
82
+ for (Statement* stmt : block->Statements ())
83
+ {
84
+ for (GenTree* tree = stmt->GetTreeList (); tree != nullptr ; tree = tree->gtNext )
85
+ {
86
+ if (!tree->IsCall ())
87
+ {
88
+ continue ;
89
+ }
90
+
91
+ GenTreeCall* call = tree->AsCall ();
92
+ if (call->gtCallType != CT_HELPER)
93
+ {
94
+ continue ;
95
+ }
96
+
97
+ CorInfoHelpFunc helpFunc = eeGetHelperNum (call->gtCallMethHnd );
98
+ if (helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE)
99
+ {
100
+ continue ;
101
+ }
102
+
103
+ GenTree* moduleIdArg = call->LateArgs ().begin ()->GetNode ();
104
+ GenTree* clsIdArg = call->LateArgs ().begin ()->GetNext ()->GetNode ();
105
+
106
+ if (!moduleIdArg->IsCnsIntOrI () || !clsIdArg->IsCnsIntOrI ())
107
+ {
108
+ // Looks like moduleId or/and clsId were passed as indirect loads
109
+ continue ;
110
+ }
111
+
112
+ //
113
+ // * JTRUE void
114
+ // \--* NE int
115
+ // +--* AND int
116
+ // | +--* IND ubyte
117
+ // | | \--* CNS_INT long moduleIdArg + clsIdArg + dataBlobOffset
118
+ // | \--* CNS_INT int isInitMask
119
+ // \--* CNS_INT int 0
120
+ //
121
+ // * CALL help long HELPER.CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE
122
+ // +--* CNS_INT long moduleIdArg
123
+ // \--* CNS_INT int clsIdArg
124
+ //
125
+
126
+ BasicBlock* callInitBb = fgNewBBbefore (BBJ_NONE, block, true );
127
+ fgAddRefPred (block, callInitBb);
128
+ callInitBb->bbSetRunRarely ();
129
+ callInitBb->bbFlags |= block->bbFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_HAS_CALL);
130
+
131
+ GenTree* clonedHelperCall = gtCloneExprCallHelper (call);
132
+ clonedHelperCall->gtFlags |= call->gtFlags ;
133
+ fgInsertStmtAtEnd (callInitBb, fgNewStmtFromTree (clonedHelperCall));
134
+
135
+ BasicBlock* isInitedBb = fgNewBBbefore (BBJ_COND, callInitBb, true );
136
+ fgAddRefPred (callInitBb, isInitedBb);
137
+ fgAddRefPred (block, isInitedBb);
138
+ isInitedBb->inheritWeight (block);
139
+ isInitedBb->bbFlags |= block->bbFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_HAS_CALL);
140
+
141
+ // TODO: ask VM for these constants:
142
+ const int dataBlobOffset = 48 ;
143
+ const int isInitMask = 1 ;
144
+
145
+ size_t address = moduleIdArg->AsIntCon ()->IconValue () + dataBlobOffset + clsIdArg->AsIntCon ()->IconValue ();
146
+ GenTree* indir = gtNewIndir (TYP_UBYTE, gtNewIconNode (address, TYP_I_IMPL));
147
+ indir->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
148
+
149
+ GenTree* isInitedMask = gtNewOperNode (GT_AND, TYP_INT, indir, gtNewIconNode (isInitMask));
150
+ GenTree* isInitedCmp = gtNewOperNode (GT_NE, TYP_INT, isInitedMask, gtNewIconNode (0 ));
151
+
152
+ fgInsertStmtAtEnd (isInitedBb, fgNewStmtFromTree (gtNewOperNode (GT_JTRUE, TYP_VOID, isInitedCmp)));
153
+ isInitedBb->bbJumpDest = block;
154
+ gtReplaceTree (stmt, call, gtNewNothingNode ());
155
+
156
+
157
+ modified = true ;
158
+ }
159
+ if (modified)
160
+ {
161
+ // clear GTF_CALL and GTF_EXC flags
162
+ gtUpdateStmtSideEffects (stmt);
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ if (!strcmp (info.compMethodName , " Test" ))
169
+ {
170
+ fgDispBasicBlocks (true );
171
+ }
172
+
173
+ if (modified)
174
+ {
175
+ fgReorderBlocks ();
176
+ fgUpdateChangedFlowGraph (false );
177
+ return PhaseStatus::MODIFIED_EVERYTHING;
178
+ }
179
+ return PhaseStatus::MODIFIED_NOTHING;
180
+ }
181
+
55
182
// ------------------------------------------------------------------------------
56
183
// fgInsertGCPolls : Insert GC polls for basic blocks containing calls to methods
57
184
// with SuppressGCTransitionAttribute.
0 commit comments