Adding Support for FieldDescSlot generic dictionary entries for R2R generic code...
authorFadi Hanna <fadim@microsoft.com>
Thu, 4 Aug 2016 01:00:49 +0000 (18:00 -0700)
committerGitHub <noreply@github.com>
Thu, 4 Aug 2016 01:00:49 +0000 (18:00 -0700)
This enables generic code with ldtoken instructions for fields on generic types to be compiled into R2R.

This change makes newer versions of the runtime compatible with older version R2R images,
but not vice-versa. Therefore, the major version is increased to 2 with this change.

This change adds more encodings to a R2R image without changing the format of any previously encoded
entity, and is backwards compatible.

Commit migrated from https://github.com/dotnet/coreclr/commit/693fff99049bc7d63459b2c444237ca532036b47

17 files changed:
src/coreclr/src/inc/corcompile.h
src/coreclr/src/inc/readytorun.h
src/coreclr/src/vm/codeman.cpp
src/coreclr/src/vm/compile.cpp
src/coreclr/src/vm/compile.h
src/coreclr/src/vm/genericdict.cpp
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/zapsig.cpp
src/coreclr/src/vm/zapsig.h
src/coreclr/src/zap/zapimport.cpp
src/coreclr/src/zap/zapimport.h
src/coreclr/tests/src/readytorun/fieldgetter.il [new file with mode: 0644]
src/coreclr/tests/src/readytorun/fieldgetter.ilproj [new file with mode: 0644]
src/coreclr/tests/src/readytorun/main.cs
src/coreclr/tests/src/readytorun/mainv1.csproj
src/coreclr/tests/src/readytorun/mainv2.csproj
src/coreclr/tests/src/readytorun/test.cs

index d3120d4..965de28 100644 (file)
@@ -1784,7 +1784,8 @@ class ICorCompileInfo
             SigBuilder * pSigBuilder,
             LPVOID encodeContext,
             ENCODEMODULE_CALLBACK pfnEncodeModule,
-            CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL) = 0;
+            CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL,
+            BOOL fEncodeUsingResolvedTokenSpecStreams = FALSE) = 0;
 
 
     // Encode generic dictionary signature
index 0fa1a14..fbcfc22 100644 (file)
@@ -15,8 +15,8 @@
 
 #define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
 
-#define READYTORUN_MAJOR_VERSION 0x0001
-#define READYTORUN_MINOR_VERSION 0x0002
+#define READYTORUN_MAJOR_VERSION 0x0002
+#define READYTORUN_MINOR_VERSION 0x0000
 
 struct READYTORUN_HEADER
 {
index 8e1800d..9ce6bb2 100644 (file)
@@ -6412,18 +6412,12 @@ UINT32 ReadyToRunJitManager::JitTokenToGCInfoVersion(const METHODTOKEN& MethodTo
 {
     CONTRACTL{
         NOTHROW;
-    GC_NOTRIGGER;
-    HOST_NOCALLS;
-    SUPPORTS_DAC;
+        GC_NOTRIGGER;
+        HOST_NOCALLS;
+        SUPPORTS_DAC;
     } CONTRACTL_END;
 
-    READYTORUN_HEADER * header = JitTokenToReadyToRunInfo(MethodToken)->GetImage()->GetReadyToRunHeader();
-    UINT32 gcInfoVersion = header->MajorVersion;
-
-    // Currently there's only one version of GCInfo.
-    _ASSERTE(gcInfoVersion == GCINFO_VERSION);
-
-    return gcInfoVersion;
+    return GCINFO_VERSION;
 }
 
 PTR_RUNTIME_FUNCTION ReadyToRunJitManager::JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken)
index 7a3507e..b381b3f 100644 (file)
@@ -2368,7 +2368,8 @@ void CEECompileInfo::EncodeField(
                          SigBuilder *          pSigBuilder,
                          LPVOID                encodeContext,
                          ENCODEMODULE_CALLBACK pfnEncodeModule,
-                         CORINFO_RESOLVED_TOKEN * pResolvedToken)
+                         CORINFO_RESOLVED_TOKEN * pResolvedToken, 
+                         BOOL fEncodeUsingResolvedTokenSpecStreams)
 {
     STANDARD_VM_CONTRACT;
 
@@ -2379,7 +2380,8 @@ void CEECompileInfo::EncodeField(
                         pSigBuilder,
                         encodeContext, 
                         pfnEncodeModule,
-                        pResolvedToken);
+                        pResolvedToken,
+                        fEncodeUsingResolvedTokenSpecStreams);
 
     COOPERATIVE_TRANSITION_END();
 }
index c7a2d06..19bbac3 100644 (file)
@@ -281,8 +281,8 @@ class CEECompileInfo : public ICorCompileInfo
                        SigBuilder              *pSigBuilder,
                        LPVOID                  encodeContext,
                        ENCODEMODULE_CALLBACK   pfnEncodeModule,
-                       CORINFO_RESOLVED_TOKEN pResolvedToken,
-                       CORINFO_RESOLVED_TOKEN pConstrainedResolvedToken,
+                       CORINFO_RESOLVED_TOKEN  *pResolvedToken,
+                       CORINFO_RESOLVED_TOKEN  *pConstrainedResolvedToken,
                        BOOL                    fEncodeUsingResolvedTokenSpecStreams);
 
     virtual mdToken TryEncodeMethodAsToken(CORINFO_METHOD_HANDLE handle, 
@@ -296,7 +296,8 @@ class CEECompileInfo : public ICorCompileInfo
                        SigBuilder              *pSigBuilder,
                        LPVOID                  encodeContext,
                        ENCODEMODULE_CALLBACK   pfnEncodeModule,
-                       CORINFO_RESOLVED_TOKEN * pResolvedToken);
+                       CORINFO_RESOLVED_TOKEN  *pResolvedToken,
+                       BOOL                    fEncodeUsingResolvedTokenSpecStreams);
 
     // Encode generic dictionary signature
     virtual void EncodeGenericSignature(
index 70a4b8a..4aca9e1 100644 (file)
@@ -690,6 +690,7 @@ Dictionary::PopulateEntry(
         switch (signatureKind)
         {
             case ENCODE_TYPE_HANDLE:    kind = TypeHandleSlot; break;
+            case ENCODE_FIELD_HANDLE:   kind = FieldDescSlot; break;
             case ENCODE_METHOD_HANDLE:  kind = MethodDescSlot; break;
             case ENCODE_METHOD_ENTRY:   kind = MethodEntrySlot; break;
             case ENCODE_VIRTUAL_ENTRY:  kind = DispatchStubAddrSlot; break;
@@ -1124,30 +1125,43 @@ Dictionary::PopulateEntry(
 
         case FieldDescSlot:
         {
-            TypeHandle th = ptr.GetTypeHandleThrowing(
-                pLookupModule,
-                &typeContext, 
-                (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), 
-                CLASS_LOADED, 
-                FALSE, 
-                NULL, 
-                pZapSigContext);
-            if (th.IsNull())
+            TypeHandle ownerType;
+
+            if (isReadyToRunModule)
             {
-                _ASSERTE(nonExpansive);
-                return NULL;
+                FieldDesc* pField = ZapSig::DecodeField((Module*)pZapSigContext->pModuleContext, pZapSigContext->pInfoModule, ptr.GetPtr(), &typeContext, &ownerType);
+                _ASSERTE(!ownerType.IsNull());
+                
+                if (!IsCompilationProcess())
+                    ownerType.AsMethodTable()->EnsureInstanceActive();
+
+                result = (CORINFO_GENERIC_HANDLE)pField;
             }
-            IfFailThrow(ptr.SkipExactlyOne());
+            else
+            {
+                ownerType = ptr.GetTypeHandleThrowing(
+                    pLookupModule,
+                    &typeContext,
+                    (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+                    CLASS_LOADED,
+                    FALSE,
+                    NULL,
+                    pZapSigContext);
+                if (ownerType.IsNull())
+                {
+                    _ASSERTE(nonExpansive);
+                    return NULL;
+                }
+                IfFailThrow(ptr.SkipExactlyOne());
 
-            DWORD fieldIndex;
-            IfFailThrow(ptr.GetData(&fieldIndex));
+                DWORD fieldIndex;
+                IfFailThrow(ptr.GetData(&fieldIndex));
 
-            if (!IsCompilationProcess())
-            {
-                th.AsMethodTable()->EnsureInstanceActive();
-            }
+                if (!IsCompilationProcess())
+                    ownerType.AsMethodTable()->EnsureInstanceActive();
 
-            result = (CORINFO_GENERIC_HANDLE)th.AsMethodTable()->GetFieldDescByIndex(fieldIndex);
+                result = (CORINFO_GENERIC_HANDLE)ownerType.AsMethodTable()->GetFieldDescByIndex(fieldIndex);
+            }
             break;
         }
 
index b72eaf3..59172fe 100644 (file)
@@ -3137,10 +3137,8 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr
         switch (entryKind)
         {
         case TypeHandleSlot:
-        {
             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
             break;
-        }
 
         case MethodDescSlot:
         case MethodEntrySlot:
@@ -3161,8 +3159,11 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr
             break;
         }
 
-        case DeclaringTypeHandleSlot:
         case FieldDescSlot:
+            pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
+            break;
+
+        case DeclaringTypeHandleSlot:
         case ConstrainedMethodEntrySlot:
             ThrowHR(E_NOTIMPL);
 
index 93b34db..c619610 100644 (file)
@@ -836,7 +836,7 @@ MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
                                  Module *pInfoModule,
                                  PCCOR_SIGNATURE pBuffer,
                                  SigTypeContext *pContext,
-                                 TypeHandle * ppTH, /*=NULL*/
+                                 TypeHandle *ppTH, /*=NULL*/
                                  PCCOR_SIGNATURE *ppOwnerTypeSpecWithVars, /*=NULL*/
                                  PCCOR_SIGNATURE *ppMethodSpecWithVars /*=NULL*/)
 {
@@ -1013,7 +1013,20 @@ MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
 FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
                                 Module *pInfoModule,
                                 PCCOR_SIGNATURE pBuffer,
-                                TypeHandle * ppTH /*=NULL*/)
+                                TypeHandle *ppTH /*=NULL*/)
+{
+    STANDARD_VM_CONTRACT;
+
+    SigTypeContext typeContext;    // empty context is OK: encoding should not contain type variables.
+
+    return DecodeField(pReferencingModule, pInfoModule, pBuffer, &typeContext, ppTH);
+}
+
+FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
+                                Module *pInfoModule,
+                                PCCOR_SIGNATURE pBuffer,
+                                SigTypeContext *pContext,
+                                TypeHandle *ppTH /*=NULL*/)
 {
     CONTRACTL
     {
@@ -1037,10 +1050,8 @@ FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
         ZapSig::Context    zapSigContext(pInfoModule, pReferencingModule);
         ZapSig::Context *  pZapSigContext = &zapSigContext;
 
-        SigTypeContext typeContext;    // empty context is OK: encoding should not contain type variables.
-
         pOwnerMT = sig.GetTypeHandleThrowing(pInfoModule,
-                                        &typeContext,
+                                        pContext,
                                         ClassLoader::LoadTypes,
                                         CLASS_LOADED,
                                         FALSE,
@@ -1371,7 +1382,8 @@ void ZapSig::EncodeField(
         SigBuilder             *pSigBuilder,
         LPVOID                 pEncodeModuleContext,
         ENCODEMODULE_CALLBACK  pfnEncodeModule,
-        CORINFO_RESOLVED_TOKEN * pResolvedToken)
+        CORINFO_RESOLVED_TOKEN *pResolvedToken,
+        BOOL                   fEncodeUsingResolvedTokenSpecStreams)
 {
     CONTRACTL
     {
@@ -1452,15 +1464,23 @@ void ZapSig::EncodeField(
 
     if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
     {
-        ZapSig zapSig(pInfoModule, pEncodeModuleContext, ZapSig::NormalTokens,
-                        (EncodeModuleCallback) pfnEncodeModule, NULL);
+        if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
+        {
+            _ASSERTE(pResolvedToken->cbTypeSpec > 0);
+            pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
+        }
+        else
+        {
+            ZapSig zapSig(pInfoModule, pEncodeModuleContext, ZapSig::NormalTokens,
+                (EncodeModuleCallback)pfnEncodeModule, NULL);
 
-        //
-        // Write class
-        //
-        BOOL fSuccess;
-        fSuccess = zapSig.GetSignatureForTypeHandle(pMT, pSigBuilder);
-        _ASSERTE(fSuccess);
+            //
+            // Write class
+            //
+            BOOL fSuccess;
+            fSuccess = zapSig.GetSignatureForTypeHandle(pMT, pSigBuilder);
+            _ASSERTE(fSuccess);
+        }
     }
 
     if ((fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken) == 0)
index ef837ad..258e821 100644 (file)
@@ -154,28 +154,39 @@ public:
     // fromModule is the module in which the type is defined.
     // pBuffer contains the signature encoding for the type.
     // level is the class load level (see classloadlevel.h) to which the type should be loaded
-    static TypeHandle DecodeType(Module *referencingModule,
-        Module *fromModule,
-        PCCOR_SIGNATURE pBuffer,
-        ClassLoadLevel level = CLASS_LOADED);
-
-    static MethodDesc *DecodeMethod(Module *referencingModule,
-        Module *fromModule,
-        PCCOR_SIGNATURE pBuffer,
-        TypeHandle * ppTH = NULL);
-
-    static MethodDesc *DecodeMethod(Module *referencingModule,
-        Module *fromModule,
-        PCCOR_SIGNATURE pBuffer,
-        SigTypeContext *pContext,
-        TypeHandle * ppTH = NULL,
-        PCCOR_SIGNATURE *ppOwnerTypeSpecWithVars = NULL,
-        PCCOR_SIGNATURE *ppMethodSpecWithVars = NULL);
-
-    static FieldDesc *DecodeField(Module *referencingModule,
-        Module *fromModule,
-        PCCOR_SIGNATURE pBuffer,
-        TypeHandle * ppTH = NULL);
+    static TypeHandle DecodeType(
+        Module              *referencingModule,
+        Module              *fromModule,
+        PCCOR_SIGNATURE     pBuffer,
+        ClassLoadLevel      level = CLASS_LOADED);
+
+    static MethodDesc *DecodeMethod(
+        Module              *referencingModule,
+        Module              *fromModule,
+        PCCOR_SIGNATURE     pBuffer,
+        TypeHandle          *ppTH = NULL);
+
+    static MethodDesc *DecodeMethod(
+        Module              *referencingModule,
+        Module              *fromModule,
+        PCCOR_SIGNATURE     pBuffer,
+        SigTypeContext      *pContext,
+        TypeHandle          *ppTH = NULL,
+        PCCOR_SIGNATURE     *ppOwnerTypeSpecWithVars = NULL,
+        PCCOR_SIGNATURE     *ppMethodSpecWithVars = NULL);
+
+    static FieldDesc *DecodeField(
+        Module              *referencingModule,
+        Module              *fromModule,
+        PCCOR_SIGNATURE     pBuffer,
+        TypeHandle          *ppTH = NULL);
+
+    static FieldDesc *DecodeField(
+        Module              *pReferencingModule,
+        Module              *pInfoModule,
+        PCCOR_SIGNATURE     pBuffer,
+        SigTypeContext      *pContext,
+        TypeHandle          *ppTH = NULL);
 
     static BOOL EncodeMethod(
         MethodDesc             *pMethod,
@@ -184,8 +195,8 @@ public:
         LPVOID                 pReferencingModule,
         ENCODEMODULE_CALLBACK  pfnEncodeModule,
         DEFINETOKEN_CALLBACK   pfnDefineToken,
-        CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL,
-        CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken = NULL,
+        CORINFO_RESOLVED_TOKEN *pResolvedToken = NULL,
+        CORINFO_RESOLVED_TOKEN *pConstrainedResolvedToken = NULL,
         BOOL                   fEncodeUsingResolvedTokenSpecStreams = FALSE);
 
     static void EncodeField(
@@ -194,7 +205,8 @@ public:
         SigBuilder             *pSigBuilder,
         LPVOID                 pReferencingModule,
         ENCODEMODULE_CALLBACK  pfnEncodeModule,
-        CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL);
+        CORINFO_RESOLVED_TOKEN *pResolvedToken = NULL,
+        BOOL                   fEncodeUsingResolvedTokenSpecStreams = FALSE);
 
 };
 
index 1412adc..400ea78 100644 (file)
@@ -999,13 +999,13 @@ void ZapImportTable::EncodeClassInContext(CORINFO_MODULE_HANDLE context, CORINFO
 }
 
 void ZapImportTable::EncodeField(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, SigBuilder * pSigBuilder,
-        CORINFO_RESOLVED_TOKEN * pResolvedToken)
+        CORINFO_RESOLVED_TOKEN * pResolvedToken, BOOL fEncodeUsingResolvedTokenSpecStreams)
 {
     CORINFO_CLASS_HANDLE clsHandle = GetJitInfo()->getFieldClass(handle);
     CORINFO_MODULE_HANDLE referencingModule = GetJitInfo()->getClassModule(clsHandle);
     referencingModule = TryEncodeModule(kind, referencingModule, pSigBuilder);
     GetCompileInfo()->EncodeField(referencingModule, handle, pSigBuilder, this, EncodeModuleHelper,
-        pResolvedToken);
+        pResolvedToken, fEncodeUsingResolvedTokenSpecStreams);
 }
 
 void ZapImportTable::EncodeMethod(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, SigBuilder * pSigBuilder,
@@ -1834,6 +1834,10 @@ ZapImport * ZapImportTable::GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND k
         EncodeMethod(ENCODE_VIRTUAL_ENTRY, pResolvedToken->hMethod, &sigBuilder, pResolvedToken, NULL, TRUE);
         break;
 
+    case READYTORUN_FIXUP_FieldHandle:
+        EncodeField(ENCODE_FIELD_HANDLE, pResolvedToken->hField, &sigBuilder, pResolvedToken, TRUE);
+        break;
+
         // TODO: support for the rest of the dictionary signature kinds
 
     default:
index b1a5fbb..34a673e 100644 (file)
@@ -339,7 +339,7 @@ public:
     void EncodeClass(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_CLASS_HANDLE handle, SigBuilder * pSigBuilder);
     void EncodeClassInContext(CORINFO_MODULE_HANDLE context, CORINFO_CLASS_HANDLE handle, SigBuilder * pSigBuilder);
     void EncodeField(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, SigBuilder * pSigBuilder,
-            CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL);
+            CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL, BOOL fEncodeUsingResolvedTokenSpecStreams = FALSE);
     void EncodeMethod(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, SigBuilder * pSigBuilder, 
             CORINFO_RESOLVED_TOKEN * pResolvedToken = NULL, CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken = NULL,
             BOOL fEncodeUsingResolvedTokenSpecStreams = FALSE);
diff --git a/src/coreclr/tests/src/readytorun/fieldgetter.il b/src/coreclr/tests/src/readytorun/fieldgetter.il
new file mode 100644 (file)
index 0000000..c2eff20
--- /dev/null
@@ -0,0 +1,215 @@
+// 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.
+
+.assembly extern System.Console { }
+.assembly extern mscorlib { }
+.assembly extern test { }
+
+.assembly fieldgetter { }
+.module fieldgetter.dll
+
+//==========================================================================================
+
+.class public auto ansi beforefieldinit Gen`1<T>
+       extends [mscorlib]System.Object
+{
+  .field public int32 m_Field1
+  .field public string m_Field2
+  .field public !T m_Field3
+  .field public static class [mscorlib]System.Collections.Generic.List`1<!T> m_Field4
+  .field public static valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!T,int32> m_Field5
+  
+  .method public hidebysig specialname rtspecialname instance void  .ctor() cil managed
+  {
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method Gen`1::.ctor
+} // end of class Gen`1
+
+.class interface public abstract auto ansi IFieldGetter
+{
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field1() cil managed
+  {
+  } // end of method IFieldGetter::GetGenT_Field1
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field2() cil managed
+  {
+  } // end of method IFieldGetter::GetGenT_Field2
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field3() cil managed
+  {
+  } // end of method IFieldGetter::GetGenT_Field3
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field4() cil managed
+  {
+  } // end of method IFieldGetter::GetGenT_Field4
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field5() cil managed
+  {
+  } // end of method IFieldGetter::GetGenT_Field5
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field1() cil managed
+  {
+  } // end of method IFieldGetter::GetGenDllT_Field1
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field2() cil managed
+  {
+  } // end of method IFieldGetter::GetGenDllT_Field2
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field3() cil managed
+  {
+  } // end of method IFieldGetter::GetGenDllT_Field3
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field4() cil managed
+  {
+  } // end of method IFieldGetter::GetGenDllT_Field4
+
+  .method public hidebysig newslot abstract virtual 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field5() cil managed
+  {
+  } // end of method IFieldGetter::GetGenDllT_Field5
+
+} // end of class IFieldGetter
+
+.class public auto ansi beforefieldinit FieldGetter`1<T>
+       extends [mscorlib]System.Object
+       implements IFieldGetter
+{
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field1() cil managed
+  {
+    ldtoken field int32 class Gen`1<!0>::m_Field1
+    ldtoken class Gen`1<!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenT_Field1
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field2() cil managed
+  {
+    ldtoken field string class Gen`1<!0>::m_Field2
+    ldtoken class Gen`1<!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenT_Field2
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field3() cil managed
+  {
+    ldtoken field !0 class Gen`1<!0>::m_Field3
+    ldtoken class Gen`1<!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenT_Field3
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field4() cil managed
+  {
+    ldtoken field class [mscorlib]System.Collections.Generic.List`1<!0> class Gen`1<!0>::m_Field4
+    ldtoken class Gen`1<!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenT_Field4
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenT_Field5() cil managed
+  {
+    ldtoken field valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,int32> class Gen`1<!0>::m_Field5
+    ldtoken class Gen`1<!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenT_Field5
+  
+  
+  
+  
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field1() cil managed
+  {
+    ldtoken field string class [test]MyGeneric`2<!0,!0>::m_Field1
+    ldtoken class [test]MyGeneric`2<!0,!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenDllT_Field1
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field2() cil managed
+  {
+    ldtoken field !0 class [test]MyGeneric`2<!0,!0>::m_Field2
+    ldtoken class [test]MyGeneric`2<!0,!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenDllT_Field2
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field3() cil managed
+  {
+    ldtoken field class [mscorlib]System.Collections.Generic.List`1<!0> class [test]MyGeneric`2<!0,!0>::m_Field3
+    ldtoken class [test]MyGeneric`2<!0,!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenDllT_Field3
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field4() cil managed
+  {
+    ldtoken field valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,int32> class [test]MyGeneric`2<!0,!0>::m_Field4
+    ldtoken class [test]MyGeneric`2<!0,!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenDllT_Field4
+
+  .method public hidebysig newslot virtual final 
+          instance class [mscorlib]System.Reflection.FieldInfo 
+          GetGenDllT_Field5() cil managed
+  {
+    ldtoken field int32 class [test]MyGeneric`2<!0,!0>::m_Field5
+    ldtoken class [test]MyGeneric`2<!0,!0>
+       call class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Reflection.FieldInfo::GetFieldFromHandle(valuetype [mscorlib]System.RuntimeFieldHandle, valuetype [mscorlib]System.RuntimeTypeHandle)
+    ret
+  } // end of method FieldGetter`1::GetGenDllT_Field5
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method FieldGetter`1::.ctor
+
+} // end of class FieldGetter`1
+
diff --git a/src/coreclr/tests/src/readytorun/fieldgetter.ilproj b/src/coreclr/tests/src/readytorun/fieldgetter.ilproj
new file mode 100644 (file)
index 0000000..0f6f687
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>fieldgetter</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Library</OutputType>
+    <CLRTestKind>SharedLibrary</CLRTestKind>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="fieldgetter.il" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
index b01702f..cce03b4 100644 (file)
@@ -379,6 +379,44 @@ class Program
         Func<string, object> idClosed = "World".OpenClosedDelegateTarget;
         Assert.AreEqual(idClosed("hey"), "World, hey");
     }
+    
+    static void GenericLdtokenFieldsTest()
+    {
+        Func<FieldInfo, string> FieldFullName = (fi) => fi.FieldType + " " + fi.DeclaringType.ToString() + "::" + fi.Name;
+        
+        IFieldGetter getter1 = new FieldGetter<string>();
+        IFieldGetter getter2 = new FieldGetter<object>();
+        IFieldGetter getter3 = new FieldGetter<int>();
+
+        foreach (var instArg in new Type[]{typeof(String), typeof(object), typeof(int)})
+        {
+            IFieldGetter getter = (IFieldGetter)Activator.CreateInstance(typeof(FieldGetter<>).MakeGenericType(instArg));
+
+            string expectedField1 = "System.Int32 Gen`1[???]::m_Field1".Replace("???", instArg.ToString());
+            string expectedField2 = "System.String Gen`1[???]::m_Field2".Replace("???", instArg.ToString());
+            string expectedField3 = "??? Gen`1[???]::m_Field3".Replace("???", instArg.ToString());
+            string expectedField4 = "System.Collections.Generic.List`1[???] Gen`1[???]::m_Field4".Replace("???", instArg.ToString());
+            string expectedField5 = "System.Collections.Generic.KeyValuePair`2[???,System.Int32] Gen`1[???]::m_Field5".Replace("???", instArg.ToString());
+
+            string expectedDllField1 = "System.String MyGeneric`2[???,???]::m_Field1".Replace("???", instArg.ToString());
+            string expectedDllField2 = "??? MyGeneric`2[???,???]::m_Field2".Replace("???", instArg.ToString());
+            string expectedDllField3 = "System.Collections.Generic.List`1[???] MyGeneric`2[???,???]::m_Field3".Replace("???", instArg.ToString());
+            string expectedDllField4 = "System.Collections.Generic.KeyValuePair`2[???,System.Int32] MyGeneric`2[???,???]::m_Field4".Replace("???", instArg.ToString());
+            string expectedDllField5 = "System.Int32 MyGeneric`2[???,???]::m_Field5".Replace("???", instArg.ToString());
+            
+            Assert.AreEqual(expectedField1, FieldFullName(getter.GetGenT_Field1()));
+            Assert.AreEqual(expectedField2, FieldFullName(getter.GetGenT_Field2()));
+            Assert.AreEqual(expectedField3, FieldFullName(getter.GetGenT_Field3()));
+            Assert.AreEqual(expectedField4, FieldFullName(getter.GetGenT_Field4()));
+            Assert.AreEqual(expectedField5, FieldFullName(getter.GetGenT_Field5()));
+
+            Assert.AreEqual(expectedDllField1, FieldFullName(getter.GetGenDllT_Field1()));
+            Assert.AreEqual(expectedDllField2, FieldFullName(getter.GetGenDllT_Field2()));
+            Assert.AreEqual(expectedDllField3, FieldFullName(getter.GetGenDllT_Field3()));
+            Assert.AreEqual(expectedDllField4, FieldFullName(getter.GetGenDllT_Field4()));
+            Assert.AreEqual(expectedDllField5, FieldFullName(getter.GetGenDllT_Field5()));
+        }
+    }
 
     static void RunAllTests()
     {
@@ -430,6 +468,8 @@ class Program
         TestRangeCheckElimination();
 
         TestOpenClosedDelegate();
+        
+        GenericLdtokenFieldsTest();
     }
 
     static int Main()
index 8da9bc2..855c357 100644 (file)
@@ -27,6 +27,7 @@
     </CodeAnalysisDependentAssemblyPaths>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="fieldgetter.ilproj" />
     <ProjectReference Include="testv1\test.csproj">
        <Project>{F74F55A1-DFCF-4C7C-B462-E96E1D0BB667}</Project>
     </ProjectReference>
@@ -47,6 +48,7 @@ $(CLRTestBatchPreCommands)
 DEL test.dll
 COPY /Y ..\testv1\test\test.dll test.dll
 %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll 
+%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll 
 %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv1.ni.exe mainv1.exe
 ]]></CLRTestBatchPreCommands>
   <BashCLRTestPreCommands><![CDATA[
@@ -54,6 +56,7 @@ $(BashCLRTestPreCommands)
 rm -f test.dll
 cp ../testv1/test/test.dll test.dll
 $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll
+$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll
 $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv1.ni.exe mainv1.exe
 ]]></BashCLRTestPreCommands>
   </PropertyGroup>  
index 19f16b3..52a3720 100644 (file)
@@ -27,6 +27,7 @@
     </CodeAnalysisDependentAssemblyPaths>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="fieldgetter.ilproj" />
     <ProjectReference Include="testv1\test.csproj" />
   </ItemGroup>
   <ItemGroup>
@@ -45,6 +46,7 @@ $(CLRTestBatchPreCommands)
 DEL test.dll
 COPY /Y ..\testv1\test\test.dll test.dll
 %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv2.ni.exe mainv2.exe
+%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll 
 DEL test.dll
 COPY /Y ..\testv2\test\test.dll test.dll
 %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll 
@@ -54,6 +56,7 @@ $(BashCLRTestPreCommands)
 rm -f test.dll
 cp ../testv1/test/test.dll test.dll
 $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv2.ni.exe mainv2.exe
+$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll
 rm -f test.dll
 cp ../testv2/test/test.dll test.dll
 $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll
index 39afbd2..40199b4 100644 (file)
@@ -225,6 +225,32 @@ public struct MyStruct : IDisposable
 
 public class MyGeneric<T,U>
 {
+#if V2
+    public object m_unused1;
+    public string m_Field1;
+    
+    public object m_unused2;
+    public T m_Field2;
+    
+    public object m_unused3;
+    public List<T> m_Field3;
+    
+    static public object m_unused4;
+    static public KeyValuePair<T, int> m_Field4;
+    
+    static public object m_unused5;
+    static public int m_Field5;
+    
+    public object m_unused6;
+    static public object m_unused7;
+#else
+    public string m_Field1;
+    public T m_Field2;
+    public List<T> m_Field3;
+    static public KeyValuePair<T, int> m_Field4;
+    static public int m_Field5;
+#endif
+
     [ThreadStatic] public static Object ThreadStatic;
 
     public MyGeneric()