Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <michals@microsoft.com>2015-11-10 05:45:46 +0300
committerMichal Strehovský <michals@microsoft.com>2015-11-10 22:44:07 +0300
commit6956622dbbcda664a6ad7b6a00d870cb3a0f5f97 (patch)
tree84dc3ec0f38d15f2e13d1946792b92f3fb4729e7 /src/JitInterface
parent137a6cf6dd75d53ca8a45c44d05d2e16c820ed15 (diff)
Add support for constrained method calls
This should be complete for the set of scenarios we can currently encounter (no shared generics). * Port of TryResolveConstraintMethodApprox from NUTC/CoreCLR. This is the part that will need to be extended for shared generics. I think I managed to come up with an assert that will trigger when the time is right to update the logic. * Necessary changes on the JitInterface side * Implement UncheckedCast in the BCL (I hit this since my fix started pulling in 30% more methods for hello world). I'm not checking in a change to allow compiling the extra methods that we now support (change to _skipJitList in Compilation.cs). This is because I don't want to spend time updating the list for Linux Hello World.
Diffstat (limited to 'src/JitInterface')
-rw-r--r--src/JitInterface/src/CorInfoImpl.cs143
1 files changed, 124 insertions, 19 deletions
diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs
index 6831c9d39..64f2bec75 100644
--- a/src/JitInterface/src/CorInfoImpl.cs
+++ b/src/JitInterface/src/CorInfoImpl.cs
@@ -1562,31 +1562,134 @@ namespace Internal.JitInterface
void getCallInfo(IntPtr _this, ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, ref CORINFO_CALL_INFO pResult)
{
- // TODO: Constrained calls
- if (pConstrainedResolvedToken != null)
- throw new NotImplementedException();
-
+#if DEBUG
+ // In debug, write some bogus data to the struct to ensure we have filled everything
+ // properly.
+ fixed (CORINFO_CALL_INFO* tmp = &pResult)
+ MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf<CORINFO_CALL_INFO>());
+#endif
MethodDesc method = HandleToObject(pResolvedToken.hMethod);
+ // Spec says that a callvirt lookup ignores static methods. Since static methods
+ // can't have the exact same signature as instance methods, a lookup that found
+ // a static method would have never found an instance method.
+ if (method.Signature.IsStatic && (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) != 0)
+ {
+ throw new BadImageFormatException();
+ }
+
+ TypeDesc exactType = HandleToObject(pResolvedToken.hClass);
+
+ TypeDesc constrainedType = null;
+ if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) != 0 && pConstrainedResolvedToken != null)
+ {
+ constrainedType = HandleToObject(pConstrainedResolvedToken->hClass);
+ }
+
+ bool resolvedConstraint = false;
+ bool forceUseRuntimeLookup = false;
+
+ MethodDesc methodAfterConstraintResolution = method;
+ if (constrainedType == null)
+ {
+ pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
+ }
+ else
+ {
+ // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
+ // will not necessarily resolve the call exactly, since we might be compiling
+ // shared generic code - it may just resolve it to a candidate suitable for
+ // JIT compilation, and require a runtime lookup for the actual code pointer
+ // to call.
+
+ MethodDesc directMethod = constrainedType.GetClosestMetadataType().TryResolveConstraintMethodApprox(exactType, method, out forceUseRuntimeLookup);
+ if (directMethod != null)
+ {
+ // Either
+ // 1. no constraint resolution at compile time (!directMethod)
+ // OR 2. no code sharing lookup in call
+ // OR 3. we have have resolved to an instantiating stub
+
+ methodAfterConstraintResolution = directMethod;
+
+ Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface);
+ resolvedConstraint = true;
+ pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
+
+ exactType = constrainedType;
+ }
+ else if (constrainedType.IsValueType)
+ {
+ pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_BOX_THIS;
+ }
+ else
+ {
+ pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_DEREF_THIS;
+ }
+ }
+
+ MethodDesc targetMethod = methodAfterConstraintResolution;
+
+ //
+ // Determine whether to perform direct call
+ //
+
+ bool directCall = false;
+ bool resolvedCallVirt = false;
+
+ if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0)
+ {
+ // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
+ directCall = true;
+ }
+ else if (targetMethod.Signature.IsStatic)
+ {
+ // Static methods are always direct calls
+ directCall = true;
+ }
+ else if (targetMethod.OwningType.IsInterface)
+ {
+ // Force all interface calls to be interpreted as if they are virtual.
+ directCall = false;
+ }
+ else if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) == 0 || resolvedConstraint)
+ {
+ directCall = true;
+ }
+ else
+ {
+ if (!targetMethod.IsVirtual || targetMethod.IsFinal || targetMethod.OwningType.GetClosestMetadataType().IsSealed)
+ {
+ resolvedCallVirt = true;
+ directCall = true;
+ }
+ }
+
// TODO: Interface methods
- if (method.IsVirtual && method.OwningType.IsInterface)
+ if (targetMethod.IsVirtual && targetMethod.OwningType.IsInterface)
throw new NotImplementedException();
- pResult.hMethod = pResolvedToken.hMethod;
- pResult.methodFlags = getMethodAttribsInternal(method);
+ pResult.hMethod = ObjectToHandle(targetMethod);
+ pResult.methodFlags = getMethodAttribsInternal(targetMethod);
- pResult.classFlags = getClassAttribsInternal(method.OwningType);
+ pResult.classFlags = getClassAttribsInternal(targetMethod.OwningType);
- Get_CORINFO_SIG_INFO(method.Signature, out pResult.sig);
+ Get_CORINFO_SIG_INFO(targetMethod.Signature, out pResult.sig);
- pResult.verMethodFlags = pResult.methodFlags;
- pResult.verSig = pResult.sig;
+ // Get the required verification information in case it is needed by the verifier later
+ if (pResult.hMethod != pResolvedToken.hMethod)
+ {
+ pResult.verMethodFlags = getMethodAttribsInternal(targetMethod);
+ Get_CORINFO_SIG_INFO(targetMethod.Signature, out pResult.verSig);
+ }
+ else
+ {
+ pResult.verMethodFlags = pResult.methodFlags;
+ pResult.verSig = pResult.sig;
+ }
pResult.accessAllowed = CorInfoIsAccessAllowedResult.CORINFO_ACCESS_ALLOWED;
- // TODO: Constraint calls
- pResult.thisTransform = CORINFO_THIS_TRANSFORM.CORINFO_NO_THIS_TRANSFORM;
-
pResult.kind = CORINFO_CALL_KIND.CORINFO_CALL;
pResult._nullInstanceCheck = (uint)(((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) != 0) ? 1 : 0);
@@ -1598,10 +1701,10 @@ namespace Internal.JitInterface
// TODO: CORINFO_CALL_CODE_POINTER
pResult.codePointerOrStubLookup.constLookup.accessType = InfoAccessType.IAT_VALUE;
- if (((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT) != 0) && method.IsVirtual)
+ if (!directCall)
{
pResult.codePointerOrStubLookup.constLookup.addr =
- (void *)ObjectToHandle(_compilation.GetReadyToRunHelper(ReadyToRunHelperId.VirtualCall, method));
+ (void *)ObjectToHandle(_compilation.GetReadyToRunHelper(ReadyToRunHelperId.VirtualCall, targetMethod));
if ((pResult.methodFlags & (uint)CorInfoFlag.CORINFO_FLG_DELEGATE_INVOKE) != 0)
{
@@ -1610,16 +1713,18 @@ namespace Internal.JitInterface
}
else
{
- if (method.IsConstructor && method.OwningType.IsString)
+ if (targetMethod.IsConstructor && targetMethod.OwningType.IsString)
{
// Calling a string constructor doesn't call the actual constructor.
- var initMethod = IntrinsicMethods.GetStringInitializer(method);
+ var initMethod = IntrinsicMethods.GetStringInitializer(targetMethod);
pResult.codePointerOrStubLookup.constLookup.addr = ObjectToHandle(initMethod);
}
else
{
- pResult.codePointerOrStubLookup.constLookup.addr = pResolvedToken.hMethod;
+ pResult.codePointerOrStubLookup.constLookup.addr = pResult.hMethod;
}
+
+ pResult.nullInstanceCheck = resolvedCallVirt;
}
// TODO: Generics