New jit intrinsic support (#13815)
authorAndy Ayers <andya@microsoft.com>
Thu, 7 Sep 2017 21:28:07 +0000 (14:28 -0700)
committerGitHub <noreply@github.com>
Thu, 7 Sep 2017 21:28:07 +0000 (14:28 -0700)
Support for new-style intrinsics where corelib methods can have both IL
implementations and optional jit-supplied implementations.

Mark such methods with the [Intrinsic] attribute, then recognize the
intrinsic methods by name in the jit.

Jit currently has a placeholder for the Enum.HasFlag method.

23 files changed:
src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
src/ToolBox/superpmi/superpmi-shared/lwmlist.h
src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
src/ToolBox/superpmi/superpmi-shared/methodcontext.h
src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
src/inc/corinfo.h
src/jit/ICorJitInfo_API_names.h
src/jit/ICorJitInfo_API_wrapper.hpp
src/jit/compiler.h
src/jit/importer.cpp
src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
src/mscorlib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs [new file with mode: 0644]
src/mscorlib/src/System/Enum.cs
src/vm/classnames.h
src/vm/jitinterface.cpp
src/vm/jitinterface.h
src/vm/method.hpp
src/vm/methodtablebuilder.cpp
src/zap/zapinfo.cpp
src/zap/zapinfo.h

index ad6b269..4ce775d 100644 (file)
@@ -670,6 +670,14 @@ const char* getMethodName(CORINFO_METHOD_HANDLE ftn,       /* IN */
                           const char**          moduleName /* OUT */
                           );
 
+// Return method name as in metadata, or nullptr if there is none,
+// and optionally return the class name as in metadata.
+// Suitable for non-debugging use.
+const char* getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,       /* IN */
+                                      const char**          className, /* OUT */
+                                      const char**          namespaceName /* OUT */
+                                      );
+
 // this function is for debugging only.  It returns a value that
 // is will always be the same for a given method.  It is used
 // to implement the 'jitRange' functionality
index 349b6bf..898641c 100644 (file)
@@ -100,6 +100,7 @@ LWM(GetMethodDefFromMethod, DWORDLONG, DWORD)
 LWM(GetMethodHash, DWORDLONG, DWORD)
 LWM(GetMethodInfo, DWORDLONG, Agnostic_GetMethodInfo)
 LWM(GetMethodName, DLD, DD)
+LWM(GetMethodNameFromMetadata, DLDD, DDD)
 LWM(GetMethodSig, DLDL, Agnostic_CORINFO_SIG_INFO)
 LWM(GetMethodSync, DWORDLONG, DLDL)
 LWM(GetMethodVTableOffset, DWORDLONG, DDD)
index 82a7985..1545056 100644 (file)
@@ -1121,6 +1121,7 @@ void MethodContext::dmpGetMethodName(DLD key, DD value)
            moduleName);
     GetMethodName->Unlock();
 }
+
 const char* MethodContext::repGetMethodName(CORINFO_METHOD_HANDLE ftn, const char** moduleName)
 {
     const char* result = "hackishMethodName";
@@ -1148,6 +1149,85 @@ const char* MethodContext::repGetMethodName(CORINFO_METHOD_HANDLE ftn, const cha
     return result;
 }
 
+
+void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, 
+    char* methodName, const char** className, const char **namespaceName)
+{
+    if (GetMethodNameFromMetadata == nullptr)
+        GetMethodNameFromMetadata = new LightWeightMap<DLDD, DDD>();
+    DDD  value;
+    DLDD key;
+    key.A = (DWORDLONG)ftn;
+    key.B = (className != nullptr);
+    key.C = (namespaceName != nullptr);
+
+    if (methodName != nullptr)
+        value.A = GetMethodNameFromMetadata->AddBuffer((unsigned char*)methodName, (DWORD)strlen(methodName) + 1);
+    else
+        value.A = (DWORD)-1;
+
+    if (className != nullptr)
+        value.B = GetMethodNameFromMetadata->AddBuffer((unsigned char*)*className, (DWORD)strlen(*className) + 1);
+    else
+        value.B = (DWORD)-1;
+
+    if (namespaceName != nullptr)
+        value.C = GetMethodNameFromMetadata->AddBuffer((unsigned char*)*namespaceName, (DWORD)strlen(*namespaceName) + 1);
+    else
+        value.C = (DWORD)-1;
+
+    GetMethodNameFromMetadata->Add(key, value);
+    DEBUG_REC(dmpGetMethodNameFromMetadata(key, value));
+}
+
+void MethodContext::dmpGetMethodNameFromMetadata(DLDD key, DDD value)
+{
+    unsigned char* methodName = (unsigned char*)GetMethodName->GetBuffer(value.A);
+    unsigned char* className = (unsigned char*)GetMethodName->GetBuffer(value.B);
+    unsigned char* namespaceName = (unsigned char*)GetMethodName->GetBuffer(value.C);
+    printf("GetMethodNameFromMetadata key - ftn-%016llX classNonNull-%u namespaceNonNull-%u, value meth-'%s', class-'%s', namespace-'%s'", 
+        key.A, key.B, key.C, methodName, className, namespaceName);
+    GetMethodNameFromMetadata->Unlock();
+}
+
+const char* MethodContext::repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char** moduleName, const char** namespaceName)
+{
+    const char* result = nullptr;
+    DDD         value;
+    DLDD        key;
+    key.A = (DWORDLONG)ftn;
+    key.B = (moduleName != nullptr);
+    key.C = (namespaceName != nullptr);
+
+    int itemIndex = -1;
+    if (GetMethodNameFromMetadata != nullptr)
+        itemIndex = GetMethodNameFromMetadata->GetIndex(key);
+    if (itemIndex < 0)
+    {
+        if (moduleName != nullptr)
+        {
+            *moduleName = nullptr;
+        }
+    }
+    else
+    {
+        value = GetMethodNameFromMetadata->Get(key);
+        result = (const char*)GetMethodNameFromMetadata->GetBuffer(value.A);
+
+        if (moduleName != nullptr)
+        {            
+            *moduleName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.B);
+        }
+
+        if (namespaceName != nullptr)
+        {            
+            *namespaceName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.C);
+        }
+    }
+    DEBUG_REP(dmpGetMethodNameFromMetadata(key, value));
+    return result;
+}
+
 void MethodContext::recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DWORD result)
 {
     if (GetJitFlags == nullptr)
@@ -2980,7 +3060,7 @@ void MethodContext::recGetMethodVTableOffset(CORINFO_METHOD_HANDLE method,
     DDD value;
     value.A = (DWORD)*offsetOfIndirection;
     value.B = (DWORD)*offsetAfterIndirection;
-    value.C = *isRelative;
+    value.C = *isRelative ? 1 : 0;
     GetMethodVTableOffset->Add((DWORDLONG)method, value);
     DEBUG_REC(dmpGetMethodVTableOffset((DWORDLONG)method, value));
 }
@@ -3003,7 +3083,7 @@ void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method,
 
     *offsetOfIndirection    = (unsigned)value.A;
     *offsetAfterIndirection = (unsigned)value.B;
-    *isRelative             = value.C;
+    *isRelative             = value.C != 0;
     DEBUG_REP(dmpGetMethodVTableOffset((DWORDLONG)method, value));
 }
 
index 83c1677..eec4031 100644 (file)
@@ -89,6 +89,12 @@ public:
         DWORDLONG A;
         DWORD     B;
     };
+    struct DLDD
+    {
+        DWORDLONG A;
+        DWORD     B;
+        DWORD     C;
+    };
     struct Agnostic_CORINFO_RESOLVED_TOKENin
     {
         DWORDLONG tokenContext;
@@ -241,7 +247,7 @@ public:
     {
         DWORD A;
         DWORD B;
-        bool C;
+        DWORD C;
     };
     struct Agnostic_CanTailCall
     {
@@ -616,6 +622,10 @@ public:
     void dmpGetMethodName(DLD key, DD value);
     const char* repGetMethodName(CORINFO_METHOD_HANDLE ftn, const char** moduleName);
 
+    void recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, char* methodname, const char** moduleName, const char** namespaceName);
+    void dmpGetMethodNameFromMetadata(DLDD key, DDD value);
+    const char* repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char** className, const char** namespaceName);
+
     void recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DWORD result);
     void dmpGetJitFlags(DWORD key, DD value);
     DWORD repGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes);
@@ -1247,7 +1257,7 @@ private:
 };
 
 // ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 160
+// Highest packet number: 161
 // *************************************************************************************
 enum mcPackets
 {
@@ -1342,6 +1352,7 @@ enum mcPackets
     Packet_GetMethodHash                                 = 73,
     Packet_GetMethodInfo                                 = 74,
     Packet_GetMethodName                                 = 75,
+    Packet_GetMethodNameFromMetadata                     = 161,  // Added 9/6/17
     Packet_GetMethodSig                                  = 76,
     Packet_GetMethodSync                                 = 77,
     Packet_GetMethodVTableOffset                         = 78,
index d79e4ee..2a477a0 100644 (file)
@@ -1367,6 +1367,17 @@ const char* interceptor_ICJI::getMethodName(CORINFO_METHOD_HANDLE ftn,       /*
     return temp;
 }
 
+const char* interceptor_ICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,          /* IN */
+                                                        const char**          className,    /* OUT */
+                                                        const char**          namespaceName /* OUT */            
+                                                        )
+{
+    mc->cr->AddCall("getMethodNameFromMetadata");
+    const char* temp = original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName);
+    mc->recGetMethodNameFromMetadata(ftn, (char*)temp, className, namespaceName);
+    return temp;
+}
+
 // this function is for debugging only.  It returns a value that
 // is will always be the same for a given method.  It is used
 // to implement the 'jitRange' functionality
index d731a77..a54ead5 100644 (file)
@@ -1080,6 +1080,15 @@ const char* interceptor_ICJI::getMethodName(CORINFO_METHOD_HANDLE ftn,       /*
     return original_ICorJitInfo->getMethodName(ftn, moduleName);
 }
 
+const char* interceptor_ICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,          /* IN */
+                                                        const char**          className,    /* OUT */
+                                                        const char**          namespaceName /* OUT */
+                                                        )
+{
+    mcs->AddCall("getMethodNameFromMetadata");
+    return original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName);
+}
+
 // this function is for debugging only.  It returns a value that
 // is will always be the same for a given method.  It is used
 // to implement the 'jitRange' functionality
index fd45a3c..7e0ded9 100644 (file)
@@ -974,6 +974,14 @@ const char* interceptor_ICJI::getMethodName(CORINFO_METHOD_HANDLE ftn,       /*
     return original_ICorJitInfo->getMethodName(ftn, moduleName);
 }
 
+const char* interceptor_ICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,          /* IN */
+                                                        const char**          className,    /* OUT */
+                                                        const char**          namespaceName /* OUT */
+                                                        )
+{
+    return original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName);
+}
+
 // this function is for debugging only.  It returns a value that
 // is will always be the same for a given method.  It is used
 // to implement the 'jitRange' functionality
index e8b4187..2e78113 100644 (file)
@@ -1183,6 +1183,15 @@ const char* MyICJI::getMethodName(CORINFO_METHOD_HANDLE ftn,       /* IN */
     return jitInstance->mc->repGetMethodName(ftn, moduleName);
 }
 
+const char* MyICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,          /* IN */
+                                              const char**          className,    /* OUT */
+                                              const char**          namespaceName /* OUT */
+                                              )
+{
+    jitInstance->mc->cr->AddCall("getMethodNameFromMetadata");
+    return jitInstance->mc->repGetMethodNameFromMetadata(ftn, className, namespaceName);
+}
+
 // this function is for debugging only.  It returns a value that
 // is will always be the same for a given method.  It is used
 // to implement the 'jitRange' functionality
index 084b984..3171d6b 100644 (file)
@@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
     #define SELECTANY extern __declspec(selectany)
 #endif
 
-SELECTANY const GUID JITEEVersionIdentifier = { /* 5a1cfc89-a84a-4642-b01d-ead88e60c1ee */
-    0x5a1cfc89,
-    0xa84a,
-    0x4642,
-    { 0xb0, 0x1d, 0xea, 0xd8, 0x8e, 0x60, 0xc1, 0xee }
+SELECTANY const GUID JITEEVersionIdentifier = { /* 7f70c266-eada-427b-be8a-be1260e34b1b */
+    0x7f70c266,
+    0xeada,
+    0x427b,
+    {0xbe, 0x8a, 0xbe, 0x12, 0x60, 0xe3, 0x4b, 0x1b}
 };
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -827,7 +827,7 @@ enum CorInfoFlag
     CORINFO_FLG_NOSECURITYWRAP        = 0x04000000, // The method requires no security checks
     CORINFO_FLG_DONT_INLINE           = 0x10000000, // The method should not be inlined
     CORINFO_FLG_DONT_INLINE_CALLER    = 0x20000000, // The method should not be inlined, nor should its callers. It cannot be tail called.
-//  CORINFO_FLG_UNUSED                = 0x40000000,
+    CORINFO_FLG_JIT_INTRINSIC         = 0x40000000, // Method is a potential jit intrinsic; verify identity by name check
 
     // These are internal flags that can only be on Classes
     CORINFO_FLG_VALUECLASS            = 0x00010000, // is the class a value class
@@ -2260,7 +2260,6 @@ public:
             CORINFO_CLASS_HANDLE    cls
             ) = 0;
 
-
     // Append a (possibly truncated) representation of the type cls to the preallocated buffer ppBuf of length pnBufLen
     // If fNamespace=TRUE, include the namespace/enclosing classes
     // If fFullInst=TRUE (regardless of fNamespace and fAssembly), include namespace and assembly for any type parameters
@@ -2791,6 +2790,15 @@ public:
             const char                **moduleName  /* OUT */
             ) = 0;
 
+    // Return method name as in metadata, or nullptr if there is none,
+    // and optionally return the class and namespace names as in metadata.
+    // Suitable for non-debugging use.
+    virtual const char* getMethodNameFromMetadata(
+            CORINFO_METHOD_HANDLE       ftn,            /* IN */
+            const char                **className,      /* OUT */
+            const char                **namespaceName   /* OUT */
+            ) = 0;
+
     // this function is for debugging only.  It returns a value that
     // is will always be the same for a given method.  It is used
     // to implement the 'jitRange' functionality
index 1330f81..34a8bc0 100644 (file)
@@ -106,6 +106,7 @@ DEF_CLR_API(getEEInfo)
 DEF_CLR_API(getJitTimeLogFilename)
 DEF_CLR_API(getMethodDefFromMethod)
 DEF_CLR_API(getMethodName)
+DEF_CLR_API(getMethodNameFromMetadata)
 DEF_CLR_API(getMethodHash)
 DEF_CLR_API(findNameOfToken)
 DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor)
index 1d30e00..78177e1 100644 (file)
@@ -1029,6 +1029,17 @@ const char* WrapICorJitInfo::getMethodName(
     return temp;
 }
 
+const char* WrapICorJitInfo::getMethodNameFromMetadata(
+        CORINFO_METHOD_HANDLE       ftn,           /* IN */
+        const char                **className,     /* OUT */
+        const char                **namespaceName  /* OUT */)
+{
+    API_ENTER(getMethodNameFromMetadata);
+    const char* temp = wrapHnd->getMethodNameFromMetaData(ftn, moduleName, namespaceName);
+    API_LEAVE(getMethodNameFromMetadata);
+    return temp;
+}
+
 unsigned WrapICorJitInfo::getMethodHash(
         CORINFO_METHOD_HANDLE       ftn         /* IN */)
 {
index dd8f913..01997f1 100644 (file)
@@ -2980,6 +2980,7 @@ protected:
                             int                   memberRef,
                             bool                  readonlyCall,
                             bool                  tailCall,
+                            bool                  isJitIntrinsic,
                             CorInfoIntrinsics*    pIntrinsicID);
     GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
                                        CORINFO_SIG_INFO*    sig,
index e829d9a..dab2ee3 100644 (file)
@@ -3281,12 +3281,21 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
                                   int                   memberRef,
                                   bool                  readonlyCall,
                                   bool                  tailCall,
+                                  bool                  isJitIntrinsic,
                                   CorInfoIntrinsics*    pIntrinsicID)
 {
     bool              mustExpand  = false;
     CorInfoIntrinsics intrinsicID = info.compCompHnd->getIntrinsicID(method, &mustExpand);
     *pIntrinsicID                 = intrinsicID;
 
+    // Jit intrinsics are always optional to expand, and won't have an
+    // Intrinsic ID.
+    if (isJitIntrinsic)
+    {
+        assert(!mustExpand);
+        assert(intrinsicID == CORINFO_INTRINSIC_Illegal);
+    }
+
 #ifndef _TARGET_ARM_
     genTreeOps interlockedOperator;
 #endif
@@ -3755,6 +3764,29 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr            newobjThis,
             break;
     }
 
+#ifdef DEBUG
+    // Sample code showing how to use the new intrinsic mechansim.
+    if (isJitIntrinsic)
+    {
+        assert(retNode == nullptr);
+        const char* className     = nullptr;
+        const char* namespaceName = nullptr;
+        const char* methodName    = info.compCompHnd->getMethodNameFromMetadata(method, &className, &namespaceName);
+
+        if ((namespaceName != nullptr) && strcmp(namespaceName, "System") == 0)
+        {
+            if ((className != nullptr) && strcmp(className, "Enum") == 0)
+            {
+                if ((methodName != nullptr) && strcmp(methodName, "HasFlag") == 0)
+                {
+                    // Todo: plug in the intrinsic expansion
+                    JITDUMP("Found Intrinsic call to Enum.HasFlag\n");
+                }
+            }
+        }
+    }
+#endif
+
     if (mustExpand)
     {
         if (retNode == nullptr)
@@ -6776,10 +6808,12 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
 #endif // DEBUG
 
         // <NICE> Factor this into getCallInfo </NICE>
-        if ((mflags & CORINFO_FLG_INTRINSIC) && !pConstrainedResolvedToken)
+        const bool isIntrinsic    = (mflags & CORINFO_FLG_INTRINSIC) != 0;
+        const bool isJitIntrinsic = (mflags & CORINFO_FLG_JIT_INTRINSIC) != 0;
+        if ((isIntrinsic || isJitIntrinsic) && !pConstrainedResolvedToken)
         {
             call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, pResolvedToken->token, readonlyCall,
-                                (canTailCall && (tailCall != 0)), &intrinsicID);
+                                (canTailCall && (tailCall != 0)), isJitIntrinsic, &intrinsicID);
 
             if (compIsForInlining() && compInlineResult->IsFailure())
             {
index bd68b54..bc7e039 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IndexerNameAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\INotifyCompletion.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\InternalsVisibleToAttribute.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IntrinsicAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsConst.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsByRefLikeAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IsVolatile.cs" />
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/IntrinsicAttribute.cs
new file mode 100644 (file)
index 0000000..0d249de
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+namespace System.Runtime.CompilerServices
+{
+    // Calls to methods marked with this attribute may be replaced at
+    // some call sites with jit intrinsic expansions.
+    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)]
+    internal sealed class IntrinsicAttribute : Attribute
+    {
+    }
+}
index 092bea1..b5d00fe 100644 (file)
@@ -12,6 +12,18 @@ using System.Runtime.Versioning;
 using System.Diagnostics;
 using System.Diagnostics.Contracts;
 
+// The code below includes partial support for float/double and
+// pointer sized enums.
+//
+// The type loader does not prohibit such enums, and older versions of
+// the ECMA spec include them as possible enum types.
+//
+// However there are many things broken throughout the stack for
+// float/double/intptr/uintptr enums. There was a conscious decision
+// made to not fix the whole stack to work well for them because of
+// the right behavior is often unclear, and it is hard to test and
+// very low value because of such enums cannot be expressed in C#.
+
 namespace System
 {
     [Serializable]
@@ -961,6 +973,7 @@ namespace System
             return ToString();
         }
 
+        [Intrinsic]
         public Boolean HasFlag(Enum flag)
         {
             if (flag == null)
index 0c24914..fc08737 100644 (file)
 
 #define g_CompilerServicesFixedAddressValueTypeAttribute "System.Runtime.CompilerServices.FixedAddressValueTypeAttribute"
 #define g_CompilerServicesUnsafeValueTypeAttribute "System.Runtime.CompilerServices.UnsafeValueTypeAttribute"
+#define g_CompilerServicesIntrinsicAttribute "System.Runtime.CompilerServices.IntrinsicAttribute"
 #define g_UnmanagedFunctionPointerAttribute "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"
 #define g_DefaultDllImportSearchPathsAttribute "System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute"
 #define g_NativeCallableAttribute "System.Runtime.InteropServices.NativeCallableAttribute"
index 71af406..4301873 100644 (file)
@@ -6460,6 +6460,48 @@ const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** s
     return result;
 }
 
+const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName)
+{
+    CONTRACTL {
+        SO_TOLERANT;
+        THROWS;
+        GC_TRIGGERS;
+        MODE_PREEMPTIVE;
+    } CONTRACTL_END;
+
+    const char* result = NULL;
+    const char* classResult = NULL;
+    const char* namespaceResult = NULL;
+
+    JIT_TO_EE_TRANSITION();
+
+    MethodDesc *ftn = GetMethod(ftnHnd);
+    mdMethodDef token = ftn->GetMemberDef();
+
+    if (!IsNilToken(token))
+    {
+        if (!FAILED(ftn->GetMDImport()->GetNameOfMethodDef(token, &result)))
+        {
+            MethodTable* pMT = ftn->GetMethodTable();
+            classResult = pMT->GetFullyQualifiedNameInfo(&namespaceResult);
+        }
+    }
+
+    if (className != NULL)
+    {
+        *className = classResult;
+    }
+
+    if (namespaceName != NULL)
+    {
+        *namespaceName = namespaceResult;
+    }
+
+    EE_TO_JIT_TRANSITION();
+    
+    return result;
+}
+
 /*********************************************************************/
 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
 {
@@ -6514,6 +6556,8 @@ DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
         result |= CORINFO_FLG_SYNCH;
     if (pMD->IsFCallOrIntrinsic())
         result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
+    if (pMD->IsJitIntrinsic())
+        result |= CORINFO_FLG_JIT_INTRINSIC;
     if (IsMdVirtual(attribs))
         result |= CORINFO_FLG_VIRTUAL;
     if (IsMdAbstract(attribs))
index 141c812..8ba65c3 100644 (file)
@@ -649,6 +649,7 @@ public:
 
     // ICorMethodInfo stuff
     const char* getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName);
+    const char* getMethodNameFromMetadata (CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName);
     unsigned getMethodHash (CORINFO_METHOD_HANDLE ftnHnd);
 
     DWORD getMethodAttribs (CORINFO_METHOD_HANDLE ftnHnd);
index 671fd82..9a20af2 100644 (file)
@@ -704,7 +704,6 @@ public:
         InterlockedUpdateFlags(mdcNotInline, set);
     }
 
-
     BOOL IsIntrospectionOnly();
 #ifndef DACCESS_COMPILE
     VOID EnsureActive();
@@ -1690,7 +1689,8 @@ protected:
         enum_flag2_IsUnboxingStub           = 0x04,
         enum_flag2_HasNativeCodeSlot        = 0x08,   // Has slot for native code
 
-        // unused                           = 0x10,
+        enum_flag2_IsJitIntrinsic           = 0x10,   // Jit may expand method as an intrinsic
+
         // unused                           = 0x20,
         // unused                           = 0x40,
         // unused                           = 0x80, 
@@ -1743,6 +1743,18 @@ public:
         m_bFlags2 |= enum_flag2_HasNativeCodeSlot;
     }
 
+    inline BOOL IsJitIntrinsic()
+    {
+        LIMITED_METHOD_DAC_CONTRACT;
+        return (m_bFlags2 & enum_flag2_IsJitIntrinsic) != 0;
+    }
+
+    inline void SetIsJitIntrinsic()
+    {
+        LIMITED_METHOD_CONTRACT;
+        m_bFlags2 |= enum_flag2_IsJitIntrinsic;
+    }
+
     static const SIZE_T s_ClassificationSizeTable[];
 
     static SIZE_T GetBaseSize(DWORD classification)
index 4768807..cdee2d8 100644 (file)
@@ -5082,6 +5082,20 @@ MethodTableBuilder::InitNewMethodDesc(
         pNewMD->SetNotInline(true);
     }
 
+    // Check for methods marked as [Intrinsic]
+    if (GetModule()->IsSystem())
+    {
+        HRESULT hr = GetMDImport()->GetCustomAttributeByName(pMethod->GetMethodSignature().GetToken(),
+            g_CompilerServicesIntrinsicAttribute,
+            NULL,
+            NULL);
+
+        if (hr == S_OK)
+        {
+            pNewMD->SetIsJitIntrinsic();
+        }
+    }
+
     pNewMD->SetSlot(pMethod->GetSlotIndex());
 }
 
index 5683f4f..b8ef3ea 100644 (file)
@@ -3545,6 +3545,11 @@ const char* ZapInfo::getMethodName(CORINFO_METHOD_HANDLE ftn, const char **modul
     return m_pEEJitInfo->getMethodName(ftn, moduleName);
 }
 
+const char* ZapInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char **className, const char** namespaceName)
+{
+    return m_pEEJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName);
+}
+
 unsigned ZapInfo::getMethodHash(CORINFO_METHOD_HANDLE ftn)
 {
     return m_pEEJitInfo->getMethodHash(ftn);
index 88f095b..d533975 100644 (file)
@@ -616,6 +616,10 @@ public:
 
     const char* getMethodName(CORINFO_METHOD_HANDLE ftn,
                                         const char **moduleName);
+    const char* getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
+                                          const char **className,
+                                          const char **namespaceName);
+
     unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn);
     DWORD getMethodAttribs(CORINFO_METHOD_HANDLE ftn);
     void setMethodAttribs(CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs);