Skip to content

Commit 9e932c4

Browse files
committed
Merge remote-tracking branch 'dotnet/main' into fix-81500
2 parents 589fc71 + 98b587c commit 9e932c4

File tree

228 files changed

+5818
-2666
lines changed

Some content is hidden

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

228 files changed

+5818
-2666
lines changed

docs/design/coreclr/botr/readytorun-format.md

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -712,22 +712,82 @@ the first byte of the encoding specify the number of following bytes as follows:
712712

713713
## Sparse Array
714714

715-
**TODO**: Document native format sparse array
715+
The NativeArray provides O(1) indexed access while maintaining compact storage through null element compression (empty blocks share storage) and variable-sized offset encoding (adapts to data size).
716+
717+
The array is made up of three parts, the header, block index, and the blocks.
718+
719+
The header is a variable encoded value where:
720+
- Bits 0-1: Entry index size
721+
- 0 = uint8 offsets
722+
- 1 = uint16 offsets
723+
- 2 = uint32 offsets
724+
- Bits 2-31: Number of elements in the array
725+
726+
The block index immediately follows the header in memory and consists of one offset entry per block (dynamic size encoded in the header), where each entry points to the location of a data block relative to the start of the block index section. The array uses a maximum block size of 16 elements, the block index effectively maps every group of 16 consecutive array indices to their corresponding data blocks.
727+
728+
The following the block index are the actual data blocks. These are made up of two types of nodes. Tree nodes and Data nodes.
729+
730+
Tree nodes are made up of a variable length encoded uint where:
731+
- Bit 0: If set, the node has a lower index child
732+
- Bit 1: If set, the node has a higher index child
733+
- Bits 2-31: Shifted relative offset of higher index child
734+
735+
Data nodes contain the user defined data.
736+
737+
Since each block has at most 16 elements, they have a depth of `4`.
738+
739+
### Lookup Algorithm Steps
740+
741+
**Step 1: Read the Header**
742+
- Decode the variable-length encoded header value from the array
743+
- Extract the entry index size from bits 0-1 (0=uint8, 1=uint16, 2=uint32 offsets)
744+
- Extract the total number of elements from bits 2-31 by right-shifting the header value by 2 bits
745+
- Use this information to determine how to interpret the block index entries and validate array bounds
746+
747+
**Step 2: Calculate Block Offset**
748+
- Determine the block index `blockIndex` containing the target element by dividing the index by the block size (16).
749+
- Calculate the memory location containing the block offset `pBlockOffset = baseOffset + entrySize * blockIndex` where `baseOffset` is the address immediately following the header and `entrySize` is determined by the low bits of the header.
750+
- Read the block offset `blockOffset` from the block index table using the calculated `pBlockOffset` and entry size determined by the header.
751+
- Add the `baseOffset` to convert the relative `blockOffset` to an absolute position.
752+
753+
**Step 3: Initialize Tree Navigation**
754+
- Using the `blockOffset` calculated above, begin traversal at the root of the block's binary tree structure
755+
756+
**Step 4: Navigate Binary Tree**
757+
For each level of the tree (iterating through bit positions 8, 4, 2, 1):
758+
759+
**Step 4a: Read Node Descriptor**
760+
- Decode the current node's control value, which contains navigation flags and child offset information
761+
- Extract flags indicating the presence of left and right child nodes
762+
- Extract the relative offset to the right child node (if present)
763+
764+
**Step 4b: Determine Navigation Direction**
765+
- Test the current bit position against the target index
766+
- If the bit is set in the target index, attempt to navigate to the right child
767+
- If the bit is clear in the target index, attempt to navigate to the left child
768+
769+
**Step 4c: Follow Navigation Path**
770+
- If the desired child exists (indicated by the appropriate flag), update the current position
771+
- For right child navigation, add the encoded offset to the current position
772+
- For left child navigation, move to the position immediately following the current node
773+
- Continue to the next bit level if navigation was successful
774+
775+
**Step 5: Return Element Location**
776+
- Upon successful traversal, return the final offset position which points to the stored data.
777+
- If traversal is not successful (child node does not exist), the element can not be found in the array and return a failure status.
716778

717779
## Hashtable
718780

719781
Conceptually, a native hash table is a header that describe the dimensions of the table, a table that maps hash values of the keys to buckets followed with a list of buckets that store the values. These three things are stored consecutively in the format.
720782

721-
To make look up fast, the number of buckets is always a power of 2. The table is simply a sequence of `(1 + number of buckets)` cells, for the first `(number of buckets)` cells, its stores the offset of the bucket list from the beginning of the whole native hash table. The last cell stores the offset to the end of the buckets.
722-
723-
Each bucket is a sequence of entries. An entry has a hash code and an offset to the object stored. The entries are sorted by hash code.
783+
To make look up fast, the number of buckets is always a power of 2. The table is simply a sequence of `(1 + number of buckets)` cells, for the first `(number of buckets)` cells, its stores the offset of the bucket list from the beginning of the whole native hash table. The last cell stores the offset to the end of the buckets. Entries are mapped to buckets using `x` lowest bits of the hash not in the lowest byte where `2^x = (number of buckets)`. For example, if `x=2` the following bits marked with `X` would be used in a 32-bit hash `b00000000_00000000_000000XX_00000000`.
724784

725785
Physically, the header is a single byte. The most significant six bits is used to store the number of buckets in its base-2 logarithm. The remaining two bits are used for storing the entry size, as explained below:
726786

727787
Because the offsets to the bucket lists are often small numbers, the table cells are variable sized.
728788
It could be either 1 byte, 2 bytes or 4 bytes. The three cases are described with two bits. `00` means it is one byte, `01` means it is two bytes and `10` means it is four bytes.
729789

730-
The remaining data are the entries. The entries has only the least significant byte of the hash code, followed by the offset to the actual object stored in the hash table.
790+
The remaining data are the entries. The entries has only the least significant byte of the hash code, followed by the offset to the actual object stored in the hash table. The entries are sorted by hash code.
731791

732792
To perform a lookup, one starts with reading the header, computing the hash code, using the number of buckets to determine the number of bits to mask away from the hash code, look it up in the table using the right pointer size, find the bucket list, find the next bucket list (or the end of the table) so that we know where to stop, search the entries in that list and then we will find the object if we have a hit, or we have a miss.
733793

@@ -740,23 +800,23 @@ To see this in action, we can take a look at the following example, with these o
740800
| P | 0x1231 |
741801
| Q | 0x1232 |
742802
| R | 0x1234 |
743-
| S | 0x1238 |
803+
| S | 0x1338 |
744804

745-
Suppose we decided to have only two buckets, then only the least significant digit will be used to index the table, the whole hash table will look like this:
805+
Suppose we decided to have only two buckets, then only the 9th bit will be used to index the table, the whole hash table will look like this:
746806

747807
| Part | Offset | Content | Meaning |
748808
|:--------|:-------|:--------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
749809
| Header | 0 | 0x04 | This is the header, the least significant bit is `00`, therefore the table cell is just one byte. The most significant six bit represents 1, which means the number of buckets is 2^1 = 2. |
750-
| Table | 1 | 0x08 | This is the representation of the unsigned integer 4, which correspond to the offset of the bucket correspond to hash code `0`. |
751-
| Table | 2 | 0x14 | This is the representation of the unsigned integer 10, which correspond to the offset of the bucket correspond to hash code `1`. |
752-
| Table | 3 | 0x18 | This is the representation of the unsigned integer 12, which correspond to the offset of the end of the whole hash table. |
753-
| Bucket1 | 4 | 0x32 | This is the least significant byte of the hash code of P |
810+
| Table | 1 | 0x04 | This is the representation of the unsigned integer 4, which correspond to the offset of the bucket correspond to hash code `0`. |
811+
| Table | 2 | 0x0A | This is the representation of the unsigned integer 10, which correspond to the offset of the bucket correspond to hash code `1`. |
812+
| Table | 3 | 0x0C | This is the representation of the unsigned integer 12, which correspond to the offset of the end of the whole hash table. |
813+
| Bucket1 | 4 | 0x31 | This is the least significant byte of the hash code of P |
754814
| Bucket1 | 5 | P | This should be the offset to the object P |
755-
| Bucket1 | 6 | 0x34 | This is the least significant byte of the hash code of Q |
815+
| Bucket1 | 6 | 0x32 | This is the least significant byte of the hash code of Q |
756816
| Bucket1 | 7 | Q | This should be the offset to the object Q |
757-
| Bucket1 | 8 | 0x38 | This is the least significant byte of the hash code of R |
817+
| Bucket1 | 8 | 0x34 | This is the least significant byte of the hash code of R |
758818
| Bucket1 | 9 | R | This should be the offset to the object R |
759-
| Bucket2 | 10 | 0x31 | This is the least significant byte of the hash code of S |
819+
| Bucket2 | 10 | 0x38 | This is the least significant byte of the hash code of S |
760820
| Bucket2 | 11 | S | This should be the offset to the object S |
761821

762822

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,10 @@ CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass)
968968
CDAC_GLOBAL_POINTER(SyncTableEntries, &::g_pSyncTable)
969969
CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress)
970970
CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize)
971+
CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo)
972+
#ifdef TARGET_WINDOWS
973+
CDAC_GLOBAL_POINTER(TlsIndexBase, &::_tls_index)
974+
#endif // TARGET_WINDOWS
971975
#ifdef STRESS_LOG
972976
CDAC_GLOBAL(StressLogEnabled, uint8, 1)
973977
CDAC_GLOBAL_POINTER(StressLog, &g_pStressLog)

src/coreclr/dlls/mscorrc/mscorrc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ BEGIN
308308
IDS_CLASSLOAD_INLINE_ARRAY_FIELD_COUNT "InlineArrayAttribute requires that the target type has a single instance field. Type: '%1'. Assembly: '%2'."
309309
IDS_CLASSLOAD_INLINE_ARRAY_LENGTH "InlineArrayAttribute requires that the length argument is greater than 0. Type: '%1'. Assembly: '%2'."
310310
IDS_CLASSLOAD_INLINE_ARRAY_EXPLICIT "InlineArrayAttribute cannot be applied to a type with explicit layout. Type: '%1'. Assembly: '%2'."
311+
IDS_CLASSLOAD_INLINE_ARRAY_EXPLICIT_SIZE "InlineArrayAttribute cannot be applied to a type with explicit size. Type: '%1'. Assembly: '%2'."
311312

312313
IDS_CLASSLOAD_BYREF_OF_BYREF "Could not create a ByRef of a ByRef. Type: '%1'. Assembly: '%2'."
313314
IDS_CLASSLOAD_POINTER_OF_BYREF "Could not create a pointer to a ByRef. Type: '%1'. Assembly: '%2'."

src/coreclr/dlls/mscorrc/resource.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
#define IDS_CLASSLOAD_BYREF_OF_BYREF 0x17af
161161
#define IDS_CLASSLOAD_POINTER_OF_BYREF 0x17b0
162162

163+
#define IDS_CLASSLOAD_INLINE_ARRAY_EXPLICIT_SIZE 0x17b1
164+
163165
#define IDS_INVALID_REDIM 0x17c3
164166
#define IDS_INVALID_PINVOKE_CALLCONV 0x17c4
165167
#define IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET 0x17c7

src/coreclr/inc/corinfo.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,12 +3139,6 @@ class ICorDynamicInfo : public ICorStaticInfo
31393139
CORINFO_CONST_LOOKUP * pResult
31403140
) = 0;
31413141

3142-
// get the synchronization handle that is passed to monXstatic function
3143-
virtual void* getMethodSync(
3144-
CORINFO_METHOD_HANDLE ftn,
3145-
void** ppIndirection = NULL
3146-
) = 0;
3147-
31483142
// get slow lazy string literal helper to use (CORINFO_HELP_STRCNS*).
31493143
// Returns CORINFO_HELP_UNDEF if lazy string literal helper cannot be used.
31503144
virtual CorInfoHelpFunc getLazyStringLiteralHelper(

src/coreclr/inc/dacvars.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ DEFINE_DACVAR(PTR_SystemDomain, SystemDomain__m_pSystemDomain, SystemDomain::m_p
115115
DEFINE_DACVAR(DWORD, dac__g_debuggerWordTLSIndex, g_debuggerWordTLSIndex)
116116
#endif
117117
DEFINE_DACVAR(DWORD, dac__g_TlsIndex, g_TlsIndex)
118+
DEFINE_DACVAR(DWORD, dac__g_offsetOfCurrentThreadInfo, g_offsetOfCurrentThreadInfo)
118119

119120
#ifdef FEATURE_EH_FUNCLETS
120121
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pEHClass, ::g_pEHClass)

src/coreclr/inc/icorjitinfoimpl_generated.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,10 +550,6 @@ void getFunctionFixedEntryPoint(
550550
bool isUnsafeFunctionPointer,
551551
CORINFO_CONST_LOOKUP* pResult) override;
552552

553-
void* getMethodSync(
554-
CORINFO_METHOD_HANDLE ftn,
555-
void** ppIndirection) override;
556-
557553
CorInfoHelpFunc getLazyStringLiteralHelper(
558554
CORINFO_MODULE_HANDLE handle) override;
559555

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737

3838
#include <minipal/guid.h>
3939

40-
constexpr GUID JITEEVersionIdentifier = { /* 952f0344-7651-46af-8ef3-a34539af5c4a */
41-
0x952f0344,
42-
0x7651,
43-
0x46af,
44-
{0x8e, 0xf3, 0xa3, 0x45, 0x39, 0xaf, 0x5c, 0x4a}
40+
constexpr GUID JITEEVersionIdentifier = { /* d24a67e0-9e57-4c9e-ad31-5785df2526f2 */
41+
0xd24a67e0,
42+
0x9e57,
43+
0x4c9e,
44+
{0xad, 0x31, 0x57, 0x85, 0xdf, 0x25, 0x26, 0xf2}
4545
};
4646

4747
#endif // JIT_EE_VERSIONING_GUID_H

src/coreclr/jit/ICorJitInfo_names_generated.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ DEF_CLR_API(getAddrOfCaptureThreadGlobal)
136136
DEF_CLR_API(getHelperFtn)
137137
DEF_CLR_API(getFunctionEntryPoint)
138138
DEF_CLR_API(getFunctionFixedEntryPoint)
139-
DEF_CLR_API(getMethodSync)
140139
DEF_CLR_API(getLazyStringLiteralHelper)
141140
DEF_CLR_API(embedModuleHandle)
142141
DEF_CLR_API(embedClassHandle)

src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,16 +1299,6 @@ void WrapICorJitInfo::getFunctionFixedEntryPoint(
12991299
API_LEAVE(getFunctionFixedEntryPoint);
13001300
}
13011301

1302-
void* WrapICorJitInfo::getMethodSync(
1303-
CORINFO_METHOD_HANDLE ftn,
1304-
void** ppIndirection)
1305-
{
1306-
API_ENTER(getMethodSync);
1307-
void* temp = wrapHnd->getMethodSync(ftn, ppIndirection);
1308-
API_LEAVE(getMethodSync);
1309-
return temp;
1310-
}
1311-
13121302
CorInfoHelpFunc WrapICorJitInfo::getLazyStringLiteralHelper(
13131303
CORINFO_MODULE_HANDLE handle)
13141304
{

0 commit comments

Comments
 (0)