@@ -49,6 +49,7 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE pC
49
49
typedef void * (*HELPER_FTN_PP)(void *);
50
50
typedef void * (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void *);
51
51
typedef Object* (*HELPER_FTN_NEWARR)(CORINFO_CLASS_HANDLE, intptr_t );
52
+ typedef Object* (*HELPER_FTN_NEW_MDARR)(CORINFO_CLASS_HANDLE, int , void *);
52
53
53
54
InterpThreadContext::InterpThreadContext ()
54
55
{
@@ -1118,22 +1119,35 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
1118
1119
// First execution of this call. Ensure target method is compiled and
1119
1120
// patch the data item slot with the actual method code.
1120
1121
MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_HANDLE_TAG);
1121
- PCODE code = pMD->GetNativeCode ();
1122
- if (!code) {
1123
- // This is an optimization to ensure that the stack walk will not have to search
1124
- // for the topmost frame in the current InterpExecMethod. It is not required
1125
- // for correctness, as the stack walk will find the topmost frame anyway. But it
1126
- // would need to seek through the frames to find it.
1127
- // An alternative approach would be to update the topmost frame during stack walk
1128
- // to make the probability that the next stack walk will need to search only a
1129
- // small subset of frames high.
1130
- pInterpreterFrame->SetTopInterpMethodContextFrame (pFrame);
1131
- GCX_PREEMP ();
1132
- pMD->PrepareInitialCode (CallerGCMode::Coop);
1133
- code = pMD->GetNativeCode ();
1122
+ if (pMD->IsArray () || pMD->IsFCall ())
1123
+ {
1124
+ // For FCalls and array special methods we can't go through the regular caching path
1125
+ // because it will try to do pMD->GetNativeCode() and then crash.
1126
+ PCODE code = pMD->TryGetMultiCallableAddrOfCode (CORINFO_ACCESS_ANY);
1127
+ assert (code);
1128
+ InvokeCompiledMethod (pMD, stack + callArgsOffset, stack + returnOffset, code);
1129
+ // FIXME: Caching in dataItems somehow
1130
+ break ;
1131
+ }
1132
+ else
1133
+ {
1134
+ PCODE code = pMD->GetNativeCode ();
1135
+ if (!code) {
1136
+ // This is an optimization to ensure that the stack walk will not have to search
1137
+ // for the topmost frame in the current InterpExecMethod. It is not required
1138
+ // for correctness, as the stack walk will find the topmost frame anyway. But it
1139
+ // would need to seek through the frames to find it.
1140
+ // An alternative approach would be to update the topmost frame during stack walk
1141
+ // to make the probability that the next stack walk will need to search only a
1142
+ // small subset of frames high.
1143
+ pInterpreterFrame->SetTopInterpMethodContextFrame (pFrame);
1144
+ GCX_PREEMP ();
1145
+ pMD->PrepareInitialCode (CallerGCMode::Coop);
1146
+ code = pMD->GetNativeCode ();
1147
+ }
1148
+ pMethod->pDataItems [methodSlot] = (void *)code;
1149
+ targetIp = (const int32_t *)code;
1134
1150
}
1135
- pMethod->pDataItems [methodSlot] = (void *)code;
1136
- targetIp = (const int32_t *)code;
1137
1151
}
1138
1152
else
1139
1153
{
@@ -1204,14 +1218,39 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
1204
1218
LOCAL_VAR (callArgsOffset, void *) = nullptr ; // and zero it too! it might get scanned by the GC.
1205
1219
callArgsOffset += sizeof (StackVal);
1206
1220
1207
- // Get the address of the fcall that implements the ctor
1208
- PCODE code = pMD->TryGetMultiCallableAddrOfCode (CORINFO_ACCESS_ANY);
1209
- assert (code);
1221
+ if (pClass->IsArray ())
1222
+ {
1223
+ // mdarray ctors are implemented via a helper ftn we grabbed at compile time
1224
+ size_t helperDirectOrIndirect = (size_t )pMethod->pDataItems [ip[5 ]];
1225
+ HELPER_FTN_NEW_MDARR helper = nullptr ;
1226
+ if (helperDirectOrIndirect & INTERP_INDIRECT_HELPER_TAG)
1227
+ helper = *(HELPER_FTN_NEW_MDARR *)(helperDirectOrIndirect & ~INTERP_INDIRECT_HELPER_TAG);
1228
+ else
1229
+ helper = (HELPER_FTN_NEW_MDARR)helperDirectOrIndirect;
1230
+ assert (helper);
1231
+
1232
+ // mdarray ctor wants an array of ints, we can't pass the callArgsOffset directly since
1233
+ // it's technically a stream of intptrs even if each value is an int
1234
+ int rank = pClass->GetRank ();
1235
+ int dims[8 ] = { 0 };
1236
+ assert (rank < 8 );
1237
+ for (int i = 0 ; i < rank; i++)
1238
+ dims[i] = LOCAL_VAR (callArgsOffset + (i * sizeof (StackVal)), int );
1239
+
1240
+ LOCAL_VAR (returnOffset, Object*) = helper ((CORINFO_CLASS_HANDLE)pClass, rank, dims);
1241
+ }
1242
+ else
1243
+ {
1244
+ // Get the address of the fcall that implements the ctor
1245
+ PCODE code = pMD->TryGetMultiCallableAddrOfCode (CORINFO_ACCESS_ANY);
1246
+ assert (code);
1247
+
1248
+ // callArgsOffset now only points to the ctor arguments, which are what the fcall expects.
1249
+ // returnOffset still points to where the new instance goes, and the fcall will write it there.
1250
+ InvokeCompiledMethod (pMD, stack + callArgsOffset, stack + returnOffset, code);
1251
+ }
1210
1252
1211
- // callArgsOffset now only points to the ctor arguments, which are what the fcall expects.
1212
- // returnOffset still points to where the new instance goes, and the fcall will write it there.
1213
- InvokeCompiledMethod (pMD, stack + callArgsOffset, stack + returnOffset, code);
1214
- ip += 5 ;
1253
+ ip += 6 ;
1215
1254
break ;
1216
1255
}
1217
1256
else
@@ -1222,7 +1261,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
1222
1261
LOCAL_VAR (returnOffset, OBJECTREF) = objRef;
1223
1262
// Set `this` arg for ctor call
1224
1263
LOCAL_VAR (callArgsOffset, OBJECTREF) = objRef;
1225
- ip += 5 ;
1264
+ ip += 6 ;
1226
1265
1227
1266
goto CALL_INTERP_SLOT;
1228
1267
}
0 commit comments