Cuckoo metadata (#24498)
authorDavid Wrighton <davidwr@microsoft.com>
Mon, 20 May 2019 22:15:52 +0000 (15:15 -0700)
committerGitHub <noreply@github.com>
Mon, 20 May 2019 22:15:52 +0000 (15:15 -0700)
* Basic infra for cuckoo filter of attributes
- Implement cuckoo filter lookup logic
- Implement new ready to run section
 - Add dumper to R2RDump
 - Parse section on load into data structure
 - Implement function to query filter
- Add concept of enum of well known attributes
  - So that attribute name hashes themselves may be cached
* Wrap all even vaguely perf critical uses of attribute by name parsing with use of R2R data
* Update emmintrin.h in the PAL header to contain the needed SSE2 intrinsics for the feature
- Disable the presence table for non Corelib cases. Current performance data does not warrant the size increase in other generated binaries

42 files changed:
src/inc/readytorun.h
src/md/enc/mdinternalrw.cpp
src/md/runtime/mdinternalro.cpp
src/pal/inc/rt/cpp/emmintrin.h
src/pal/inc/rt/cpp/xmmintrin.h
src/tools/r2rdump/NativeHashtable.cs
src/tools/r2rdump/R2RSection.cs
src/tools/r2rdump/README.md
src/tools/r2rdump/TextDumper.cs
src/vm/assembly.cpp
src/vm/assembly.hpp
src/vm/ceeload.cpp
src/vm/ceeload.h
src/vm/class.cpp
src/vm/comcallablewrapper.cpp
src/vm/comdelegate.cpp
src/vm/commtmemberinfomap.cpp
src/vm/comtoclrcall.cpp
src/vm/dllimport.cpp
src/vm/fieldmarshaler.cpp
src/vm/fieldmarshaler.h
src/vm/interoputil.cpp
src/vm/interoputil.h
src/vm/marshalnative.cpp
src/vm/marshalnative.h
src/vm/method.cpp
src/vm/method.hpp
src/vm/methodtable.h
src/vm/methodtable.inl
src/vm/methodtablebuilder.cpp
src/vm/methodtablebuilder.h
src/vm/mlinfo.cpp
src/vm/nativeformatreader.h
src/vm/readytoruninfo.cpp
src/vm/readytoruninfo.h
src/vm/siginfo.cpp
src/vm/staticallocationhelpers.inl
src/vm/typehashingalgorithms.h
src/vm/wellknownattributes.h [new file with mode: 0644]
src/zap/zapimage.cpp
src/zap/zapimage.h
src/zap/zapreadytorun.cpp

index 6307bc9..d28d78c 100644 (file)
@@ -16,7 +16,7 @@
 #define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
 
 #define READYTORUN_MAJOR_VERSION 0x0003
-#define READYTORUN_MINOR_VERSION 0x0000
+#define READYTORUN_MINOR_VERSION 0x0001
 #define MINIMUM_READYTORUN_MAJOR_VERSION 0x003
 // R2R Version 2.1 adds the READYTORUN_SECTION_INLINING_INFO section
 // R2R Version 2.2 adds the READYTORUN_SECTION_PROFILEDATA_INFO section
@@ -66,7 +66,8 @@ enum ReadyToRunSectionType
     READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS  = 109,
     READYTORUN_SECTION_INLINING_INFO                = 110, // Added in V2.1
     READYTORUN_SECTION_PROFILEDATA_INFO             = 111, // Added in V2.2
-    READYTORUN_SECTION_MANIFEST_METADATA            = 112  // Added in V2.3
+    READYTORUN_SECTION_MANIFEST_METADATA            = 112, // Added in V2.3
+    READYTORUN_SECTION_ATTRIBUTEPRESENCE            = 113, // Added in V3.1
 
        // If you add a new section consider whether it is a breaking or non-breaking change.
        // Usually it is non-breaking, but if it is preferable to have older runtimes fail
index c8f844d..c24c1b7 100644 (file)
@@ -1482,6 +1482,10 @@ HRESULT MDInternalRW::EnumAllInit(      // return S_FALSE if record not found
         phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountFiles();
         break;
 
+    case mdtCustomAttribute:
+        phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountCustomAttributes();
+        break;
+
     default:
         _ASSERTE(!"Bad token kind!");
         break;
index a4f59a3..99a1a0d 100644 (file)
@@ -609,6 +609,10 @@ HRESULT MDInternalRO::EnumAllInit(      // return S_FALSE if record not found
         phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountFiles();
         break;
 
+    case mdtCustomAttribute:
+        phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountCustomAttributes();
+        break;
+
     default:
         _ASSERTE(!"Bad token kind!");
         break;
index 5401fab..14b72be 100644 (file)
@@ -2,4 +2,128 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+// From llvm-3.9/clang-3.9.1 emmintrin.h:
+
+/*===---- emmintrin.h - SSE2 intrinsics ------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
 #include "palrt.h"
+#ifdef __GNUC__
+#ifndef __EMMINTRIN_H
+#define __IMMINTRIN_H
+
+typedef long long __m128i __attribute__((__vector_size__(16)));
+
+typedef unsigned long long __v2du __attribute__ ((__vector_size__ (16)));
+typedef short __v8hi __attribute__((__vector_size__(16)));
+typedef char __v16qi __attribute__((__vector_size__(16)));
+
+
+/* Define the default attribute for the functions in this file. */
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
+
+/// \brief Performs a bitwise OR of two 128-bit integer vectors.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c VPOR / POR instruction.
+///
+/// \param __a
+///    A 128-bit integer vector containing one of the source operands.
+/// \param __b
+///    A 128-bit integer vector containing one of the source operands.
+/// \returns A 128-bit integer vector containing the bitwise OR of the values
+///    in both operands.
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_or_si128(__m128i __a, __m128i __b)
+{
+  return (__m128i)((__v2du)__a | (__v2du)__b);
+}
+
+/// \brief Compares each of the corresponding 16-bit values of the 128-bit
+///    integer vectors for equality. Each comparison yields 0h for false, FFFFh
+///    for true.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c VPCMPEQW / PCMPEQW instruction.
+///
+/// \param __a
+///    A 128-bit integer vector.
+/// \param __b
+///    A 128-bit integer vector.
+/// \returns A 128-bit integer vector containing the comparison results.
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_cmpeq_epi16(__m128i __a, __m128i __b)
+{
+  return (__m128i)((__v8hi)__a == (__v8hi)__b);
+}
+
+/// \brief Moves packed integer values from an unaligned 128-bit memory location
+///    to elements in a 128-bit integer vector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c VMOVDQU / MOVDQU instruction.
+///
+/// \param __p
+///    A pointer to a memory location containing integer values.
+/// \returns A 128-bit integer vector containing the moved values.
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_loadu_si128(__m128i const *__p)
+{
+  struct __loadu_si128 {
+    __m128i __v;
+  } __attribute__((__packed__, __may_alias__));
+  return ((struct __loadu_si128*)__p)->__v;
+}
+
+/// \brief Initializes all values in a 128-bit vector of [8 x i16] with the
+///    specified 16-bit value.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic is a utility function and does not correspond to a specific
+///    instruction.
+///
+/// \param __w
+///    A 16-bit value used to initialize the elements of the destination integer
+///    vector.
+/// \returns An initialized 128-bit vector of [8 x i16] with all elements
+///    containing the value provided in the operand.
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_set1_epi16(short __w)
+{
+  return (__m128i)(__v8hi){ __w, __w, __w, __w, __w, __w, __w, __w };
+}
+
+static __inline__ int __DEFAULT_FN_ATTRS
+_mm_movemask_epi8(__m128i __a)
+{
+  return __builtin_ia32_pmovmskb128((__v16qi)__a);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif /* __EMMINTRIN_H */
+#endif // __GNUC__
index 33bc8b4..ed2ff58 100644 (file)
@@ -113,4 +113,6 @@ _mm_store_ps(float *__p, __m128 __a)
     *(__m128*)__p = __a;
 }
 
+#undef __DEFAULT_FN_ATTRS
+
 #endif // __GNUC__
index 830805e..44e7b3f 100644 (file)
@@ -238,4 +238,61 @@ namespace R2RDump
             return new AllEntriesEnumerator(this);
         }
     }
+
+    /// <summary>
+    /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/vm/nativeformatreader.h">NativeFormat::NativeHashtable</a>
+    /// </summary>
+    struct NativeCuckooFilter
+    {
+        private byte[] _image;
+        private int _filterStartOffset;
+        private int _filterEndOffset;
+
+        public NativeCuckooFilter(byte[] image, int filterStartOffset, int filterEndOffset)
+        {
+            _image = image;
+            _filterStartOffset = filterStartOffset;
+            _filterEndOffset = filterEndOffset;
+
+            if (((_filterStartOffset & 0xF) != 0) || ((_filterEndOffset & 0xF) != 0))
+            {
+                // Native cuckoo filters must be aligned at 16byte boundaries within the PE file
+                throw new System.BadImageFormatException();
+            }
+        }
+
+        private IEnumerable<ushort[]> GetBuckets()
+        {
+            int offset = _filterStartOffset;
+            while (offset < _filterEndOffset)
+            {
+                ushort[] bucket = new ushort[8];
+                for (int i = 0; i < bucket.Length; i++)
+                {
+                    bucket[i] = NativeReader.ReadUInt16(_image, ref offset);
+                }
+                yield return bucket;
+            }
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+
+            sb.AppendLine($"NativeCuckooFilter Size: {(_filterEndOffset - _filterStartOffset) / 16}");
+            int bucket = 0;
+            foreach (ushort [] bucketContents in GetBuckets())
+            {
+                sb.Append($"Bucket: {bucket} [");
+                for (int i = 0; i < 8; i++)
+                {
+                    sb.Append($"{bucketContents[i],4:X} ");
+                }
+                sb.AppendLine("]");
+                bucket++;
+            }
+
+            return sb.ToString();
+        }
+    }
 }
index 3ba922b..0eca7e9 100644 (file)
@@ -29,6 +29,7 @@ namespace R2RDump
             READYTORUN_SECTION_INLINING_INFO = 110,
             READYTORUN_SECTION_PROFILEDATA_INFO = 111,
             READYTORUN_SECTION_MANIFEST_METADATA = 112, // Added in v2.3
+            READYTORUN_SECTION_ATTRIBUTEPRESENCE = 113, // Added in V3.1
         }
 
         /// <summary>
index 0d7bdb9..ee16e40 100644 (file)
@@ -81,6 +81,10 @@ A [NativeArray](NativeArray.cs) used for finding the index of the entrypoint Run
 
 A [NativeHashtable](NativeHashtable.cs) mapping type hashcodes of types defined in the program to the rowIds. The hashcode is calculated with [ComputeNameHashCode](../../vm/typehashingalgorithms.h)(namespace) ^ [ComputeNameHashCode](../../vm/typehashingalgorithms.h)(name)
 
+### READYTORUN_SECTION_ATTRIBUTEPRESENCE
+
+A [NativeCuckooFilter](NativeHashtable.cs) to discover which tokens have which "System.Runtime." prefixed attributes. The System.Runtime.CompilerServices.NullableAttribute is not used in this calculation. The filter is composed of a name hash of the type name using [ComputeNameHashCode](../../vm/typehashingalgorithms.h)(namespace + name) hash combined with a hash of each token that produced it. In addition the upper 16 bits is used as the fingerprint in the filter. 
+
 ### READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS
 
 A [NativeHashtable](NativeHashtable.cs) mapping type hashcodes of generic instances to the (methodFlags, methodRowId, list of types, runtimeFunctionId). Each type in the list of types corresponds to a generic type in the method.
index db4c5f3..b1528df 100644 (file)
@@ -374,6 +374,13 @@ namespace R2RDump
                         _writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {_r2r.ManifestReferenceAssemblies[manifestAsmIndex]}");
                     }
                     break;
+                case R2RSection.SectionType.READYTORUN_SECTION_ATTRIBUTEPRESENCE:
+                    int attributesStartOffset = _r2r.GetOffset(section.RelativeVirtualAddress);
+                    int attributesEndOffset = attributesStartOffset + section.Size;
+                    NativeCuckooFilter attributes = new NativeCuckooFilter(_r2r.Image, attributesStartOffset, attributesEndOffset);
+                    _writer.WriteLine("Attribute presence filter");
+                    _writer.WriteLine(attributes.ToString());
+                    break;
             }
         }
 
index 119f922..4573f7c 100644 (file)
@@ -229,8 +229,7 @@ BOOL Assembly::IsDisabledPrivateReflection()
 
     if (m_isDisabledPrivateReflection == UNINITIALIZED)
     {
-        IMDInternalImport *pImport = GetManifestImport();
-        HRESULT hr = pImport->GetCustomAttributeByName(GetManifestToken(), DISABLED_PRIVATE_REFLECTION_TYPE, NULL, 0);
+        HRESULT hr = GetManifestModule()->GetCustomAttribute(GetManifestToken(), WellKnownAttribute::DisablePrivateReflectionType, NULL, 0);
         IfFailThrow(hr);
 
         if (hr == S_OK)
index 8979397..e4b0795 100644 (file)
@@ -304,6 +304,16 @@ public:
         return m_pManifestFile->GetPersistentMDImport();
     }
 
+    HRESULT GetCustomAttribute(mdToken parentToken,
+                               WellKnownAttribute attribute,
+                               const void  **ppData,
+                               ULONG *pcbData)
+    {
+        WRAPPER_NO_CONTRACT;
+        SUPPORTS_DAC;
+        return GetManifestModule()->GetCustomAttribute(parentToken, attribute, ppData, pcbData);
+    }
+
 #ifndef DACCESS_COMPILE
     IMetaDataAssemblyImport* GetManifestAssemblyImporter()
     {
@@ -549,9 +559,9 @@ protected:
 
         if (!IsWinMD()) // ignore classic COM interop CAs in .winmd
         {
-            if (this->GetManifestImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_IMPORTEDFROMTYPELIB_TYPE, 0, 0) == S_OK)
+            if (GetManifestModule()->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::ImportedFromTypeLib, NULL, 0) == S_OK)
                 mask |= INTEROP_ATTRIBUTE_IMPORTED_FROM_TYPELIB;
-            if (this->GetManifestImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_PRIMARYINTEROPASSEMBLY_TYPE, 0, 0) == S_OK)
+            if (GetManifestModule()->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::PrimaryInteropAssembly, NULL, 0) == S_OK)
                 mask |= INTEROP_ATTRIBUTE_PRIMARY_INTEROP_ASSEMBLY;
         }
         
index e389df9..40b73a0 100644 (file)
@@ -219,6 +219,7 @@ void Module::UpdateNewlyAddedTypes()
 
     DWORD countTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
     DWORD countExportedTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
+    DWORD countCustomAttributeCount = GetMDImport()->GetCountWithTokenKind(mdtCustomAttribute);
 
     // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs before means rid X+1 was valid and our incremental addition should start at X+2
     for (DWORD typeDefRid = m_dwTypeCount + 2; typeDefRid < countTypesAfterProfilerUpdate + 2; typeDefRid++)
@@ -232,8 +233,15 @@ void Module::UpdateNewlyAddedTypes()
         GetAssembly()->AddExportedType(TokenFromRid(exportedTypeDef, mdtExportedType));
     }
 
+    if ((countCustomAttributeCount != m_dwCustomAttributeCount) && IsReadyToRun())
+    {
+        // Set of custom attributes has changed. Disable the cuckoo filter from ready to run, and do normal custom attribute parsing
+        GetReadyToRunInfo()->DisableCustomAttributeFilter();
+    }
+
     m_dwTypeCount = countTypesAfterProfilerUpdate;
     m_dwExportedTypeCount = countExportedTypesAfterProfilerUpdate;
+    m_dwCustomAttributeCount = countCustomAttributeCount;
 }
 
 void Module::NotifyProfilerLoadFinished(HRESULT hr)
@@ -257,6 +265,7 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr)
         {
             m_dwTypeCount = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
             m_dwExportedTypeCount = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
+            m_dwCustomAttributeCount = GetMDImport()->GetCountWithTokenKind(mdtCustomAttribute);
         }
 
         // Notify the profiler, this may cause metadata to be updated
@@ -622,6 +631,7 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
     // a safe initial value now.
     m_dwTypeCount = 0;
     m_dwExportedTypeCount = 0;
+    m_dwCustomAttributeCount = 0;
 
     // Prepare statics that are known at module load time
     AllocateStatics(pamTracker);
@@ -2535,10 +2545,9 @@ BOOL Module::HasDefaultDllImportSearchPathsAttribute()
     {
         return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
     }
-    IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
 
     BOOL attributeIsFound = FALSE;
-    attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(mdImport, TokenFromRid(1, mdtAssembly),&m_DefaultDllImportSearchPathsAttributeValue);
+    attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(this, TokenFromRid(1, mdtAssembly),&m_DefaultDllImportSearchPathsAttributeValue);
     if(attributeIsFound)
     {
         FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED | DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS);
index 602a69c..3aab11d 100644 (file)
@@ -36,6 +36,8 @@
 #include "corcompile.h"
 #include <gcinfodecoder.h>
 
+#include "wellknownattributes.h"
+
 #ifdef FEATURE_PREJIT
 #include "dataimage.h"
 #endif // FEATURE_PREJIT
@@ -1627,6 +1629,7 @@ private:
 #if PROFILING_SUPPORTED_DATA 
     DWORD                   m_dwTypeCount;
     DWORD                   m_dwExportedTypeCount;
+    DWORD                   m_dwCustomAttributeCount;
 #endif // PROFILING_SUPPORTED_DATA
 
 #ifdef FEATURE_PREJIT
@@ -1889,6 +1892,20 @@ protected:
 
     CHECK CheckActivated();
 
+    HRESULT GetCustomAttribute(mdToken parentToken,
+                               WellKnownAttribute attribute,
+                               const void  **ppData,
+                               ULONG *pcbData)
+    {
+        if (IsReadyToRun())
+        {
+            if (!GetReadyToRunInfo()->MayHaveCustomAttribute(attribute, parentToken))
+                return S_FALSE;
+        }
+
+        return GetMDImport()->GetCustomAttributeByName(parentToken, GetWellKnownAttributeName(attribute), ppData, pcbData);
+    }
+
     IMDInternalImport *GetMDImport() const
     {
         WRAPPER_NO_CONTRACT;
index abc1230..10271c9 100644 (file)
@@ -1649,7 +1649,7 @@ TypeHandle MethodTable::SetupCoClassForInterface()
 
     if (!IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT types
     {
-        HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COCLASS_TYPE , (const void **)&pVal, &cbVal);
+        HRESULT hr = GetCustomAttribute(WellKnownAttribute::CoClass, (const void **)&pVal, &cbVal);
         if (hr == S_OK)
         {
             CustomAttributeParser cap(pVal, cbVal);
@@ -2026,7 +2026,7 @@ void EEClass::GetBestFitMapping(MethodTable * pMT, BOOL *pfBestFitMapping, BOOL
         *pfBestFitMapping = FALSE;
         *pfThrowOnUnmappableChar = FALSE;
         
-        ReadBestFitCustomAttribute(pMT->GetMDImport(), pMT->GetCl(), pfBestFitMapping, pfThrowOnUnmappableChar);
+        ReadBestFitCustomAttribute(pMT->GetModule(), pMT->GetCl(), pfBestFitMapping, pfThrowOnUnmappableChar);
 
         DWORD flags = VMFLAG_BESTFITMAPPING_INITED;
         if (*pfBestFitMapping) flags |= VMFLAG_BESTFITMAPPING;
@@ -3954,7 +3954,6 @@ void EEClassLayoutInfo::ParseFieldNativeTypes(
                 pFieldInfoArrayOut,
                 pNativeType,
                 cbNativeType,
-                pInternalImport,
                 cl,
                 pTypeContext,
                 fDisqualifyFromManagedSequential
index f38f180..d271a6d 100644 (file)
@@ -349,7 +349,7 @@ bool IsOleAutDispImplRequiredForClass(MethodTable *pClass)
     }
 
     // First check for the IDispatchImplType custom attribute first.
-    hr = pClass->GetMDImport()->GetCustomAttributeByName(pClass->GetCl(), INTEROP_IDISPATCHIMPL_TYPE, (const void**)&pVal, &cbVal);
+    hr = pClass->GetCustomAttribute(WellKnownAttribute::IDispatchImpl, (const void**)&pVal, &cbVal);
     if (hr == S_OK)
     {
         CustomAttributeParser cap(pVal, cbVal);
@@ -367,7 +367,7 @@ bool IsOleAutDispImplRequiredForClass(MethodTable *pClass)
         return (bool) (DispImplType == CompatibleImpl);
 
     // Check to see if the assembly has the IDispatchImplType attribute set.
-    hr = pAssembly->GetManifestImport()->GetCustomAttributeByName(pAssembly->GetManifestToken(), INTEROP_IDISPATCHIMPL_TYPE, (const void**)&pVal, &cbVal);
+    hr = pAssembly->GetCustomAttribute(pAssembly->GetManifestToken(), WellKnownAttribute::IDispatchImpl, (const void**)&pVal, &cbVal);
     if (hr == S_OK)
     {
         CustomAttributeParser cap(pVal, cbVal);
index 58cbdb0..8125f89 100644 (file)
@@ -1071,7 +1071,7 @@ PCODE COMDelegate::ConvertToCallback(MethodDesc* pMD)
     LONG cData = 0;
     CorPinvokeMap callConv = (CorPinvokeMap)0;
 
-    HRESULT hr = pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), g_NativeCallableAttribute, (const VOID **)(&pData), (ULONG *)&cData);
+    HRESULT hr = pMD->GetCustomAttribute(WellKnownAttribute::NativeCallable, (const VOID **)(&pData), (ULONG *)&cData);
     IfFailThrow(hr);
 
     if (cData > 0)
index e53cd2f..f2a8e33 100644 (file)
@@ -214,24 +214,15 @@ void ComMTMemberInfoMap::Init(size_t sizeOfPtr)
     CONTRACTL_END;
 
     HRESULT     hr = S_OK;
-    mdTypeDef   td;                     // Token for the class.
     BYTE const  *pData;                 // Pointer to a custom attribute blob.
     ULONG       cbData;                 // Size of a custom attribute blob.
 
-    // Get the TypeDef and some info about it.
-    td = m_pMT->GetCl();
-
     m_bHadDuplicateDispIds = FALSE;
 
     // See if there is a default property.
     m_DefaultProp[0] = 0; // init to 'none'.
-    hr = m_pMT->GetMDImport()->GetCustomAttributeByName(
-        td, INTEROP_DEFAULTMEMBER_TYPE, reinterpret_cast<const void**>(&pData), &cbData);
-    if (hr == S_FALSE)
-    {
-        hr = m_pMT->GetMDImport()->GetCustomAttributeByName(
-            td, "System.Reflection.DefaultMemberAttribute", reinterpret_cast<const void**>(&pData), &cbData);
-    }
+    hr = m_pMT->GetCustomAttribute(
+        WellKnownAttribute::DefaultMember, reinterpret_cast<const void**>(&pData), &cbData);
     
     if (hr == S_OK && cbData > 5 && pData[0] == 1 && pData[1] == 0)
     {
index a527c6e..362759a 100644 (file)
@@ -1119,7 +1119,7 @@ void ComCallMethodDesc::InitNativeInfo()
             // Look up the best fit mapping info via Assembly & Interface level attributes
             BOOL BestFit = TRUE;
             BOOL ThrowOnUnmappableChar = FALSE;
-            ReadBestFitCustomAttribute(fsig.GetModule()->GetMDImport(), pFD->GetEnclosingMethodTable()->GetCl(), &BestFit, &ThrowOnUnmappableChar);
+            ReadBestFitCustomAttribute(fsig.GetModule(), pFD->GetEnclosingMethodTable()->GetCl(), &BestFit, &ThrowOnUnmappableChar);
 
             MarshalInfo info(fsig.GetModule(), fsig.GetArgProps(), fsig.GetSigTypeContext(), pFD->GetMemberDef(), MarshalInfo::MARSHAL_SCENARIO_COMINTEROP,
                              (CorNativeLinkType)0, (CorNativeLinkFlags)0, 
@@ -1423,7 +1423,7 @@ void ComCall::PopulateComCallMethodDesc(ComCallMethodDesc *pCMD, DWORD *pdwStubF
         _ASSERTE(IsMemberVisibleFromCom(pFD->GetApproxEnclosingMethodTable(), pFD->GetMemberDef(), mdTokenNil) && "Calls are not permitted on this member since it isn't visible from COM. The only way you can have reached this code path is if your native interface doesn't match the managed interface.");
 
         MethodTable *pMT = pFD->GetEnclosingMethodTable();
-        ReadBestFitCustomAttribute(pMT->GetMDImport(), pMT->GetCl(), &BestFit, &ThrowOnUnmappableChar);
+        ReadBestFitCustomAttribute(pMT->GetModule(), pMT->GetCl(), &BestFit, &ThrowOnUnmappableChar);
     }
     else
     {
index 56f5c93..8f3458d 100644 (file)
@@ -2716,7 +2716,7 @@ void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
     }
     else
     {
-        ReadBestFitCustomAttribute(m_pModule->GetMDImport(), mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
+        ReadBestFitCustomAttribute(m_pModule, mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
     }
 
     SetBestFitMapping (bBestFit);
@@ -2790,8 +2790,8 @@ PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOn
     LONG cData = 0;
     CorPinvokeMap callConv = (CorPinvokeMap)0;
 
-    HRESULT hRESULT = pMT->GetMDImport()->GetCustomAttributeByName(
-        pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, (const VOID **)(&pData), (ULONG *)&cData);
+    HRESULT hRESULT = pMT->GetCustomAttribute(
+        WellKnownAttribute::UnmanagedFunctionPointer, (const VOID **)(&pData), (ULONG *)&cData);
     IfFailThrow(hRESULT);
     if (cData != 0)
     {
@@ -4657,15 +4657,14 @@ HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, Met
         if (pTargetMD->IsInterface())
         {
             _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
-            hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
-                pTargetMD->GetMemberDef(),
-                FORWARD_INTEROP_STUB_METHOD_TYPE,
+            hr = pTargetMD->GetCustomAttribute(
+                WellKnownAttribute::ManagedToNativeComInteropStub,
                 &pBytes,
                 &cbBytes);
                 
             if (FAILED(hr)) 
                 RETURN hr;
-            // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
+            // GetCustomAttribute returns S_FALSE when it cannot find the attribute but nothing fails...
             // Translate that to E_FAIL
             else if (hr == S_FALSE)
                 RETURN E_FAIL;               
index 0d994c1..8691f2b 100644 (file)
@@ -67,7 +67,6 @@ VOID ParseNativeType(Module*                     pModule,
                          LayoutRawFieldInfo*         pfwalk,
                          PCCOR_SIGNATURE             pNativeType,
                          ULONG                       cbNativeType,
-                         IMDInternalImport*          pInternalImport,
                          mdTypeDef                   cl,
                          const SigTypeContext *      pTypeContext,
                          BOOL                       *pfDisqualifyFromManagedSequential  // set to TRUE if needed (never set to FALSE, it may come in as TRUE!)
@@ -217,7 +216,7 @@ do                                                      \
             {
                 if (fAnsi)
                 {
-                    ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                    ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                     INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
                 }
                 else
@@ -227,7 +226,7 @@ do                                                      \
             }
             else if (ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
             {
-                ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
             }
             else if (ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
@@ -518,7 +517,7 @@ do                                                      \
                     if (IsStructMarshalable(thNestedType))
                     {
 #ifdef _DEBUG
-                        INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable(), IsFixedBuffer(pfwalk->m_MD, pInternalImport)));
+                        INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable(), IsFixedBuffer(pfwalk->m_MD, pModule->GetMDImport())));
 #else
                         INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable()));
 #endif
@@ -624,7 +623,7 @@ do                                                      \
 #endif // FEATURE_COMINTEROP
                     if (fAnsi)
                     {
-                        ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                        ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                         INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
                     }
                     else
@@ -637,7 +636,7 @@ do                                                      \
                     switch (ntype)
                     {
                         case NATIVE_TYPE_LPSTR:
-                            ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                            ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                             INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
                             break;
 
@@ -682,7 +681,7 @@ do                                                      \
 
                                 if (fAnsi)
                                 {
-                                    ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                                    ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                                     INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar));
                                 }
                                 else
@@ -786,7 +785,7 @@ do                                                      \
                     // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
 
                     // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
-                    INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, VT_BSTR, g_pStringClass));
+                    INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pModule, cl, numElements, VT_BSTR, g_pStringClass));
                 }
             }
 #endif // FEATURE_CLASSIC_COMINTEROP
@@ -929,7 +928,7 @@ do                                                      \
                     // We need to special case fixed sized arrays of ANSI chars since the OleVariant code
                     // that is used by the generic fixed size array marshaller doesn't support them
                     // properly. 
-                    ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
+                    ReadBestFitCustomAttribute(pModule, cl, &BestFit, &ThrowOnUnmappableChar);
                     INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar));
                     break;                    
                 }
@@ -937,7 +936,7 @@ do                                                      \
                 {
                     VARTYPE elementVT = arrayMarshalInfo.GetElementVT();
 
-                    INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
+                    INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pModule, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
                     break;
                 }
             }
@@ -2728,7 +2727,7 @@ VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue,
 // Embedded array
 // See FieldMarshaler for details.
 //=======================================================================
-FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
+FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(Module *pModule, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
 : m_numElems(numElems)
 , m_vt(vt)
 , m_BestFitMap(FALSE)
@@ -2750,7 +2749,7 @@ FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImpor
     {
         BOOL BestFitMap = FALSE;
         BOOL ThrowOnUnmappableChar = FALSE;
-        ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar);      
+        ReadBestFitCustomAttribute(pModule, cl, &BestFitMap, &ThrowOnUnmappableChar);      
         m_BestFitMap = !!BestFitMap;
         m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar;
     }
index e3e0509..9e393b7 100644 (file)
@@ -103,7 +103,6 @@ VOID ParseNativeType(Module*    pModule,
     LayoutRawFieldInfo*         pfwalk,
     PCCOR_SIGNATURE             pNativeType,
     ULONG                       cbNativeType,
-    IMDInternalImport*          pInternalImport,
     mdTypeDef                   cl,
     const SigTypeContext *      pTypeContext,
     BOOL                       *pfDisqualifyFromManagedSequential
@@ -1024,7 +1023,7 @@ private:
 class FieldMarshaler_FixedArray : public FieldMarshaler
 {
 public:
-    FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT);
+    FieldMarshaler_FixedArray(Module *pModule, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT);
 
     VOID UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const;
     VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const;
index 7b24f9c..044cd2a 100644 (file)
@@ -898,24 +898,24 @@ void FillExceptionData(
 //---------------------------------------------------------------------------
 // If pImport has the DefaultDllImportSearchPathsAttribute, 
 // set the value of the attribute in pDlImportSearchPathFlags and return true.
-BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlags)
+BOOL GetDefaultDllImportSearchPathsAttributeValue(Module *pModule, mdToken token, DWORD * pDllImportSearchPathFlags)
 {
     CONTRACTL
     {
         THROWS;
         GC_NOTRIGGER;
         MODE_ANY;
-        PRECONDITION(CheckPointer(pImport));
+        PRECONDITION(CheckPointer(pModule));
     }
     CONTRACTL_END;
 
     BYTE* pData = NULL;
     LONG cData = 0;
 
-    HRESULT hr = pImport->GetCustomAttributeByName(token,
-                                                   g_DefaultDllImportSearchPathsAttribute,
-                                                   (const VOID **)(&pData),
-                                                   (ULONG *)&cData);
+    HRESULT hr = pModule->GetCustomAttribute(token,
+                                            WellKnownAttribute::DefaultDllImportSearchPaths,
+                                            (const VOID **)(&pData),
+                                            (ULONG *)&cData);
 
     IfFailThrow(hr);
     if(cData == 0 )
@@ -954,7 +954,7 @@ int GetLCIDParameterIndex(MethodDesc *pMD)
     if (!pMD->GetMethodTable()->IsProjectedFromWinRT()) //  ignore LCIDConversionAttribute on WinRT methods
     {
         // Check to see if the method has the LCIDConversionAttribute.
-        hr = pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), INTEROP_LCIDCONVERSION_TYPE, (const void**)&pVal, &cbVal);
+        hr = pMD->GetCustomAttribute(WellKnownAttribute::LCIDConversion, (const void**)&pVal, &cbVal);
         if (hr == S_OK)
         {
             CustomAttributeParser caLCID(pVal, cbVal);
@@ -1030,6 +1030,7 @@ BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef m
     DWORD                   dwFlags;
 
     IMDInternalImport *pInternalImport = pDeclaringMT->GetMDImport();
+    Module *pModule = pDeclaringMT->GetModule();
 
     // Check to see if the member is public.
     switch (TypeFromToken(tk))
@@ -1077,7 +1078,7 @@ BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef m
             if (!pDeclaringMT->IsProjectedFromWinRT() && !pDeclaringMT->IsExportedToWinRT() && !pDeclaringMT->IsWinRTObjectType())
             {
                 // Check to see if the associate has the ComVisible attribute set (non-WinRT members only).
-                hr = pInternalImport->GetCustomAttributeByName(mdAssociate, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
+                hr = pModule->GetCustomAttribute(mdAssociate, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
                 if (hr == S_OK)
                 {
                     CustomAttributeParser cap(pVal, cbVal);
@@ -1101,7 +1102,7 @@ BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef m
     if (!pDeclaringMT->IsProjectedFromWinRT() && !pDeclaringMT->IsExportedToWinRT() && !pDeclaringMT->IsWinRTObjectType())
     {
         // Check to see if the member has the ComVisible attribute set (non-WinRT members only).
-        hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
+        hr = pModule->GetCustomAttribute(tk, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
         if (hr == S_OK)
         {
             CustomAttributeParser cap(pVal, cbVal);
@@ -1321,7 +1322,7 @@ HRESULT GetStringizedTypeLibGuidForAssembly(Assembly *pAssembly, CQuickArray<BYT
     {
         // If the ComCompatibleVersionAttribute is set, then use the version
         // number in the attribute when generating the GUID.
-        IfFailGo(pAssembly->GetManifestImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_COMCOMPATIBLEVERSION_TYPE, (const void**)&pbData, &cbData));
+        IfFailGo(pAssembly->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::ComCompatibleVersion, (const void**)&pbData, &cbData));
     }
 
     if (hr == S_OK && cbData >= (2 + 4 * sizeof(INT32)))
@@ -1635,13 +1636,13 @@ ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappab
     }
     CONTRACTL_END;
     
-    ReadBestFitCustomAttribute(pMD->GetMDImport(),
+    ReadBestFitCustomAttribute(pMD->GetModule(),
         pMD->GetMethodTable()->GetCl(),
         BestFit, ThrowOnUnmappableChar);
 }
 
 VOID
-ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
+ReadBestFitCustomAttribute(Module* pModule, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
 {
     // Set the attributes to their defaults, just to be safe.
     *BestFit = TRUE;
@@ -1652,7 +1653,7 @@ ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOO
         NOTHROW;
         GC_NOTRIGGER;
         MODE_ANY;
-        PRECONDITION(CheckPointer(pInternalImport));
+        PRECONDITION(CheckPointer(pModule));
     }
     CONTRACTL_END;
     
@@ -1668,7 +1669,7 @@ ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOO
     // 30 for the ThrowOnUnmappableChar bool
 
     // Try the assembly first
-    hr = pInternalImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_BESTFITMAPPING_TYPE, (const VOID**)(&pData), &cbCount);
+    hr = pModule->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::BestFitMapping, (const VOID**)(&pData), &cbCount);
     if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
     {
         _ASSERTE((cbCount == 5) || (cbCount == 30));
@@ -1685,7 +1686,7 @@ ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOO
     // Now try the interface/class/struct
     if (IsNilToken(cl))
         return;
-    hr = pInternalImport->GetCustomAttributeByName(cl, INTEROP_BESTFITMAPPING_TYPE, (const VOID**)(&pData), &cbCount);
+    hr = pModule->GetCustomAttribute(cl, WellKnownAttribute::BestFitMapping, (const VOID**)(&pData), &cbCount);
     if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
     {
         _ASSERTE((cbCount == 5) || (cbCount == 30));
@@ -1781,7 +1782,7 @@ int InternalWideToAnsi(__in_ecount(iNumWideChars) LPCWSTR szWideString, int iNum
 namespace
 {
     HRESULT TryParseClassInterfaceAttribute(
-        _In_ IMDInternalImport *import,
+        _In_ Module *pModule,
         _In_ mdToken tkObj,
         _Out_ CorClassIfaceAttr *val)
     {
@@ -1790,14 +1791,14 @@ namespace
             NOTHROW;
             GC_TRIGGERS;
             MODE_ANY;
-            PRECONDITION(CheckPointer(import));
+            PRECONDITION(CheckPointer(pModule));
             PRECONDITION(CheckPointer(val));
         }
         CONTRACTL_END
 
         const BYTE *pVal = nullptr;
         ULONG cbVal = 0;
-        HRESULT hr = import->GetCustomAttributeByName(tkObj, INTEROP_CLASSINTERFACE_TYPE, (const void**)&pVal, &cbVal);
+        HRESULT hr = pModule->GetCustomAttribute(tkObj, WellKnownAttribute::ClassInterface, (const void**)&pVal, &cbVal);
         if (hr != S_OK)
         {
             *val = clsIfNone;
@@ -1840,7 +1841,7 @@ CorClassIfaceAttr ReadClassInterfaceTypeCustomAttribute(TypeHandle type)
         CorClassIfaceAttr attrValueMaybe;
 
         // First look for the class interface attribute at the class level.
-        HRESULT hr = TryParseClassInterfaceAttribute(type.GetMethodTable()->GetMDImport(), type.GetCl(), &attrValueMaybe);
+        HRESULT hr = TryParseClassInterfaceAttribute(type.GetModule(), type.GetCl(), &attrValueMaybe);
         if (FAILED(hr))
             ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
 
@@ -1848,7 +1849,7 @@ CorClassIfaceAttr ReadClassInterfaceTypeCustomAttribute(TypeHandle type)
         {
             // Check the class interface attribute at the assembly level.
             Assembly *pAssembly = type.GetAssembly();
-            hr = TryParseClassInterfaceAttribute(pAssembly->GetManifestImport(), pAssembly->GetManifestToken(), &attrValueMaybe);
+            hr = TryParseClassInterfaceAttribute(pAssembly->GetManifestModule(), pAssembly->GetManifestToken(), &attrValueMaybe);
             if (FAILED(hr))
                 ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
         }
@@ -2604,7 +2605,7 @@ BOOL ClassSupportsIClassX(MethodTable *pMT)
     }
 
     // If the class is decorated with an explicit ClassInterfaceAttribute, we're going to say yes.
-    if (S_OK == pMT->GetMDImport()->GetCustomAttributeByName(pMT->GetCl(), INTEROP_CLASSINTERFACE_TYPE, NULL, NULL))
+    if (S_OK == pMT->GetCustomAttribute(WellKnownAttribute::ClassInterface, NULL, NULL))
         return TRUE;
 
     MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
@@ -2769,7 +2770,7 @@ DefaultInterfaceType GetDefaultInterfaceForClassInternal(TypeHandle hndClass, Ty
         return DefaultInterfaceType_IUnknown;
     
     // Start by checking for the ComDefaultInterface attribute.
-    hr = pClassMT->GetMDImport()->GetCustomAttributeByName(pClassMT->GetCl(), INTEROP_COMDEFAULTINTERFACE_TYPE, &pvData, &cbData);
+    hr = pClassMT->GetCustomAttribute(WellKnownAttribute::ComDefaultInterface, &pvData, &cbData);
     IfFailThrow(hr);
     if (hr == S_OK && cbData > 2)
     {
@@ -3043,7 +3044,7 @@ void GetComSourceInterfacesForClass(MethodTable *pMT, CQuickArray<MethodTable *>
     for (; pMT != NULL; pMT = pMT->GetParentMethodTable())
     {
         // See if there is any [source] interface at this level of the hierarchy.
-        hr = pMT->GetMDImport()->GetCustomAttributeByName(pMT->GetCl(), INTEROP_COMSOURCEINTERFACES_TYPE, &pvData, &cbData);
+        hr = pMT->GetCustomAttribute(WellKnownAttribute::ComSourceInterfaces, &pvData, &cbData);
         IfFailThrow(hr);
         if (hr == S_OK && cbData > 2)
         {
@@ -3565,6 +3566,7 @@ static BOOL SpecialIsGenericTypeVisibleFromCom(TypeHandle hndType)
     mdTypeDef               mdType = pMT->GetCl();
     IMDInternalImport *     pInternalImport = pMT->GetMDImport();
     Assembly *              pAssembly = pMT->GetAssembly();
+    Module *                pModule = pMT->GetModule();
 
     // If the type is a COM imported interface then it is visible from COM.
     if (pMT->IsInterface() && pMT->IsComImport())
@@ -3606,7 +3608,7 @@ static BOOL SpecialIsGenericTypeVisibleFromCom(TypeHandle hndType)
         return FALSE;
 
     // Check to see if the type has the ComVisible attribute set.
-    hr = pInternalImport->GetCustomAttributeByName(mdType, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
+    hr = pModule->GetCustomAttribute(mdType, WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
     if (hr == S_OK)
     {
         CustomAttributeParser cap(pVal, cbVal);
@@ -3621,7 +3623,7 @@ static BOOL SpecialIsGenericTypeVisibleFromCom(TypeHandle hndType)
     }
 
     // Check to see if the assembly has the ComVisible attribute set.
-    hr = pAssembly->GetManifestImport()->GetCustomAttributeByName(pAssembly->GetManifestToken(), INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
+    hr = pModule->GetCustomAttribute(pAssembly->GetManifestToken(), WellKnownAttribute::ComVisible, (const void**)&pVal, &cbVal);
     if (hr == S_OK)
     {
         CustomAttributeParser cap(pVal, cbVal);
index 311cedd..bcb0a97 100644 (file)
@@ -118,7 +118,7 @@ BOOL IsComObjectClass(TypeHandle type);
 // both assembly level and interface level
 //---------------------------------------------------------
 VOID ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappableChar);
-VOID ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar);
+VOID ReadBestFitCustomAttribute(Module* pModule, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar);
 int  InternalWideToAnsi(__in_ecount(iNumWideChars) LPCWSTR szWideString, int iNumWideChars, __out_ecount_opt(cbAnsiBufferSize) LPSTR szAnsiString, int cbAnsiBufferSize, BOOL fBestFit, BOOL fThrowOnUnmappableChar);
 
 //---------------------------------------------------------
@@ -138,7 +138,7 @@ void FillExceptionData(
 //---------------------------------------------------------------------------
 // If pImport has the DefaultDllImportSearchPathsAttribute, 
 // set the value of the attribute in pDlImportSearchPathFlags and return true.
-BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDlImportSearchPathFlags);
+BOOL GetDefaultDllImportSearchPathsAttributeValue(Module *pModule, mdToken token, DWORD * pDlImportSearchPathFlags);
 
 //---------------------------------------------------------------------------
 // Returns the index of the LCID parameter if one exists and -1 otherwise.
index bd4ad09..2f4a8d9 100644 (file)
@@ -1755,34 +1755,6 @@ FCIMPL2(void, MarshalNative::DoGetTypeLibGuidForAssembly, GUID * result, Assembl
 }
 FCIMPLEND
 
-FCIMPL3(void, MarshalNative::GetTypeLibVersionForAssembly, AssemblyBaseObject* refAsmUNSAFE, INT32 *pMajorVersion, INT32 *pMinorVersion)
-{
-    FCALL_CONTRACT;
-
-    // Validate the arguments.
-    _ASSERTE(refAsmUNSAFE != NULL);
-
-    ASSEMBLYREF refAsm = (ASSEMBLYREF) refAsmUNSAFE;
-    HELPER_METHOD_FRAME_BEGIN_1(refAsm);
-
-    HRESULT hr = S_OK;
-
-    // Retrieve the assembly from the ASSEMBLYREF.
-    Assembly *pAssembly = refAsm->GetAssembly();
-    _ASSERTE(pAssembly);
-
-    // Retrieve the version for the assembly.
-    USHORT usMaj, usMin;
-    IfFailThrow(::GetTypeLibVersionForAssembly(pAssembly, &usMaj, &usMin));
-
-    // Set the out parameters.
-    *pMajorVersion = usMaj;
-    *pMinorVersion = usMin;
-
-    HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
 FCIMPL1(int, MarshalNative::GetStartComSlot, ReflectClassBaseObject* tUNSAFE)
 {
     FCALL_CONTRACT;
index bac0c24..089ed6c 100644 (file)
@@ -205,12 +205,6 @@ public:
     static FCDECL2(void, DoGetTypeLibGuidForAssembly, GUID * result, AssemblyBaseObject* refAsmUNSAFE);
 
     //====================================================================
-    // Given a assembly, return the version number of the type library
-    // that would be exported from the assembly.
-    //====================================================================
-    static FCDECL3(void, GetTypeLibVersionForAssembly, AssemblyBaseObject* refAsmUNSAFE, INT32 *pMajorVersion, INT32 *pMinorVersion);
-
-    //====================================================================
     // These methods are used to map COM slots to method info's.
     //====================================================================
     static FCDECL1(int, GetStartComSlot, ReflectClassBaseObject* tUNSAFE);
index 2f6a9b4..31c4974 100644 (file)
@@ -157,7 +157,7 @@ BOOL NDirectMethodDesc::HasDefaultDllImportSearchPathsAttribute()
 
     _ASSERTE(!IsZapped());
 
-    BOOL attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(GetMDImport(),GetMemberDef(),&ndirect.m_DefaultDllImportSearchPathsAttributeValue);
+    BOOL attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(GetModule(),GetMemberDef(),&ndirect.m_DefaultDllImportSearchPathsAttributeValue);
 
     if(attributeIsFound )
     {
@@ -5281,8 +5281,8 @@ BOOL MethodDesc::HasNativeCallableAttribute()
     }
     CONTRACTL_END;
 
-    HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetMemberDef(),
-        g_NativeCallableAttribute,
+    HRESULT hr = GetModule()->GetCustomAttribute(GetMemberDef(),
+        WellKnownAttribute::NativeCallable,
         NULL,
         NULL);
     if (hr == S_OK)
index cf532f8..7722097 100644 (file)
@@ -866,6 +866,16 @@ public:
         return pModule->GetMDImport();
     }
 
+    HRESULT GetCustomAttribute(WellKnownAttribute attribute,
+                               const void  **ppData,
+                               ULONG *pcbData) const
+    {
+        WRAPPER_NO_CONTRACT;
+        Module *pModule = GetModule();
+        PREFIX_ASSUME(pModule != NULL);
+        return pModule->GetCustomAttribute(GetMemberDef(), attribute, ppData, pcbData);
+    }
+
 #ifndef DACCESS_COMPILE 
     IMetaDataEmit* GetEmitter()
     {
index 3fe016f..2b7c516 100644 (file)
@@ -63,6 +63,7 @@ class   ComCallWrapperTemplate;
 class ClassFactoryBase;
 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
 class ArgDestination;
+enum class WellKnownAttribute : DWORD;
 
 //============================================================================
 // This is the in-memory structure of a class and it will evolve.
@@ -2868,6 +2869,10 @@ public:
 
     // Get the MD Import for the metadata for the corresponding type declaration
     IMDInternalImport* GetMDImport();
+
+    HRESULT GetCustomAttribute(WellKnownAttribute attribute,
+                               const void  **ppData,
+                               ULONG *pcbData);
     
     mdTypeDef GetEnclosingCl();
 
index 31e373c..de3e982 100644 (file)
@@ -1194,6 +1194,15 @@ inline IMDInternalImport* MethodTable::GetMDImport()
 }
 
 //==========================================================================================
+inline HRESULT MethodTable::GetCustomAttribute(
+                               WellKnownAttribute attribute,
+                               const void  **ppData,
+                               ULONG *pcbData)
+{
+    return GetModule()->GetCustomAttribute(GetCl(), attribute, ppData, pcbData);
+}
+
+//==========================================================================================
 inline BOOL MethodTable::IsSealed()
 {
     LIMITED_METHOD_CONTRACT;
index 91a888a..0bafe59 100644 (file)
@@ -1420,17 +1420,17 @@ MethodTableBuilder::BuildMethodTableThrowing(
     {
         bmtProp->fIsValueClass = true;
 
-        HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
-                                                                g_CompilerServicesUnsafeValueTypeAttribute,
-                                                                NULL, NULL);
+        HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
+                                        WellKnownAttribute::UnsafeValueType,
+                                        NULL, NULL);
         IfFailThrow(hr);
         if (hr == S_OK)
         {
             SetUnsafeValueClass();
         }
 
-        hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
-            g_CompilerServicesIsByRefLikeAttribute,
+        hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
+            WellKnownAttribute::IsByRefLike,
             NULL, NULL);
         IfFailThrow(hr);
         if (hr == S_OK)
@@ -1486,8 +1486,8 @@ MethodTableBuilder::BuildMethodTableThrowing(
     // We check this here fairly early to ensure other downstream checks on these types can be slightly more efficient.
     if (GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly())
     {
-        HRESULT hr = GetMDImport()->GetCustomAttributeByName(bmtInternal->pType->GetTypeDefToken(),
-            g_CompilerServicesIntrinsicAttribute,
+        HRESULT hr = GetCustomAttribute(bmtInternal->pType->GetTypeDefToken(),
+            WellKnownAttribute::Intrinsic,
             NULL,
             NULL);
 
@@ -3389,9 +3389,9 @@ MethodTableBuilder::EnumerateClassFields()
 
                 // If this static field is thread static, then we need
                 // to increment bmtEnumFields->dwNumThreadStaticFields
-                hr = pMDInternalImport->GetCustomAttributeByName(tok,
-                                                                 g_ThreadStaticAttributeClassName,
-                                                                 NULL, NULL);
+                hr = GetCustomAttribute(tok,
+                                        WellKnownAttribute::ThreadStatic,
+                                        NULL, NULL);
                 IfFailThrow(hr);
                 if (hr == S_OK)
                 {
@@ -3794,9 +3794,9 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
 
             HRESULT hr;
  
-            hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
-                                                           g_ThreadStaticAttributeClassName,
-                                                           NULL, NULL);
+            hr = GetCustomAttribute(bmtMetaData->pFields[i],
+                                    WellKnownAttribute::ThreadStatic,
+                                    NULL, NULL);
             IfFailThrow(hr);
             if (hr == S_OK)
             {
@@ -3806,9 +3806,9 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
 
             if (ElementType == ELEMENT_TYPE_VALUETYPE)
             {
-                hr = pInternalImport->GetCustomAttributeByName(bmtMetaData->pFields[i],
-                                                               g_CompilerServicesFixedAddressValueTypeAttribute,
-                                                               NULL, NULL);
+                hr = GetCustomAttribute(bmtMetaData->pFields[i],
+                                        WellKnownAttribute::FixedAddressValueType,
+                                        NULL, NULL);
                 IfFailThrow(hr);
                 if (hr == S_OK)
                 {
@@ -5124,12 +5124,10 @@ MethodTableBuilder::InitNewMethodDesc(
     // Check for methods marked as [Intrinsic]
     if (GetModule()->IsSystem() || GetAssembly()->IsSIMDVectorAssembly())
     {
-        HRESULT hr = GetMDImport()->GetCustomAttributeByName(pMethod->GetMethodSignature().GetToken(),
-            g_CompilerServicesIntrinsicAttribute,
-            NULL,
-            NULL);
-
-        if (hr == S_OK || bmtProp->fIsHardwareIntrinsic)
+        if (bmtProp->fIsHardwareIntrinsic || (S_OK == GetCustomAttribute(pMethod->GetMethodSignature().GetToken(),
+                                                    WellKnownAttribute::Intrinsic,
+                                                    NULL,
+                                                    NULL)))
         {
             pNewMD->SetIsJitIntrinsic();
         }
@@ -10358,7 +10356,7 @@ MethodTableBuilder::SetupMethodTable2(
         {
             const BYTE *        pVal;                 
             ULONG               cbVal;        
-            HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), g_WindowsFoundationMarshalingBehaviorAttributeClassName, (const void **) &pVal, &cbVal);
+            HRESULT hr = GetCustomAttribute(GetCl(), WellKnownAttribute::WinRTMarshalingBehaviorAttribute, (const void **) &pVal, &cbVal);
             if (hr == S_OK)
             {
                 CustomAttributeParser cap(pVal, cbVal);
@@ -11240,7 +11238,7 @@ VOID MethodTableBuilder::CheckForSpecialTypes()
     // Check to see if the type is a COM event interface (classic COM interop only).
     if (IsInterface() && !GetHalfBakedClass()->IsProjectedFromWinRT())
     {
-        HRESULT hr = pMDImport->GetCustomAttributeByName(GetCl(), INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
+        HRESULT hr = GetCustomAttribute(GetCl(), WellKnownAttribute::ComEventInterface, NULL, NULL);
         if (hr == S_OK)
         {
             bmtProp->fComEventItfType = true;
@@ -11608,7 +11606,7 @@ void MethodTableBuilder::GetCoClassAttribInfo()
     if (!GetHalfBakedClass()->IsProjectedFromWinRT()) // ignore classic COM interop CA on WinRT interfaces
     {
         // Retrieve the CoClassAttribute CA.
-        HRESULT hr = GetMDImport()->GetCustomAttributeByName(GetCl(), INTEROP_COCLASS_TYPE, NULL, NULL);
+        HRESULT hr = GetCustomAttribute(GetCl(), WellKnownAttribute::CoClass, NULL, NULL);
         if (hr == S_OK)
         {
             // COM class interfaces may lazily populate the m_pCoClassForIntf field of EEClass. This field is
index 82f1c4f..c309fd5 100644 (file)
@@ -185,6 +185,18 @@ private:
     PTR_EEClass GetHalfBakedClass() { LIMITED_METHOD_CONTRACT; return m_pHalfBakedClass; }
     PTR_MethodTable GetHalfBakedMethodTable() { LIMITED_METHOD_CONTRACT; return m_pHalfBakedMT; } 
 
+    HRESULT GetCustomAttribute(mdToken parentToken, WellKnownAttribute attribute, const void  **ppData, ULONG *pcbData)
+    {
+        WRAPPER_NO_CONTRACT;
+        if (GetModule()->IsReadyToRun())
+        {
+            if (!GetModule()->GetReadyToRunInfo()->MayHaveCustomAttribute(attribute, parentToken))
+                return S_FALSE;
+        }
+
+        return GetMDImport()->GetCustomAttributeByName(parentToken, GetWellKnownAttributeName(attribute), ppData, pcbData);
+    }
+
     // <NOTE> The following functions are used during MethodTable construction to access/set information about the type being constructed.
     // Beware that some of the fields of the underlying EEClass/MethodTable being constructed may not
     // be initialized.  Because of this, ideally the code will gradually be cleaned up so that
index c4696bc..8a1eda0 100644 (file)
@@ -2961,7 +2961,7 @@ lExit:
                     if (SUCCEEDED(pInternalImport->GetDefaultValue(token, &defaultValue)) && defaultValue.m_bType == ELEMENT_TYPE_VOID)
                     {
                         // check if it has params attribute
-                        if (pInternalImport->GetCustomAttributeByName(token, INTEROP_PARAMARRAY_TYPE, 0,0) == S_OK)
+                        if (pModule->GetCustomAttribute(token, WellKnownAttribute::ParamArray, 0,0) == S_OK)
                             m_fOleVarArgCandidate = TRUE;
                     }
                 }
index 4182b03..c97f324 100644 (file)
 
 #pragma once
 
+#ifndef DACCESS_COMPILE
+
+#if defined(_AMD64_) || defined(_X86_)
+#include "emmintrin.h"
+#define USE_INTEL_INTRINSICS_FOR_CUCKOO_FILTER
+#elif defined(_ARM_) || defined(_ARM64_) 
+
+#ifndef FEATURE_PAL // The Mac and Linux build environments are not setup for NEON simd.
+#define USE_ARM_INTRINSICS_FOR_CUCKOO_FILTER
+
+#if defined(_ARM_)
+#include "arm_neon.h"
+#else
+#include "arm64_neon.h"
+#endif
+#endif // FEATURE_PAL
+
+#endif // _ARM_ || _ARM64_
+
+#endif // DACCESS_COMPILE
+
 // To reduce differences between C# and C++ versions
 #define byte uint8_t
 #define uint uint32_t
@@ -45,7 +66,7 @@ namespace NativeFormat
         {
             _ASSERTE(false);
 
-#ifndef DACCESS_COMPILE
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
             // Failfast instead of throwing, to avoid violating NOTHROW contracts of callers
             EEPOLICY_HANDLE_FATAL_ERROR(COR_E_BADIMAGEFORMAT);
 #endif
@@ -523,4 +544,125 @@ namespace NativeFormat
             return Enumerator(parser, endOffset, (byte)hashcode);
         }
     };
+
+    class NativeCuckooFilter;
+    typedef DPTR(NativeCuckooFilter) PTR_NativeCuckooFilter;
+
+    class NativeCuckooFilter
+    {
+        PTR_BYTE _base;
+        UInt32 _size;
+        LONG _disableFilter;
+        
+        bool IsPowerOfTwo(UInt32 number)
+        {
+            return (number & (number - 1)) == 0;
+        }
+  
+    public:
+        static UInt32 ComputeFingerprintHash(UInt16 fingerprint)
+        {
+            // As the number of buckets is not reasonably greater than 65536, just use fingerprint as its own hash
+            // This implies that the hash of the entrypoint should be an independent hash function as compared
+            // to the fingerprint
+            return fingerprint;
+        }
+
+        NativeCuckooFilter()
+        {
+            _base = NULL;
+            _size = 0;
+            _disableFilter = 0;
+        }
+
+        NativeCuckooFilter(PTR_BYTE base_, UInt32 size, UInt32 rvaOfTable, UInt32 filterSize)
+        {
+            if (((rvaOfTable & 0xF) != 0) || ((filterSize & 0xF) != 0))
+            {
+                // Native cuckoo filters must be aligned at 16byte boundaries within the PE file
+                NativeReader exceptionReader;
+                exceptionReader.ThrowBadImageFormatException();
+            }
+            if ((filterSize != 0) && !IsPowerOfTwo(filterSize))
+            {
+                // Native cuckoo filters must be power of two in size
+                NativeReader exceptionReader;
+                exceptionReader.ThrowBadImageFormatException();
+            }
+            _base = base_ + rvaOfTable;
+            _size = filterSize;
+            _disableFilter = 0;
+        }
+
+        void DisableFilter()
+        {
+            // Set disable filter flag using interlocked to ensure that future
+            // attempts to read the filter will capture the change.
+            InterlockedExchange(&_disableFilter, 1);
+        }
+
+        bool HashComputationImmaterial()
+        {
+            if ((_base == NULL) || (_size == 0))
+                return true;
+            return false;
+        }
+
+        bool MayExist(UInt32 hashcode, UInt16 fingerprint)
+        {
+            if ((_base == NULL) || (_disableFilter))
+                return true;
+
+            if (_size == 0)
+                return false; // Empty table means none of the attributes exist
+
+            // Fingerprints of 0 don't actually exist. Just use 1, and lose some entropy
+            if (fingerprint == 0)
+                fingerprint = 1;
+
+            UInt32 bucketCount = _size / 16;
+            UInt32 bucketMask = bucketCount - 1; // filters are power of 2 in size
+
+            UInt32 bucketAIndex = hashcode & bucketMask;
+            UInt32 bucketBIndex = bucketAIndex ^ (ComputeFingerprintHash(fingerprint) & bucketMask);
+
+#if defined(USE_INTEL_INTRINSICS_FOR_CUCKOO_FILTER)
+            __m128i bucketA = _mm_loadu_si128(&((__m128i*)_base)[bucketAIndex]);
+            __m128i bucketB = _mm_loadu_si128(&((__m128i*)_base)[bucketBIndex]);
+            __m128i fingerprintSIMD = _mm_set1_epi16(fingerprint);
+            __m128i bucketACompare = _mm_cmpeq_epi16(bucketA, fingerprintSIMD);
+            __m128i bucketBCompare = _mm_cmpeq_epi16(bucketB, fingerprintSIMD);
+            __m128i bothCompare = _mm_or_si128(bucketACompare, bucketBCompare);
+            return !!_mm_movemask_epi8(bothCompare);
+#elif defined(USE_ARM_INTRINSICS_FOR_CUCKOO_FILTER)
+            uint16x8_t bucketA = vld1q_u16((uint16_t*)&((uint16x8_t*)_base)[bucketAIndex]);
+            uint16x8_t bucketB = vld1q_u16((uint16_t*)&((uint16x8_t*)_base)[bucketBIndex]);
+            uint16x8_t fingerprintSIMD = vdupq_n_u16(fingerprint);
+            uint16x8_t bucketACompare = vceqq_u16(bucketA, fingerprintSIMD);
+            uint16x8_t bucketBCompare = vceqq_u16(bucketB, fingerprintSIMD);
+            uint16x8_t bothCompare = vorrq_u16(bucketACompare, bucketBCompare);
+            uint64_t bits0Lane = vgetq_lane_u64(bothCompare, 0);
+            uint64_t bits1Lane = vgetq_lane_u64(bothCompare, 1);
+            return !!(bits0Lane | bits1Lane);
+#else // Non-intrinsic implementation supporting NativeReader to cross DAC boundary
+            NativeReader reader(_base, _size);
+
+            // Check for existence in bucketA
+            for (int i = 0; i < 8; i++)
+            {
+                if (reader.ReadUInt16(bucketAIndex * 16 + i * sizeof(UInt16)) == fingerprint)
+                    return true;
+            }
+
+            // Check for existence in bucketB
+            for (int i = 0; i < 8; i++)
+            {
+                if (reader.ReadUInt16(bucketBIndex * 16 + i * sizeof(UInt16)) == fingerprint)
+                    return true;
+            }
+
+            return false;
+#endif
+        }
+    };
 }
index 3307fe2..86eb372 100644 (file)
@@ -16,6 +16,7 @@
 #include "versionresilienthashcode.h"
 #include "typehashingalgorithms.h"
 #include "method.hpp"
+#include "wellknownattributes.h"
 
 using namespace NativeFormat;
 
@@ -614,6 +615,18 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYT
         }
     }
 
+    // For format version 3.1 and later, there is an optional attributes section
+    IMAGE_DATA_DIRECTORY *attributesPresenceDataInfoDir = FindSection(READYTORUN_SECTION_ATTRIBUTEPRESENCE);
+    if (attributesPresenceDataInfoDir != NULL)
+    {
+        NativeCuckooFilter newFilter(
+            (byte *)pLayout->GetBase(),
+            pLayout->GetVirtualSize(),
+            attributesPresenceDataInfoDir->VirtualAddress,
+            attributesPresenceDataInfoDir->Size);
+
+        m_attributesPresence = newFilter;
+    }
 }
 
 static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
@@ -907,4 +920,31 @@ BOOL ReadyToRunInfo::IsImageVersionAtLeast(int majorVersion, int minorVersion)
 
 }
 
+static DWORD s_wellKnownAttributeHashes[(DWORD)WellKnownAttribute::CountOfWellKnownAttributes];
+
+bool ReadyToRunInfo::MayHaveCustomAttribute(WellKnownAttribute attribute, mdToken token)
+{
+    UINT32 hash = 0;
+    UINT16 fingerprint = 0;
+    if (!m_attributesPresence.HashComputationImmaterial())
+    {
+        DWORD wellKnownHash = s_wellKnownAttributeHashes[(DWORD)attribute];
+        if (wellKnownHash == 0)
+        {
+            // TODO, investigate using constexpr to compute string hashes at compile time initially
+            s_wellKnownAttributeHashes[(DWORD)attribute] = wellKnownHash = ComputeNameHashCode(GetWellKnownAttributeName(attribute));
+        }
+
+        hash = CombineTwoValuesIntoHash(wellKnownHash, token);
+        fingerprint = hash >> 16;
+    }
+    
+    return m_attributesPresence.MayExist(hash, fingerprint);
+}
+
+void ReadyToRunInfo::DisableCustomAttributeFilter()
+{
+    m_attributesPresence.DisableFilter();
+}
+
 #endif // DACCESS_COMPILE
index 9205ae1..65b49a6 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "nativeformatreader.h"
 #include "inlinetracking.h"
+#include "wellknownattributes.h"
 
 typedef DPTR(struct READYTORUN_SECTION) PTR_READYTORUN_SECTION;
 
@@ -40,6 +41,7 @@ class ReadyToRunInfo
     NativeFormat::NativeHashtable   m_instMethodEntryPoints;
     NativeFormat::NativeHashtable   m_availableTypesHashtable;
     NativeFormat::NativeHashtable   m_pMetaDataHashtable;
+    NativeFormat::NativeCuckooFilter m_attributesPresence;
 
     Crst                            m_Crst;
     PtrHashMap                      m_entryPointToMethodDescMap;
@@ -135,6 +137,9 @@ public:
         return m_pPersistentInlineTrackingMap;
     }
 
+    bool MayHaveCustomAttribute(WellKnownAttribute attribute, mdToken token);
+    void DisableCustomAttributeFilter();
+
 private:
     BOOL GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace);
     BOOL GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken);
index 0397b5a..8dfb1cd 100644 (file)
@@ -2745,9 +2745,9 @@ HRESULT TypeIdentifierData::Init(Module *pModule, mdToken tk)
     ULONG cbData;
     const BYTE *pData;
 
-    IfFailRet(pInternalImport->GetCustomAttributeByName(
+    IfFailRet(pModule->GetCustomAttribute(
         tk, 
-        g_TypeIdentifierAttributeClassName,
+        WellKnownAttribute::TypeIdentifier,
         (const void **)&pData, 
         &cbData));
     
@@ -2797,13 +2797,12 @@ HRESULT TypeIdentifierData::Init(Module *pModule, mdToken tk)
         if (IsTdInterface(dwAttrType) && IsTdImport(dwAttrType))
         {
             // ComImport interfaces get scope from their GUID
-            hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_GUID_TYPE, (const void **)&pData, &cbData);
+            hr = pModule->GetCustomAttribute(tk, WellKnownAttribute::Guid, (const void **)&pData, &cbData);
         }
         else
         {
             // other equivalent types get it from the declaring assembly
-            IMDInternalImport *pAssemblyImport = pModule->GetAssembly()->GetManifestImport();
-            hr = pAssemblyImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_GUID_TYPE, (const void **)&pData, &cbData);
+            hr = pModule->GetCustomAttribute(TokenFromRid(1, mdtAssembly), WellKnownAttribute::Guid, (const void **)&pData, &cbData);
         }
 
         if (hr != S_OK)
@@ -3131,7 +3130,7 @@ BOOL IsTypeDefEquivalent(mdToken tk, Module *pModule)
     }
 
     // Check for the TypeIdentifierAttribute and auto opt-in
-    HRESULT hr = pInternalImport->GetCustomAttributeByName(tk, g_TypeIdentifierAttributeClassName, NULL, NULL);
+    HRESULT hr = pModule->GetCustomAttribute(tk, WellKnownAttribute::TypeIdentifier, NULL, NULL);
     IfFailThrow(hr);
 
     // 1. Type is within assembly marked with ImportedFromTypeLibAttribute or PrimaryInteropAssemblyAttribute
@@ -3172,7 +3171,7 @@ BOOL IsTypeDefEquivalent(mdToken tk, Module *pModule)
         else
         {
             // COMEvent
-            hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
+            hr = pModule->GetCustomAttribute(tk, WellKnownAttribute::ComEventInterface, NULL, NULL);
             IfFailThrow(hr);
 
             if (hr == S_OK)
index 26c2573..dfdeba6 100644 (file)
@@ -119,8 +119,8 @@ static BOOL GetStaticFieldElementTypeForFieldDef(Module * pModule, IMDInternalIm
         return TRUE;
 
     // We need to do an extra check to see if this field is ThreadStatic
-    HRESULT hr = pImport->GetCustomAttributeByName((mdToken)field,
-                                                    g_ThreadStaticAttributeClassName,
+    HRESULT hr = pModule->GetCustomAttribute((mdToken)field,
+                                                    WellKnownAttribute::ThreadStatic,
                                                     NULL, NULL);
     IfFailThrow(hr);
 
index c661451..c05b523 100644 (file)
@@ -97,3 +97,94 @@ inline static int ComputeGenericInstanceHashCode(int definitionHashcode, int ari
     }
     return (hashcode + _rotl(hashcode, 15));
 }
+
+/*
+
+The below hash combining function is based on the xxHash32 logic implemented
+in System.HashCode. In particular it is a port of the 2 element hash
+combining routines, which are in turn based on xxHash32 logic.
+
+The xxHash32 implementation is based on the code published by Yann Collet:
+https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b39696afea1/xxhash.c
+
+  xxHash - Fast Hash algorithm
+  Copyright (C) 2012-2016, Yann Collet
+  
+  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+  
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+  
+  * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+  
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  You can contact the author at :
+  - xxHash homepage: http://www.xxhash.com
+  - xxHash source repository : https://github.com/Cyan4973/xxHash
+
+*/
+
+inline static UINT32 HashMDToken(mdToken token)
+{
+    // Hash function to generate a value useable for reasonable hashes from a single 32bit value
+    // This function was taken from http://burtleburtle.net/bob/hash/integer.html
+    UINT32 a = token;
+    a -= (a<<6);
+    a ^= (a>>17);
+    a -= (a<<9);
+    a ^= (a<<4);
+    a -= (a<<3);
+    a ^= (a<<10);
+    a ^= (a>>15);
+    return a;
+}
+
+inline static UINT32 XXHash32_MixEmptyState()
+{
+    // Unlike System.HashCode, these hash values are required to be stable, so don't
+    // mixin a random process specific value
+    return 374761393U; // Prime5
+}
+
+inline static UINT32 XXHash32_QueueRound(UINT32 hash, UINT32 queuedValue)
+{
+    return ((UINT32)_rotl((int)(hash + queuedValue * 3266489917U/*Prime3*/), 17)) * 668265263U/*Prime4*/;
+}
+
+inline static UINT32 XXHash32_MixFinal(UINT32 hash)
+{
+    hash ^= hash >> 15;
+    hash *= 2246822519U/*Prime2*/;
+    hash ^= hash >> 13;
+    hash *= 3266489917U/*Prime3*/;
+    hash ^= hash >> 16;
+    return hash;
+}
+
+inline static UINT32 CombineTwoValuesIntoHash(UINT32 value1, UINT32 value2)
+{
+    // This matches the behavior of System.HashCode.Combine(value1, value2) as of the time of authoring
+    DWORD hash = XXHash32_MixEmptyState();
+    hash += 8;
+    hash = XXHash32_QueueRound(hash, value1);
+    hash = XXHash32_QueueRound(hash, value2);
+    hash = XXHash32_MixFinal(hash);
+    return hash;
+}
diff --git a/src/vm/wellknownattributes.h b/src/vm/wellknownattributes.h
new file mode 100644 (file)
index 0000000..297bf9a
--- /dev/null
@@ -0,0 +1,107 @@
+// 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.
+
+#ifndef __WELLKNOWNATTRIBUTES_H_
+#define __WELLKNOWNATTRIBUTES_H_
+
+enum class WellKnownAttribute : DWORD
+{
+    ParamArray,
+    DefaultMember,
+    DisablePrivateReflectionType,
+    FixedAddressValueType,
+    UnsafeValueType,
+    BestFitMapping,
+    ClassInterface,
+    CoClass,
+    ComCompatibleVersion,
+    ComDefaultInterface,
+    ComEventInterface,
+    ComSourceInterfaces,
+    ComVisible,
+    DefaultDllImportSearchPaths,
+    Guid,
+    LCIDConversion,
+    IDispatchImpl,
+    ImportedFromTypeLib,
+    Intrinsic,
+    IsByRefLike,
+    PrimaryInteropAssembly,
+    ManagedToNativeComInteropStub,
+    NativeCallable,
+    TypeIdentifier,
+    UnmanagedFunctionPointer,
+    ThreadStatic,
+    WinRTMarshalingBehaviorAttribute,
+
+    CountOfWellKnownAttributes
+};
+
+inline const char *GetWellKnownAttributeName(WellKnownAttribute attribute)
+{
+    switch (attribute)
+    {
+        case WellKnownAttribute::ParamArray:
+            return "System.ParamArrayAttribute";
+        case WellKnownAttribute::DefaultMember:
+            return "System.Reflection.DefaultMemberAttribute";
+        case WellKnownAttribute::DisablePrivateReflectionType:
+            return "System.Runtime.CompilerServices.DisablePrivateReflectionAttribute";
+        case WellKnownAttribute::FixedAddressValueType:
+            return "System.Runtime.CompilerServices.FixedAddressValueTypeAttribute";
+        case WellKnownAttribute::UnsafeValueType:
+            return "System.Runtime.CompilerServices.UnsafeValueTypeAttribute";
+        case WellKnownAttribute::BestFitMapping:
+            return "System.Runtime.InteropServices.BestFitMappingAttribute";
+        case WellKnownAttribute::ClassInterface:
+            return "System.Runtime.InteropServices.ClassInterfaceAttribute";
+        case WellKnownAttribute::CoClass:
+            return "System.Runtime.InteropServices.CoClassAttribute";
+        case WellKnownAttribute::ComCompatibleVersion:
+            return "System.Runtime.InteropServices.ComCompatibleVersionAttribute";
+        case WellKnownAttribute::ComDefaultInterface:
+            return "System.Runtime.InteropServices.ComDefaultInterfaceAttribute";
+        case WellKnownAttribute::ComEventInterface:
+            return "System.Runtime.InteropServices.ComEventInterfaceAttribute";
+        case WellKnownAttribute::ComSourceInterfaces:
+            return "System.Runtime.InteropServices.ComSourceInterfacesAttribute";
+        case WellKnownAttribute::ComVisible:
+            return "System.Runtime.InteropServices.ComVisibleAttribute";
+        case WellKnownAttribute::DefaultDllImportSearchPaths:
+            return "System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute";
+        case WellKnownAttribute::Guid:
+            return "System.Runtime.InteropServices.GuidAttribute";
+        case WellKnownAttribute::LCIDConversion:
+            return "System.Runtime.InteropServices.LCIDConversionAttribute";
+        case WellKnownAttribute::IDispatchImpl:
+            return "System.Runtime.InteropServices.IDispatchImplAttribute";
+        case WellKnownAttribute::ImportedFromTypeLib:
+            return "System.Runtime.InteropServices.ImportedFromTypeLibAttribute";
+        case WellKnownAttribute::Intrinsic:
+            return "System.Runtime.CompilerServices.IntrinsicAttribute";
+        case WellKnownAttribute::IsByRefLike:
+            return "System.Runtime.CompilerServices.IsByRefLikeAttribute";
+        case WellKnownAttribute::PrimaryInteropAssembly:
+            return "System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute";
+        case WellKnownAttribute::ManagedToNativeComInteropStub:
+            return "System.Runtime.InteropServices.ManagedToNativeComInteropStubAttribute";
+        case WellKnownAttribute::NativeCallable:
+            return "System.Runtime.InteropServices.NativeCallableAttribute";
+        case WellKnownAttribute::TypeIdentifier:
+            return "System.Runtime.InteropServices.TypeIdentifierAttribute";
+        case WellKnownAttribute::UnmanagedFunctionPointer:
+            return "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute";
+        case WellKnownAttribute::ThreadStatic:
+            return "System.ThreadStaticAttribute";
+        case WellKnownAttribute::WinRTMarshalingBehaviorAttribute:
+            return "Windows.Foundation.Metadata.MarshalingBehaviorAttribute";
+        case WellKnownAttribute::CountOfWellKnownAttributes:
+        default:
+            break; // Silence compiler warnings
+    }
+    _ASSERTE(false); // Should not be possible
+    return nullptr;
+}
+
+#endif // __WELLKNOWNATTRIBUTES_H_
index e64c0b6..c498719 100644 (file)
@@ -562,6 +562,7 @@ void ZapImage::AllocateVirtualSections()
         if (IsReadyToRunCompilation())
         {
             m_pAvailableTypesSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlySection);
+            m_pAttributePresenceSection = NewVirtualSection(pTextSection, IBCUnProfiledSection | WarmRange | ReadonlyDataSection, 16/* Must be 16 byte aligned */);
         }
 #endif    
 
@@ -1833,6 +1834,7 @@ void ZapImage::Compile()
         OutputEntrypointsTableForReadyToRun();
         OutputDebugInfoForReadyToRun();
         OutputTypesTableForReadyToRun(m_pMDImport);
+        OutputAttributePresenceFilter(m_pMDImport);
         OutputInliningTableForReadyToRun();
         OutputProfileDataForReadyToRun();
         if (IsLargeVersionBubbleEnabled())
index 4e9d233..7451789 100644 (file)
@@ -222,6 +222,7 @@ public:
 
 #ifdef FEATURE_READYTORUN_COMPILER
     ZapVirtualSection * m_pAvailableTypesSection;
+    ZapVirtualSection * m_pAttributePresenceSection;
 #endif
 
     // Preloader sections
@@ -597,6 +598,8 @@ private:
     void OutputInliningTableForReadyToRun();
     void OutputProfileDataForReadyToRun();
     void OutputManifestMetadataForReadyToRun();
+    HRESULT ComputeAttributePresenceTable(IMDInternalImport * pMDImport, SArray<UINT16> *table);
+    void OutputAttributePresenceFilter(IMDInternalImport * pMDImport);
 
     void CopyDebugDirEntry();
     void CopyWin32Resources();
index 8d83ff7..cb41a1a 100644 (file)
@@ -20,6 +20,9 @@
 
 #include "nibblestream.h"
 
+#include "../vm/typehashingalgorithms.h"
+#include "../vm/nativeformatreader.h"
+
 using namespace NativeFormat;
 
 void ZapReadyToRunHeader::Save(ZapWriter * pZapWriter)
@@ -467,6 +470,269 @@ void ZapImage::OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport)
     GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_AVAILABLE_TYPES, pBlob);
 }
 
+template<class Tlambda>
+HRESULT EnumerateAllCustomAttributes(IMDInternalImport *pMDImport, Tlambda lambda)
+{
+    HENUMInternalHolder hEnum(pMDImport);
+    hEnum.EnumAllInit(mdtCustomAttribute);
+
+    HRESULT hr = S_OK;
+
+    mdCustomAttribute tkCustomAttribute;
+    while (pMDImport->EnumNext(&hEnum, &tkCustomAttribute))
+    {
+        LPCUTF8 szNamespace;
+        LPCUTF8 szName;
+
+        hr = pMDImport->GetNameOfCustomAttribute(tkCustomAttribute, &szNamespace, &szName);
+        if (FAILED(hr))
+            return hr;
+        
+        if (szNamespace == NULL)
+            continue;
+
+        if (szName == NULL)
+            continue;
+
+        // System.Runtime.CompilerServices.NullableAttribute is NEVER added to the table (There are *many* of these, and they provide no useful value to the runtime)
+        if ((strcmp(szNamespace, "System.Runtime.CompilerServices") == 0) && (strcmp(szName, "NullableAttribute") == 0))
+            continue;
+
+        bool addToTable = false;
+        // Other than Nullable attribute, all attributes under System.Runtime are added to the table
+        if (strncmp(szNamespace, "System.Runtime.", strlen("System.Runtime.")) == 0)
+        {
+            addToTable = true;
+        }
+        else if (strcmp(szNamespace, "Windows.Foundation.Metadata") == 0)
+        {
+            // Windows.Foundation.Metadata attributes are a similar construct to compilerservices attributes. Add them to the table
+            addToTable = true;
+        }
+        else if (strcmp(szNamespace, "System") == 0)
+        {
+            // Some historical well known attributes were placed in the System namespace. Special case them
+            if (strcmp(szName, "ParamArrayAttribute") == 0)
+                addToTable = true;
+            else if (strcmp(szName, "ThreadStaticAttribute") == 0)
+                addToTable = true;
+        }
+        else if (strcmp(szNamespace, "System.Reflection") == 0)
+        {
+            // Historical attribute in the System.Reflection namespace
+            if (strcmp(szName, "DefaultMemberAttribute") == 0)
+                addToTable = true;
+        }
+
+        if (!addToTable)
+            continue;
+
+        mdToken tkParent;
+        hr = pMDImport->GetParentToken(tkCustomAttribute, &tkParent);
+        if (FAILED(hr))
+            return hr;
+        
+        hr = lambda(szNamespace, szName, tkParent);
+        if (FAILED(hr))
+            return hr;
+    }
+
+    return hr;
+}
+
+uint32_t xorshift128(uint32_t state[4])
+{
+    /* Algorithm "xor128" from p. 5 of Marsaglia, "Xorshift RNGs" */
+    uint32_t s, t = state[3];
+    state[3] = state[2];
+    state[2] = state[1];
+    state[1] = s = state[0];
+    t ^= t << 11;
+    t ^= t >> 8;
+    return state[0] = t ^ s ^ (s >> 19);
+}
+
+HRESULT ZapImage::ComputeAttributePresenceTable(IMDInternalImport * pMDImport, SArray<UINT16> *table)
+{
+    int countOfEntries = 0;
+    HRESULT hr = EnumerateAllCustomAttributes(pMDImport, [&countOfEntries](LPCUTF8 szNamespace, LPCUTF8 szName, mdToken tkParent)
+        {
+            countOfEntries++;
+            return S_OK;
+        });
+    if (FAILED(hr))
+        return hr;
+
+    if (countOfEntries == 0)
+    {
+        table->Clear();
+        _ASSERTE(table->IsEmpty());
+        return S_OK;
+    }
+
+    // Buckets have 8 entries
+    UINT minTableBucketCount = (countOfEntries / 8) + 1;
+    UINT bucketCount = 1;
+
+    // Bucket count must be power of two
+    while (bucketCount < minTableBucketCount)
+        bucketCount *= 2;
+
+    // Resize the array.
+    bool tryAgainWithBiggerTable = false;
+    int countOfRetries = 0;
+    do
+    {
+        tryAgainWithBiggerTable = false;
+        UINT actualSizeOfTable = bucketCount * 8; // Buckets have 8 entries in them
+        UINT16* pTable = table->OpenRawBuffer(actualSizeOfTable);
+        memset(pTable, 0, sizeof(UINT16) * actualSizeOfTable);
+        table->CloseRawBuffer();
+
+        uint32_t state[4] = {729055690, 833774698, 218408041, 493449127}; // 4 randomly generated numbers to initialize random number state
+
+        // Attempt to fill  table
+
+        hr = EnumerateAllCustomAttributes(pMDImport, [&](LPCUTF8 szNamespace, LPCUTF8 szName, mdToken tkParent)
+        {
+            StackSString name(SString::Utf8);
+            name.AppendUTF8(szNamespace);
+            name.AppendUTF8(NAMESPACE_SEPARATOR_STR);
+            name.AppendUTF8(szName);
+
+            StackScratchBuffer buff;
+            const char* pDebugNameUTF8 = name.GetUTF8(buff);
+            size_t len = strlen(pDebugNameUTF8);
+
+            // This hashing algorithm MUST match exactly the logic in NativeCuckooFilter
+            DWORD hashOfAttribute = ComputeNameHashCode(pDebugNameUTF8);
+            UINT32 hash = CombineTwoValuesIntoHash(hashOfAttribute, tkParent);
+            UINT16 fingerprint = (UINT16)(hash >> 16);
+            if (fingerprint == 0)
+                fingerprint = 1;
+
+            UINT bucketAIndex = hash % bucketCount;
+            UINT bucketBIndex = (bucketAIndex ^ (NativeFormat::NativeCuckooFilter::ComputeFingerprintHash(fingerprint)  % bucketCount));
+
+            _ASSERTE(bucketAIndex == (bucketBIndex ^ (NativeFormat::NativeCuckooFilter::ComputeFingerprintHash(fingerprint) % bucketCount)));
+
+            if (xorshift128(state) & 1) // Randomly choose which bucket to attempt to fill first
+            {
+                UINT temp = bucketAIndex;
+                bucketAIndex = bucketBIndex;
+                bucketBIndex = temp;
+            }
+
+            auto hasEntryInBucket = [&table](UINT bucketIndex, UINT16 fprint)
+            {
+                for (int i = 0; i < 8; i++)
+                {
+                    if ((*table)[(bucketIndex * 8) + i] == fprint)
+                        return true;
+                }
+                return false;
+            };
+
+            auto isEmptyEntryInBucket = [&table](UINT bucketIndex)
+            {
+                for (int i = 0; i < 8; i++)
+                {
+                    if ((*table)[(bucketIndex * 8) + i] == 0)
+                        return true;
+                }
+                return false;
+            };
+
+            auto fillEmptyEntryInBucket = [&table](UINT bucketIndex, UINT16 fprint)
+            {
+                for (int i = 0; i < 8; i++)
+                {
+                    if ((*table)[(bucketIndex * 8) + i] == 0)
+                    {
+                        (*table)[(bucketIndex * 8) + i] = fprint;
+                        return;
+                    }
+                }
+                _ASSERTE(!"Not possible to reach here");
+                return;
+            };
+
+            // Scan for pre-existing fingerprint entry in buckets
+            if (hasEntryInBucket(bucketAIndex, fingerprint) || hasEntryInBucket(bucketBIndex, fingerprint))
+                return S_OK;
+
+            // Determine if there is space in a bucket to add a new entry
+            if (isEmptyEntryInBucket(bucketAIndex))
+            {
+                fillEmptyEntryInBucket(bucketAIndex, fingerprint);
+                return S_OK;
+            }
+            if (isEmptyEntryInBucket(bucketBIndex))
+            {
+                fillEmptyEntryInBucket(bucketBIndex, fingerprint);
+                return S_OK;
+            }
+
+            int MaxNumKicks = 256;
+            // Note, that bucketAIndex itself was chosen randomly above.
+            for (int n = 0; n < MaxNumKicks; n++)
+            {
+                // Randomly swap an entry in bucket bucketAIndex with fingerprint
+                UINT entryIndexInBucket = xorshift128(state) & 0x7;
+                UINT16 temp = fingerprint;
+                fingerprint = (*table)[(bucketAIndex * 8) + entryIndexInBucket];
+                (*table)[(bucketAIndex * 8) + entryIndexInBucket] = temp;
+
+                // Find other bucket
+                bucketAIndex = bucketAIndex ^ (NativeFormat::NativeCuckooFilter::ComputeFingerprintHash(fingerprint) % bucketCount);
+                if (isEmptyEntryInBucket(bucketAIndex))
+                {
+                    fillEmptyEntryInBucket(bucketAIndex, fingerprint);
+                    return S_OK;
+                }
+            }
+
+            tryAgainWithBiggerTable = true;
+            return E_FAIL;
+        });
+
+        if (tryAgainWithBiggerTable)
+        {
+            // bucket entry kicking path requires bucket counts to be power of two in size due to use of xor to retrieve second hash
+            bucketCount *= 2;
+        }
+    } while(tryAgainWithBiggerTable && ((countOfRetries++) < 2));
+
+    if (tryAgainWithBiggerTable)
+    {
+        return E_FAIL;
+    }
+
+    return S_OK;
+}
+
+void ZapImage::OutputAttributePresenceFilter(IMDInternalImport * pMDImport)
+{
+    // Core library attributes are checked FAR more often than other dlls
+    // attributes, so produce a highly efficient table for determining if they are
+    // present. Other assemblies *MAY* benefit from this feature, but it doesn't show
+    // as useful at this time.
+
+    if (m_hModule != m_zapper->m_pEECompileInfo->GetLoaderModuleForMscorlib())
+        return;
+
+    SArray<UINT16> table;
+    if (SUCCEEDED(ComputeAttributePresenceTable(pMDImport, &table)))
+    {
+        UINT16* pRawTable = table.OpenRawBuffer(table.GetCount());
+        ZapNode * pBlob = ZapBlob::NewBlob(this, pRawTable, table.GetCount() * sizeof(UINT16));
+        table.CloseRawBuffer();
+
+        _ASSERTE(m_pAttributePresenceSection);
+        m_pAttributePresenceSection->Place(pBlob);
+        GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_ATTRIBUTEPRESENCE, pBlob);
+    }
+}
 
 //
 // Verify that data structures and flags shared between NGen and ReadyToRun are in sync