Skip to content

Commit adecd85

Browse files
Cuckoo metadata (dotnet#24498)
* 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
1 parent f4ae8f0 commit adecd85

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1031
-148
lines changed

src/inc/readytorun.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
1717

1818
#define READYTORUN_MAJOR_VERSION 0x0003
19-
#define READYTORUN_MINOR_VERSION 0x0000
19+
#define READYTORUN_MINOR_VERSION 0x0001
2020
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x003
2121
// R2R Version 2.1 adds the READYTORUN_SECTION_INLINING_INFO section
2222
// R2R Version 2.2 adds the READYTORUN_SECTION_PROFILEDATA_INFO section
@@ -66,7 +66,8 @@ enum ReadyToRunSectionType
6666
READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS = 109,
6767
READYTORUN_SECTION_INLINING_INFO = 110, // Added in V2.1
6868
READYTORUN_SECTION_PROFILEDATA_INFO = 111, // Added in V2.2
69-
READYTORUN_SECTION_MANIFEST_METADATA = 112 // Added in V2.3
69+
READYTORUN_SECTION_MANIFEST_METADATA = 112, // Added in V2.3
70+
READYTORUN_SECTION_ATTRIBUTEPRESENCE = 113, // Added in V3.1
7071

7172
// If you add a new section consider whether it is a breaking or non-breaking change.
7273
// Usually it is non-breaking, but if it is preferable to have older runtimes fail

src/md/enc/mdinternalrw.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,10 @@ HRESULT MDInternalRW::EnumAllInit( // return S_FALSE if record not found
14821482
phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountFiles();
14831483
break;
14841484

1485+
case mdtCustomAttribute:
1486+
phEnum->m_ulCount = m_pStgdb->m_MiniMd.getCountCustomAttributes();
1487+
break;
1488+
14851489
default:
14861490
_ASSERTE(!"Bad token kind!");
14871491
break;

src/md/runtime/mdinternalro.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,10 @@ HRESULT MDInternalRO::EnumAllInit( // return S_FALSE if record not found
609609
phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountFiles();
610610
break;
611611

612+
case mdtCustomAttribute:
613+
phEnum->m_ulCount = m_LiteWeightStgdb.m_MiniMd.getCountCustomAttributes();
614+
break;
615+
612616
default:
613617
_ASSERTE(!"Bad token kind!");
614618
break;

src/pal/inc/rt/cpp/emmintrin.h

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,128 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
// From llvm-3.9/clang-3.9.1 emmintrin.h:
6+
7+
/*===---- emmintrin.h - SSE2 intrinsics ------------------------------------===
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*
27+
*===-----------------------------------------------------------------------===
28+
*/
29+
530
#include "palrt.h"
31+
#ifdef __GNUC__
32+
#ifndef __EMMINTRIN_H
33+
#define __IMMINTRIN_H
34+
35+
typedef long long __m128i __attribute__((__vector_size__(16)));
36+
37+
typedef unsigned long long __v2du __attribute__ ((__vector_size__ (16)));
38+
typedef short __v8hi __attribute__((__vector_size__(16)));
39+
typedef char __v16qi __attribute__((__vector_size__(16)));
40+
41+
42+
/* Define the default attribute for the functions in this file. */
43+
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
44+
45+
/// \brief Performs a bitwise OR of two 128-bit integer vectors.
46+
///
47+
/// \headerfile <x86intrin.h>
48+
///
49+
/// This intrinsic corresponds to the \c VPOR / POR instruction.
50+
///
51+
/// \param __a
52+
/// A 128-bit integer vector containing one of the source operands.
53+
/// \param __b
54+
/// A 128-bit integer vector containing one of the source operands.
55+
/// \returns A 128-bit integer vector containing the bitwise OR of the values
56+
/// in both operands.
57+
static __inline__ __m128i __DEFAULT_FN_ATTRS
58+
_mm_or_si128(__m128i __a, __m128i __b)
59+
{
60+
return (__m128i)((__v2du)__a | (__v2du)__b);
61+
}
62+
63+
/// \brief Compares each of the corresponding 16-bit values of the 128-bit
64+
/// integer vectors for equality. Each comparison yields 0h for false, FFFFh
65+
/// for true.
66+
///
67+
/// \headerfile <x86intrin.h>
68+
///
69+
/// This intrinsic corresponds to the \c VPCMPEQW / PCMPEQW instruction.
70+
///
71+
/// \param __a
72+
/// A 128-bit integer vector.
73+
/// \param __b
74+
/// A 128-bit integer vector.
75+
/// \returns A 128-bit integer vector containing the comparison results.
76+
static __inline__ __m128i __DEFAULT_FN_ATTRS
77+
_mm_cmpeq_epi16(__m128i __a, __m128i __b)
78+
{
79+
return (__m128i)((__v8hi)__a == (__v8hi)__b);
80+
}
81+
82+
/// \brief Moves packed integer values from an unaligned 128-bit memory location
83+
/// to elements in a 128-bit integer vector.
84+
///
85+
/// \headerfile <x86intrin.h>
86+
///
87+
/// This intrinsic corresponds to the \c VMOVDQU / MOVDQU instruction.
88+
///
89+
/// \param __p
90+
/// A pointer to a memory location containing integer values.
91+
/// \returns A 128-bit integer vector containing the moved values.
92+
static __inline__ __m128i __DEFAULT_FN_ATTRS
93+
_mm_loadu_si128(__m128i const *__p)
94+
{
95+
struct __loadu_si128 {
96+
__m128i __v;
97+
} __attribute__((__packed__, __may_alias__));
98+
return ((struct __loadu_si128*)__p)->__v;
99+
}
100+
101+
/// \brief Initializes all values in a 128-bit vector of [8 x i16] with the
102+
/// specified 16-bit value.
103+
///
104+
/// \headerfile <x86intrin.h>
105+
///
106+
/// This intrinsic is a utility function and does not correspond to a specific
107+
/// instruction.
108+
///
109+
/// \param __w
110+
/// A 16-bit value used to initialize the elements of the destination integer
111+
/// vector.
112+
/// \returns An initialized 128-bit vector of [8 x i16] with all elements
113+
/// containing the value provided in the operand.
114+
static __inline__ __m128i __DEFAULT_FN_ATTRS
115+
_mm_set1_epi16(short __w)
116+
{
117+
return (__m128i)(__v8hi){ __w, __w, __w, __w, __w, __w, __w, __w };
118+
}
119+
120+
static __inline__ int __DEFAULT_FN_ATTRS
121+
_mm_movemask_epi8(__m128i __a)
122+
{
123+
return __builtin_ia32_pmovmskb128((__v16qi)__a);
124+
}
125+
126+
#undef __DEFAULT_FN_ATTRS
127+
128+
#endif /* __EMMINTRIN_H */
129+
#endif // __GNUC__

src/pal/inc/rt/cpp/xmmintrin.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,6 @@ _mm_store_ps(float *__p, __m128 __a)
113113
*(__m128*)__p = __a;
114114
}
115115

116+
#undef __DEFAULT_FN_ATTRS
117+
116118
#endif // __GNUC__

src/tools/r2rdump/NativeHashtable.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,61 @@ public AllEntriesEnumerator EnumerateAllEntries()
238238
return new AllEntriesEnumerator(this);
239239
}
240240
}
241+
242+
/// <summary>
243+
/// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/vm/nativeformatreader.h">NativeFormat::NativeHashtable</a>
244+
/// </summary>
245+
struct NativeCuckooFilter
246+
{
247+
private byte[] _image;
248+
private int _filterStartOffset;
249+
private int _filterEndOffset;
250+
251+
public NativeCuckooFilter(byte[] image, int filterStartOffset, int filterEndOffset)
252+
{
253+
_image = image;
254+
_filterStartOffset = filterStartOffset;
255+
_filterEndOffset = filterEndOffset;
256+
257+
if (((_filterStartOffset & 0xF) != 0) || ((_filterEndOffset & 0xF) != 0))
258+
{
259+
// Native cuckoo filters must be aligned at 16byte boundaries within the PE file
260+
throw new System.BadImageFormatException();
261+
}
262+
}
263+
264+
private IEnumerable<ushort[]> GetBuckets()
265+
{
266+
int offset = _filterStartOffset;
267+
while (offset < _filterEndOffset)
268+
{
269+
ushort[] bucket = new ushort[8];
270+
for (int i = 0; i < bucket.Length; i++)
271+
{
272+
bucket[i] = NativeReader.ReadUInt16(_image, ref offset);
273+
}
274+
yield return bucket;
275+
}
276+
}
277+
278+
public override string ToString()
279+
{
280+
StringBuilder sb = new StringBuilder();
281+
282+
sb.AppendLine($"NativeCuckooFilter Size: {(_filterEndOffset - _filterStartOffset) / 16}");
283+
int bucket = 0;
284+
foreach (ushort [] bucketContents in GetBuckets())
285+
{
286+
sb.Append($"Bucket: {bucket} [");
287+
for (int i = 0; i < 8; i++)
288+
{
289+
sb.Append($"{bucketContents[i],4:X} ");
290+
}
291+
sb.AppendLine("]");
292+
bucket++;
293+
}
294+
295+
return sb.ToString();
296+
}
297+
}
241298
}

src/tools/r2rdump/R2RSection.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public enum SectionType
2929
READYTORUN_SECTION_INLINING_INFO = 110,
3030
READYTORUN_SECTION_PROFILEDATA_INFO = 111,
3131
READYTORUN_SECTION_MANIFEST_METADATA = 112, // Added in v2.3
32+
READYTORUN_SECTION_ATTRIBUTEPRESENCE = 113, // Added in V3.1
3233
}
3334

3435
/// <summary>

src/tools/r2rdump/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ A [NativeArray](NativeArray.cs) used for finding the index of the entrypoint Run
8181

8282
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)
8383

84+
### READYTORUN_SECTION_ATTRIBUTEPRESENCE
85+
86+
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.
87+
8488
### READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS
8589

8690
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.

src/tools/r2rdump/TextDumper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,13 @@ internal override void DumpSectionContents(R2RSection section, XmlNode parentNod
374374
_writer.WriteLine($"[ID 0x{manifestAsmIndex + assemblyRefCount + 2:X2}]: {_r2r.ManifestReferenceAssemblies[manifestAsmIndex]}");
375375
}
376376
break;
377+
case R2RSection.SectionType.READYTORUN_SECTION_ATTRIBUTEPRESENCE:
378+
int attributesStartOffset = _r2r.GetOffset(section.RelativeVirtualAddress);
379+
int attributesEndOffset = attributesStartOffset + section.Size;
380+
NativeCuckooFilter attributes = new NativeCuckooFilter(_r2r.Image, attributesStartOffset, attributesEndOffset);
381+
_writer.WriteLine("Attribute presence filter");
382+
_writer.WriteLine(attributes.ToString());
383+
break;
377384
}
378385
}
379386

src/vm/assembly.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ BOOL Assembly::IsDisabledPrivateReflection()
229229

230230
if (m_isDisabledPrivateReflection == UNINITIALIZED)
231231
{
232-
IMDInternalImport *pImport = GetManifestImport();
233-
HRESULT hr = pImport->GetCustomAttributeByName(GetManifestToken(), DISABLED_PRIVATE_REFLECTION_TYPE, NULL, 0);
232+
HRESULT hr = GetManifestModule()->GetCustomAttribute(GetManifestToken(), WellKnownAttribute::DisablePrivateReflectionType, NULL, 0);
234233
IfFailThrow(hr);
235234

236235
if (hr == S_OK)

0 commit comments

Comments
 (0)