@@ -104,13 +104,16 @@ var_types Compiler::impImportCall(OPCODE opcode,
104
104
bool checkForSmallType = false ;
105
105
bool bIntrinsicImported = false ;
106
106
107
- CORINFO_SIG_INFO calliSig ;
107
+ CORINFO_SIG_INFO originalSig ;
108
108
NewCallArg extraArg;
109
109
110
- /* -------------------------------------------------------------------------
111
- * First create the call node
112
- */
110
+ // run transformations when instrumenting to not pollute PGO data
111
+ bool optimizedOrInstrumented = opts.OptimizationEnabled () || opts.IsInstrumented ();
112
+ CORINFO_METHOD_HANDLE replacementMethod = nullptr ;
113
+ GenTree* newThis = nullptr ;
114
+ SigTransform sigTransformation = SigTransform::LeaveIntact;
113
115
116
+ // handle special import cases
114
117
if (opcode == CEE_CALLI)
115
118
{
116
119
if (IsTargetAbi (CORINFO_NATIVEAOT_ABI))
@@ -125,25 +128,102 @@ var_types Compiler::impImportCall(OPCODE opcode,
125
128
}
126
129
127
130
/* Get the call site sig */
128
- eeGetSig (pResolvedToken->token , pResolvedToken->tokenScope , pResolvedToken->tokenContext , &calliSig );
131
+ eeGetSig (pResolvedToken->token , pResolvedToken->tokenScope , pResolvedToken->tokenContext , &originalSig );
129
132
130
- callRetTyp = JITtype2varType (calliSig.retType );
133
+ if (!optimizedOrInstrumented)
134
+ {
135
+ // ignore
136
+ }
137
+ else if (originalSig.getCallConv () == CORINFO_CALLCONV_DEFAULT)
138
+ {
139
+ JITDUMP (" \n\n impImportCall trying to import calli as call\n " );
140
+ GenTree* fptr = impStackTop ().val ;
141
+ if (fptr->OperIs (GT_LCL_VAR))
142
+ {
143
+ JITDUMP (" impImportCall trying to import calli as call - trying to substitute LCL_VAR\n " );
144
+ GenTree* lclValue = impGetNodeFromLocal (fptr);
145
+ if (lclValue != nullptr )
146
+ {
147
+ fptr = lclValue;
148
+ }
149
+ }
150
+ if (fptr->OperIs (GT_FTN_ADDR))
151
+ {
152
+ replacementMethod = fptr->AsFptrVal ()->gtFptrMethod ;
153
+ }
154
+ else
155
+ {
156
+ JITDUMP (" impImportCall failed to import calli as call - address node not found\n " );
157
+ }
158
+ }
159
+ else
160
+ {
161
+ JITDUMP (" impImportCall failed to import calli as call - call conv %u is not managed\n " ,
162
+ originalSig.getCallConv ());
163
+ }
164
+ }
165
+
166
+ if (replacementMethod != nullptr )
167
+ {
168
+ JITDUMP (" impImportCall trying to transform call - found target method %s\n " ,
169
+ eeGetMethodName (replacementMethod));
170
+ CORINFO_SIG_INFO methodSig;
171
+ CORINFO_CLASS_HANDLE targetClass = info.compCompHnd ->getMethodClass (replacementMethod);
172
+ info.compCompHnd ->getMethodSig (replacementMethod, &methodSig, targetClass);
131
173
132
- call = impImportIndirectCall (&calliSig, di);
174
+ unsigned replacementFlags = info.compCompHnd ->getMethodAttribs (replacementMethod);
175
+
176
+ if ((replacementFlags & CORINFO_FLG_PINVOKE) != 0 )
177
+ {
178
+ JITDUMP (" impImportCall aborting transformation - found PInvoke\n " );
179
+ }
180
+ else if (impCanSubstituteSig (&originalSig, &methodSig, sigTransformation))
181
+ {
182
+ impPopStack ();
183
+ if (newThis != nullptr )
184
+ {
185
+ assert (sigTransformation == SigTransform::ReplaceRefThis);
186
+ CORINFO_CLASS_HANDLE thisCls = NO_CLASS_HANDLE;
187
+ info.compCompHnd ->getArgType (&methodSig, methodSig.args , &thisCls);
188
+ impPushOnStack (newThis, typeInfo (TI_REF, thisCls));
189
+ }
190
+ JITDUMP (" impImportCall transforming call\n " );
191
+ pResolvedToken->hMethod = replacementMethod;
192
+ pResolvedToken->hClass = targetClass;
193
+
194
+ callInfo->sig = methodSig;
195
+ callInfo->hMethod = replacementMethod;
196
+ callInfo->methodFlags = replacementFlags;
197
+ callInfo->classFlags = info.compCompHnd ->getClassAttribs (targetClass);
198
+
199
+ return impImportCall (CEE_CALL, pResolvedToken, nullptr , nullptr ,
200
+ prefixFlags, callInfo, rawILOffset);
201
+ }
202
+ }
203
+
204
+ /* -------------------------------------------------------------------------
205
+ * First create the call node
206
+ */
207
+
208
+ if (opcode == CEE_CALLI)
209
+ {
210
+ callRetTyp = JITtype2varType (originalSig.retType );
211
+
212
+ call = impImportIndirectCall (&originalSig, di);
133
213
134
214
// We don't know the target method, so we have to infer the flags, or
135
215
// assume the worst-case.
136
- mflags = (calliSig .callConv & CORINFO_CALLCONV_HASTHIS) ? 0 : CORINFO_FLG_STATIC;
216
+ mflags = (originalSig .callConv & CORINFO_CALLCONV_HASTHIS) ? 0 : CORINFO_FLG_STATIC;
137
217
138
218
#ifdef DEBUG
139
219
if (verbose)
140
220
{
141
- unsigned structSize = (callRetTyp == TYP_STRUCT) ? eeTryGetClassSize (calliSig .retTypeSigClass ) : 0 ;
221
+ unsigned structSize = (callRetTyp == TYP_STRUCT) ? eeTryGetClassSize (originalSig .retTypeSigClass ) : 0 ;
142
222
printf (" \n In Compiler::impImportCall: opcode is %s, kind=%d, callRetType is %s, structSize is %u\n " ,
143
223
opcodeNames[opcode], callInfo->kind , varTypeName (callRetTyp), structSize);
144
224
}
145
225
#endif
146
- sig = &calliSig ;
226
+ sig = &originalSig ;
147
227
}
148
228
else // (opcode != CEE_CALLI)
149
229
{
@@ -1622,6 +1702,114 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN
1622
1702
#endif // FEATURE_MULTIREG_RET
1623
1703
}
1624
1704
1705
+ // -----------------------------------------------------------------------------------
1706
+ // impCanSubstituteSig: Checks whether it's safe to replace a call with another one.
1707
+ // This DOES NOT check if the calls are actually compatible, it only checks if their trees are.
1708
+ // Use ONLY when code will call the method with target sig anyway.
1709
+ //
1710
+ // Arguments:
1711
+ // sourceSig - original call signature
1712
+ // targetSig - new call signature
1713
+ // transformation - transformations performed on the original signature
1714
+ //
1715
+ // Return Value:
1716
+ // Whether it's safe to change the IR to call the target method
1717
+ //
1718
+ bool Compiler::impCanSubstituteSig (CORINFO_SIG_INFO* sourceSig, CORINFO_SIG_INFO* targetSig, SigTransform transformation)
1719
+ {
1720
+ const SigTransform thisChangeMask = (SigTransform)(SigTransform::DeleteThis | SigTransform::ReplaceRefThis);
1721
+ assert ((transformation & thisChangeMask) != thisChangeMask);
1722
+
1723
+ if (sourceSig->getCallConv () != targetSig->getCallConv ())
1724
+ {
1725
+ JITDUMP (" impCanSubstituteSig returning false - call conv %u != %u\n " , sourceSig->callConv , targetSig->callConv );
1726
+ return false ;
1727
+ }
1728
+
1729
+ unsigned sourceArgCount = sourceSig->numArgs ;
1730
+ if ((transformation & SigTransform::DeleteThis) != 0 )
1731
+ {
1732
+ sourceArgCount--;
1733
+ }
1734
+
1735
+ if (sourceArgCount != targetSig->numArgs )
1736
+ {
1737
+ JITDUMP (" impCanSubstituteSig returning false - args count %u != %u\n " , sourceArgCount, targetSig->numArgs );
1738
+ return false ;
1739
+ }
1740
+
1741
+ if (sourceSig->retType != targetSig->retType )
1742
+ {
1743
+ JITDUMP (" impCanSubstituteSig returning false - return type %u != %u\n " ,
1744
+ (unsigned )sourceSig->retType , (unsigned )targetSig->retType );
1745
+ return false ;
1746
+ }
1747
+
1748
+ if (sourceSig->retType == CORINFO_TYPE_VALUECLASS || sourceSig->retType == CORINFO_TYPE_REFANY)
1749
+ {
1750
+ ClassLayout* layoutRetA = typGetObjLayout (sourceSig->retTypeClass );
1751
+ ClassLayout* layoutRetB = typGetObjLayout (targetSig->retTypeClass );
1752
+
1753
+ if (!ClassLayout::AreCompatible (layoutRetA, layoutRetB))
1754
+ {
1755
+ JITDUMP (" impCanSubstituteSig returning false - return type %u is incompatible with %u\n " ,
1756
+ (unsigned )sourceSig->retType , (unsigned )targetSig->retType );
1757
+ return false ;
1758
+ }
1759
+ }
1760
+
1761
+ CORINFO_ARG_LIST_HANDLE sourceArg = sourceSig->args ;
1762
+ CORINFO_ARG_LIST_HANDLE targetArg = targetSig->args ;
1763
+
1764
+ assert ((transformation & (SigTransform::DeleteThis | SigTransform::ReplaceRefThis)) == 0 ||
1765
+ eeGetArgType (sourceArg, sourceSig) == TYP_REF);
1766
+
1767
+ if ((transformation & SigTransform::DeleteThis) != 0 )
1768
+ {
1769
+ sourceArg = info.compCompHnd ->getArgNext (sourceArg);
1770
+ }
1771
+
1772
+ if ((transformation & SigTransform::ReplaceRefThis) != 0 && eeGetArgType (targetArg, targetSig) != TYP_REF)
1773
+ {
1774
+ JITDUMP (" impCanSubstituteSig returning false - this is not TYP_REF\n " );
1775
+ return false ;
1776
+ }
1777
+
1778
+ for (unsigned i = 0 ; i < targetSig->numArgs ; i++,
1779
+ sourceArg = info.compCompHnd ->getArgNext (sourceArg),
1780
+ targetArg = info.compCompHnd ->getArgNext (targetArg))
1781
+ {
1782
+ var_types sourceType = eeGetArgType (sourceArg, sourceSig);
1783
+ var_types targetType = eeGetArgType (targetArg, targetSig);
1784
+ if (sourceType != targetType)
1785
+ {
1786
+ JITDUMP (" impCanSubstituteSig returning false - parameter %u type %s != %s\n " ,
1787
+ i, varTypeName (sourceType), varTypeName (targetType));
1788
+ return false ;
1789
+ }
1790
+
1791
+ if (varTypeIsStruct (sourceType) && varTypeIsStruct (targetType))
1792
+ {
1793
+ CORINFO_CLASS_HANDLE sourceClassHnd = NO_CLASS_HANDLE;
1794
+ CORINFO_CLASS_HANDLE targetClassHnd = NO_CLASS_HANDLE;
1795
+ info.compCompHnd ->getArgType (sourceSig, sourceArg, &sourceClassHnd);
1796
+ info.compCompHnd ->getArgType (targetSig, targetArg, &targetClassHnd);
1797
+
1798
+ ClassLayout* sourceLayout = typGetObjLayout (sourceClassHnd);
1799
+ ClassLayout* targetLayout = typGetObjLayout (targetClassHnd);
1800
+
1801
+ if (!ClassLayout::AreCompatible (sourceLayout, targetLayout))
1802
+ {
1803
+ JITDUMP (" impCanSubstituteSig returning false - parameter %u type %s is inconmpatible with %s\n " ,
1804
+ i, varTypeName (sourceType), varTypeName (targetType));
1805
+ return false ;
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ return true ;
1811
+ }
1812
+
1625
1813
GenTreeCall* Compiler::impImportIndirectCall (CORINFO_SIG_INFO* sig, const DebugInfo& di)
1626
1814
{
1627
1815
var_types callRetTyp = JITtype2varType (sig->retType );
0 commit comments