// Its basic meaning is that shared generic methods always need instantiating
// stubs as the shared generic code needs the method dictionary parameter that cannot
// be provided by other means.
- useInstantiatingStub = originalMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstMethodDescArg();
+ useInstantiatingStub = originalMethod.OwningType.IsArray || originalMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstMethodDescArg();
callerMethod = HandleToObject(callerHandle);
}
methodToCall = targetMethod;
- MethodDesc canonMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
+ bool isArrayConstructor = targetMethod.OwningType.IsArray && targetMethod.IsConstructor;
+ MethodDesc canonMethod = (isArrayConstructor ? null : targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
if (directCall)
{
bool allowInstParam = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ALLOWINSTPARAM) != 0;
- if (!allowInstParam && canonMethod.RequiresInstArg())
+ if (!allowInstParam && canonMethod != null && canonMethod.RequiresInstArg())
{
useInstantiatingStub = true;
}
const CORINFO_CALLINFO_FLAGS LdVirtFtnMask = CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN | CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT;
bool unresolvedLdVirtFtn = ((flags & LdVirtFtnMask) == LdVirtFtnMask) && !resolvedCallVirt;
- if ((pResult->exactContextNeedsRuntimeLookup && useInstantiatingStub && (!allowInstParam || resolvedConstraint)) || forceUseRuntimeLookup)
+ if (isArrayConstructor)
+ {
+ // Constructors on arrays are special and don't actually have entrypoints.
+ // That would be fine by itself and wouldn't need special casing. But
+ // constructors on SzArray have a weird property that causes them not to have canonical forms.
+ // int[][] has a .ctor(int32,int32) to construct the jagged array in one go, but its canonical
+ // form of __Canon[] doesn't have the two-parameter constructor. The canonical form would need
+ // to have an unlimited number of constructors to cover stuff like "int[][][][][][]..."
+ pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL;
+ }
+ else if ((pResult->exactContextNeedsRuntimeLookup && useInstantiatingStub && (!allowInstParam || resolvedConstraint)) || forceUseRuntimeLookup)
{
if (unresolvedLdVirtFtn)
{
if (allowInstParam)
{
useInstantiatingStub = false;
- methodToCall = canonMethod;
+ methodToCall = canonMethod ?? methodToCall;
}
pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL;
nonUnboxingMethod = rawPinvoke.Target;
}
- // READYTORUN: FUTURE: Direct calls if possible
- pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
- _compilation.NodeFactory.MethodEntrypoint(
- ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub),
- isInstantiatingStub: useInstantiatingStub,
- isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0));
+ if (methodToCall.OwningType.IsArray && methodToCall.IsConstructor)
+ {
+ pResult->codePointerOrStubLookup.constLookup = default;
+ }
+ else
+ {
+ // READYTORUN: FUTURE: Direct calls if possible
+ pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
+ _compilation.NodeFactory.MethodEntrypoint(
+ ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub),
+ isInstantiatingStub: useInstantiatingStub,
+ isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0));
+ }
// If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException
UpdateConstLookupWithRequiresRuntimeJitSymbolIfNeeded(ref pResult->codePointerOrStubLookup.constLookup, targetMethod);