diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index 6b5c0e14764..f33185e4fc3 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -182,6 +182,118 @@ public bool HasFixedSlotVTable(TypeDesc type) return NodeFactory.VTable(type).HasFixedSlots; } + public bool NeedsRuntimeLookup(ReadyToRunHelperId lookupKind, object targetOfLookup) + { + switch (lookupKind) + { + case ReadyToRunHelperId.TypeHandle: + case ReadyToRunHelperId.NecessaryTypeHandle: + case ReadyToRunHelperId.DefaultConstructor: + return ((TypeDesc)targetOfLookup).IsRuntimeDeterminedSubtype; + + case ReadyToRunHelperId.MethodDictionary: + case ReadyToRunHelperId.MethodEntry: + case ReadyToRunHelperId.VirtualDispatchCell: + case ReadyToRunHelperId.MethodHandle: + return ((MethodDesc)targetOfLookup).IsRuntimeDeterminedExactMethod; + + case ReadyToRunHelperId.FieldHandle: + return ((FieldDesc)targetOfLookup).OwningType.IsRuntimeDeterminedSubtype; + + default: + throw new NotImplementedException(); + } + } + + public ISymbolNode ComputeConstantLookup(ReadyToRunHelperId lookupKind, object targetOfLookup) + { + switch (lookupKind) + { + case ReadyToRunHelperId.TypeHandle: + return NodeFactory.ConstructedTypeSymbol((TypeDesc)targetOfLookup); + case ReadyToRunHelperId.NecessaryTypeHandle: + return NodeFactory.NecessaryTypeSymbol((TypeDesc)targetOfLookup); + case ReadyToRunHelperId.MethodDictionary: + return NodeFactory.MethodGenericDictionary((MethodDesc)targetOfLookup); + case ReadyToRunHelperId.MethodEntry: + return NodeFactory.FatFunctionPointer((MethodDesc)targetOfLookup); + case ReadyToRunHelperId.MethodHandle: + return NodeFactory.RuntimeMethodHandle((MethodDesc)targetOfLookup); + case ReadyToRunHelperId.FieldHandle: + return NodeFactory.RuntimeFieldHandle((FieldDesc)targetOfLookup); + case ReadyToRunHelperId.DefaultConstructor: + { + var type = (TypeDesc)targetOfLookup; + MethodDesc ctor = type.GetDefaultConstructor(); + if (ctor == null) + { + MetadataType activatorType = TypeSystemContext.SystemModule.GetKnownType("System", "Activator"); + MetadataType classWithMissingCtor = activatorType.GetKnownNestedType("ClassWithMissingConstructor"); + ctor = classWithMissingCtor.GetParameterlessConstructor(); + } + return NodeFactory.CanonicalEntrypoint(ctor); + } + + default: + throw new NotImplementedException(); + } + } + + public GenericDictionaryLookup ComputeGenericLookup(MethodDesc contextMethod, ReadyToRunHelperId lookupKind, object targetOfLookup) + { + GenericContextSource contextSource; + + if (contextMethod.RequiresInstMethodDescArg()) + { + contextSource = GenericContextSource.MethodParameter; + } + else if (contextMethod.RequiresInstMethodTableArg()) + { + contextSource = GenericContextSource.TypeParameter; + } + else + { + Debug.Assert(contextMethod.AcquiresInstMethodTableFromThis()); + contextSource = GenericContextSource.ThisObject; + } + + // Can we do a fixed lookup? Start by checking if we can get to the dictionary. + // Context source having a vtable with fixed slots is a prerequisite. + if (contextSource == GenericContextSource.MethodParameter + || HasFixedSlotVTable(contextMethod.OwningType)) + { + DictionaryLayoutNode dictionaryLayout; + if (contextSource == GenericContextSource.MethodParameter) + dictionaryLayout = _nodeFactory.GenericDictionaryLayout(contextMethod); + else + dictionaryLayout = _nodeFactory.GenericDictionaryLayout(contextMethod.OwningType); + + // If the dictionary layout has fixed slots, we can compute the lookup now. Otherwise defer to helper. + if (dictionaryLayout.HasFixedSlots) + { + int pointerSize = _nodeFactory.Target.PointerSize; + + GenericLookupResult lookup = ReadyToRunGenericHelperNode.GetLookupSignature(_nodeFactory, lookupKind, targetOfLookup); + int dictionarySlot = dictionaryLayout.GetSlotForEntry(lookup); + int dictionaryOffset = dictionarySlot * pointerSize; + + if (contextSource == GenericContextSource.MethodParameter) + { + return GenericDictionaryLookup.CreateFixedLookup(contextSource, dictionaryOffset); + } + else + { + int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(_nodeFactory, contextMethod.OwningType); + int vtableOffset = EETypeNode.GetVTableOffset(pointerSize) + vtableSlot * pointerSize; + return GenericDictionaryLookup.CreateFixedLookup(contextSource, vtableOffset, dictionaryOffset); + } + } + } + + // Fixed lookup not possible - use helper. + return GenericDictionaryLookup.CreateHelperLookup(contextSource); + } + CompilationResults ICompilation.Compile(string outputFile, ObjectDumper dumper) { if (dumper != null) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs index d455326eab2..b85027a02ef 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunGenericHelperNode.cs @@ -29,8 +29,11 @@ public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helpe _lookupSignature = GetLookupSignature(factory, helperId, target); } - private static GenericLookupResult GetLookupSignature(NodeFactory factory, ReadyToRunHelperId id, object target) + public static GenericLookupResult GetLookupSignature(NodeFactory factory, ReadyToRunHelperId id, object target) { + // Necessary type handle is not something you can put in a dictionary - someone should have normalized to TypeHandle + Debug.Assert(id != ReadyToRunHelperId.NecessaryTypeHandle); + switch (id) { case ReadyToRunHelperId.TypeHandle: diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs index d3795b96d39..94671a88f45 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ReadyToRunHelperNode.cs @@ -27,6 +27,7 @@ public enum ReadyToRunHelperId // The following helpers are used for generic lookups only TypeHandle, + NecessaryTypeHandle, MethodHandle, FieldHandle, MethodDictionary, diff --git a/src/ILCompiler.Compiler/src/Compiler/GenericDictionaryLookup.cs b/src/ILCompiler.Compiler/src/Compiler/GenericDictionaryLookup.cs new file mode 100644 index 00000000000..42c7deee73c --- /dev/null +++ b/src/ILCompiler.Compiler/src/Compiler/GenericDictionaryLookup.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +using Debug = System.Diagnostics.Debug; + +namespace ILCompiler +{ + /// + /// Structure that specifies how a generic dictionary lookup should be performed. + /// + public struct GenericDictionaryLookup + { + private const short UseHelperOffset = -1; + + private short _offset1; + private short _offset2; + + public readonly GenericContextSource ContextSource; + + public bool UseHelper + { + get + { + return _offset1 == UseHelperOffset; + } + } + + public int NumberOfIndirections + { + get + { + Debug.Assert(!UseHelper); + return ContextSource == GenericContextSource.MethodParameter ? 1 : 2; + } + } + + public int this[int index] + { + get + { + Debug.Assert(!UseHelper); + Debug.Assert(index < NumberOfIndirections); + switch (index) + { + case 0: + return _offset1; + case 1: + return _offset2; + } + + // Should be unreachable. + throw new NotSupportedException(); + } + } + + private GenericDictionaryLookup(GenericContextSource contextSource, int offset1, int offset2) + { + ContextSource = contextSource; + _offset1 = checked((short)offset1); + _offset2 = checked((short)offset2); + } + + public static GenericDictionaryLookup CreateFixedLookup(GenericContextSource contextSource, int offset1, int offset2 = UseHelperOffset) + { + Debug.Assert(offset1 != UseHelperOffset); + return new GenericDictionaryLookup(contextSource, offset1, offset2); + } + + public static GenericDictionaryLookup CreateHelperLookup(GenericContextSource contextSource) + { + return new GenericDictionaryLookup(contextSource, UseHelperOffset, UseHelperOffset); + } + } + + /// + /// Specifies to source of the generic context. + /// + public enum GenericContextSource + { + /// + /// Generic context is specified by a hidden parameter that has a method dictionary. + /// + MethodParameter, + + /// + /// Generic context is specified by a hidden parameter that has a type. + /// + TypeParameter, + + /// + /// Generic context is specified implicitly by the `this` object. + /// + ThisObject, + } +} diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj index 47fdf19c403..b5352997c71 100644 --- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj +++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj @@ -262,6 +262,7 @@ + diff --git a/src/JitInterface/src/CorInfoImpl.cs b/src/JitInterface/src/CorInfoImpl.cs index ebfb2ecce1e..70585ca1742 100644 --- a/src/JitInterface/src/CorInfoImpl.cs +++ b/src/JitInterface/src/CorInfoImpl.cs @@ -867,64 +867,78 @@ private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offs return impl != null ? ObjectToHandle(impl) : null; } - private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) + private void ComputeLookup(CORINFO_CONTEXT_STRUCT* pContextMethod, object entity, ReadyToRunHelperId helperId, ref CORINFO_LOOKUP lookup) { - // Resolved token as a potentially RuntimeDetermined object. - MethodDesc method = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); - - if (method.IsRuntimeDeterminedExactMethod) + if (_compilation.NeedsRuntimeLookup(helperId, entity)) { - pResult.lookup.lookupKind.needsRuntimeLookup = true; - pResult.lookup.runtimeLookup.signature = null; - pResult.lookup.runtimeLookup.indirections = CORINFO.USEHELPER; + lookup.lookupKind.needsRuntimeLookup = true; + lookup.runtimeLookup.signature = null; - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); + MethodDesc contextMethod = methodFromContext(pContextMethod); // Do not bother computing the runtime lookup if we are inlining. The JIT is going // to abort the inlining attempt anyway. - if (contextMethod == MethodBeingCompiled) + if (contextMethod != MethodBeingCompiled) + return; + + // Necessary type handle is not something that can be in a dictionary (only a constructed type). + // We only use necessary type handles if we can do a constant lookup. + if (helperId == ReadyToRunHelperId.NecessaryTypeHandle) + helperId = ReadyToRunHelperId.TypeHandle; + + GenericDictionaryLookup genericLookup = _compilation.ComputeGenericLookup(contextMethod, helperId, entity); + + if (genericLookup.UseHelper) { - switch (method.Name) + lookup.runtimeLookup.indirections = CORINFO.USEHELPER; + lookup.lookupKind.runtimeLookupFlags = (ushort)helperId; + lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(entity); + } + else + { + if (genericLookup.ContextSource == GenericContextSource.MethodParameter) + { + lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_METHOD; + } + else { - case "EETypePtrOf": - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.TypeHandle; - pResult.lookup.lookupKind.runtimeLookupArgs = ObjectToHandle(method.Instantiation[0]); - break; - case "DefaultConstructorOf": - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.DefaultConstructor; - pResult.lookup.lookupKind.runtimeLookupArgs = ObjectToHandle(method.Instantiation[0]); - break; - default: - Debug.Assert(false); - break; + lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_CLASS; } - pResult.lookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); + lookup.runtimeLookup.indirections = (ushort)genericLookup.NumberOfIndirections; + lookup.runtimeLookup.offset0 = (IntPtr)genericLookup[0]; + if (genericLookup.NumberOfIndirections > 1) + lookup.runtimeLookup.offset1 = (IntPtr)genericLookup[1]; + lookup.runtimeLookup.testForFixup = false; // TODO: this will be needed in true multifile + lookup.runtimeLookup.testForNull = false; + lookup.runtimeLookup.indirectFirstOffset = false; + lookup.lookupKind.runtimeLookupFlags = 0; + lookup.lookupKind.runtimeLookupArgs = null; } + + lookup.lookupKind.runtimeLookupKind = GetLookupKindFromContextSource(genericLookup.ContextSource); } else { - pResult.lookup.lookupKind.needsRuntimeLookup = false; - - switch (method.Name) - { - case "EETypePtrOf": - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(method.Instantiation[0])); - break; - case "DefaultConstructorOf": - MethodDesc ctor = method.Instantiation[0].GetDefaultConstructor(); - if (ctor == null) - { - MetadataType activatorType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "Activator"); - MetadataType classWithMissingCtor = activatorType.GetKnownNestedType("ClassWithMissingConstructor"); - ctor = classWithMissingCtor.GetParameterlessConstructor(); - } - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.CanonicalEntrypoint(ctor)); - break; - default: - Debug.Assert(false); - break; - } + lookup.lookupKind.needsRuntimeLookup = false; + ISymbolNode constLookup = _compilation.ComputeConstantLookup(helperId, entity); + lookup.constLookup = CreateConstLookupToSymbol(constLookup); + } + } + + private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + // Resolved token as a potentially RuntimeDetermined object. + MethodDesc method = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pResolvedToken); + + switch (method.Name) + { + case "EETypePtrOf": + ComputeLookup(pResolvedToken.tokenContext, method.Instantiation[0], ReadyToRunHelperId.TypeHandle, ref pResult.lookup); + break; + case "DefaultConstructorOf": + ComputeLookup(pResolvedToken.tokenContext, method.Instantiation[0], ReadyToRunHelperId.DefaultConstructor, ref pResult.lookup); + break; } } @@ -1497,6 +1511,11 @@ private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) private ISymbolNode GetGenericLookupHelper(CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind, ReadyToRunHelperId helperId, object helperArgument) { + // Necessary type handle is not something that can be in a dictionary (only a constructed type). + // We only use necessary type handles if we can do a constant lookup. + if (helperId == ReadyToRunHelperId.NecessaryTypeHandle) + helperId = ReadyToRunHelperId.TypeHandle; + if (runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ || runtimeLookupKind == CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM) { @@ -2605,7 +2624,8 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fixed (CORINFO_GENERICHANDLE_RESULT* tmp = &pResult) MemoryHelper.FillMemory((byte*)tmp, 0xcc, Marshal.SizeOf()); #endif - bool runtimeLookup; + ReadyToRunHelperId helperId = ReadyToRunHelperId.Invalid; + object target = null; if (!fEmbedParent && pResolvedToken.hMethod != null) { @@ -2616,28 +2636,17 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool Debug.Assert(md.OwningType == td); - runtimeLookup = md.IsSharedByGenericInstantiations; - pResult.compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)ObjectToHandle(md); - if (!runtimeLookup) - { - if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken) - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.RuntimeMethodHandle(md)); - else - throw new NotImplementedException(); - } + if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken) + helperId = ReadyToRunHelperId.MethodHandle; else { - if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken) - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodHandle; - else if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Method) - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodDictionary; - else - throw new NotImplementedException(); - - pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); + Debug.Assert(pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Method); + helperId = ReadyToRunHelperId.MethodDictionary; } + + target = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); } else if (!fEmbedParent && pResolvedToken.hField != null) { @@ -2647,19 +2656,9 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool pResult.handleType = CorInfoGenericHandleType.CORINFO_HANDLETYPE_FIELD; pResult.compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)pResolvedToken.hField; - runtimeLookup = fd.IsStatic && td.IsCanonicalSubtype(CanonicalFormKind.Any); - - if (!runtimeLookup) - { - Debug.Assert(pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken); - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.RuntimeFieldHandle(fd)); - } - else - { - Debug.Assert(pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken); - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.FieldHandle; - pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); - } + Debug.Assert(pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken); + helperId = ReadyToRunHelperId.FieldHandle; + target = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); } else { @@ -2668,69 +2667,38 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool pResult.handleType = CorInfoGenericHandleType.CORINFO_HANDLETYPE_CLASS; pResult.compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)pResolvedToken.hClass; - runtimeLookup = td.IsCanonicalSubtype(CanonicalFormKind.Any); - - if (!runtimeLookup) + object obj = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); + target = obj as TypeDesc; + if (target == null) { - if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_NewObj - || pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Box - || (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken && ConstructedEETypeNode.CreationAllowed(td))) + Debug.Assert(fEmbedParent); + + if (obj is MethodDesc) { - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(td)); + target = ((MethodDesc)obj).OwningType; } else { - pResult.lookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.NecessaryTypeSymbol(td)); + Debug.Assert(obj is FieldDesc); + target = ((FieldDesc)obj).OwningType; } } + + if (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_NewObj + || pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Box + || (pResolvedToken.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldtoken && ConstructedEETypeNode.CreationAllowed(td))) + { + helperId = ReadyToRunHelperId.TypeHandle; + } else { - pResult.lookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.TypeHandle; - - object obj = GetRuntimeDeterminedObjectForToken(ref pResolvedToken); - TypeDesc type = obj as TypeDesc; - if (type == null) - { - Debug.Assert(fEmbedParent); - - if (obj is MethodDesc) - { - type = ((MethodDesc)obj).OwningType; - } - else - { - Debug.Assert(obj is FieldDesc); - type = ((FieldDesc)obj).OwningType; - } - } - - pResult.lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(type); + helperId = ReadyToRunHelperId.NecessaryTypeHandle; } } Debug.Assert(pResult.compileTimeHandle != null); - - if (runtimeLookup) - { - pResult.lookup.lookupKind.needsRuntimeLookup = true; - pResult.lookup.runtimeLookup.signature = null; - pResult.lookup.runtimeLookup.indirections = CORINFO.USEHELPER; - - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); - - // Do not bother computing the runtime lookup if we are inlining. The JIT is going - // to abort the inlining attempt anyway. - if (contextMethod != MethodBeingCompiled) - return; - - pResult.lookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); - } - else - { - // If the target is not shared then we've already got our result and - // can simply do a static look up - pResult.lookup.lookupKind.needsRuntimeLookup = false; - } + + ComputeLookup(pResolvedToken.tokenContext, target, helperId, ref pResult.lookup); } private CORINFO_RUNTIME_LOOKUP_KIND GetGenericRuntimeLookupKind(MethodDesc method) @@ -2746,6 +2714,20 @@ private CORINFO_RUNTIME_LOOKUP_KIND GetGenericRuntimeLookupKind(MethodDesc metho } } + private CORINFO_RUNTIME_LOOKUP_KIND GetLookupKindFromContextSource(GenericContextSource contextSource) + { + switch (contextSource) + { + case GenericContextSource.MethodParameter: + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM; + case GenericContextSource.TypeParameter: + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM; + default: + Debug.Assert(contextSource == GenericContextSource.ThisObject); + return CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ; + } + } + private void getLocationOfThisType(out CORINFO_LOOKUP_KIND result, CORINFO_METHOD_STRUCT_* context) { result = new CORINFO_LOOKUP_KIND(); @@ -3078,18 +3060,11 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO if (pResult.exactContextNeedsRuntimeLookup) { - pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true; - pResult.codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER; - - // Do not bother computing the runtime lookup if we are inlining. The JIT is going - // to abort the inlining attempt anyway. - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); - if (contextMethod == MethodBeingCompiled) - { - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.MethodHandle; - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); - } + ComputeLookup(pResolvedToken.tokenContext, + GetRuntimeDeterminedObjectForToken(ref pResolvedToken), + ReadyToRunHelperId.MethodHandle, + ref pResult.codePointerOrStubLookup); + Debug.Assert(pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup); } // RyuJIT will assert if we report CORINFO_CALLCONV_PARAMTYPE for a result of a ldvirtftn @@ -3104,18 +3079,11 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO if (pResult.exactContextNeedsRuntimeLookup) { - pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup = true; - pResult.codePointerOrStubLookup.runtimeLookup.indirections = CORINFO.USEHELPER; - - // Do not bother computing the runtime lookup if we are inlining. The JIT is going - // to abort the inlining attempt anyway. - MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext); - if (contextMethod == MethodBeingCompiled) - { - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod); - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.VirtualDispatchCell; - pResult.codePointerOrStubLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(GetRuntimeDeterminedObjectForToken(ref pResolvedToken)); - } + ComputeLookup(pResolvedToken.tokenContext, + GetRuntimeDeterminedObjectForToken(ref pResolvedToken), + ReadyToRunHelperId.VirtualDispatchCell, + ref pResult.codePointerOrStubLookup); + Debug.Assert(pResult.codePointerOrStubLookup.lookupKind.needsRuntimeLookup); } else { diff --git a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs index 212aa98b9e3..85eb8a03cd2 100644 --- a/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs +++ b/src/System.Private.Jit/src/Internal/Runtime/JitSupport/JitCompilation.cs @@ -102,6 +102,24 @@ public bool HasFixedSlotVTable(TypeDesc type) return true; } + public bool NeedsRuntimeLookup(ReadyToRunHelperId lookupKind, object targetOfLookup) + { + // The current plan seem to be to copy paste from ILCompiler.Compilation, but that's not a sustainable plan + throw new NotImplementedException(); + } + + public ISymbolNode ComputeConstantLookup(ReadyToRunHelperId lookupKind, object targetOfLookup) + { + // The current plan seem to be to copy paste from ILCompiler.Compilation, but that's not a sustainable plan + throw new NotImplementedException(); + } + + public GenericDictionaryLookup ComputeGenericLookup(MethodDesc contextMethod, ReadyToRunHelperId lookupKind, object targetOfLookup) + { + // The current plan seem to be to copy paste from ILCompiler.Compilation, but that's not a sustainable plan + throw new NotImplementedException(); + } + public DelegateCreationInfo GetDelegateCtor(TypeDesc delegateType, MethodDesc target, bool followVirtualDispatch) { return DelegateCreationInfo.Create(delegateType, target, NodeFactory, followVirtualDispatch); diff --git a/src/System.Private.Jit/src/System.Private.Jit.csproj b/src/System.Private.Jit/src/System.Private.Jit.csproj index e8a31aaf119..8d303aa3e60 100644 --- a/src/System.Private.Jit/src/System.Private.Jit.csproj +++ b/src/System.Private.Jit/src/System.Private.Jit.csproj @@ -116,6 +116,7 @@ +