|
- Vitek found that the binder was still getting confused about duplicate generic types in the Twitter app. This is due to the fact that TranslateToken is not reliable very early in the binding process, before all needed modules have been loaded. In Twitter, the problematic case happened to occur for the very *first* type being loaded. The simplest way to fix this was not to call TranslateToken, but introduce another flavor of GetTypeToken which is built to tolerate not-yet loaded modules.
- The DynamicGenerics test showed that thread statics did not work correctly with generic unification. The issue was that the accessing code loaded the thread static index directly from the tls index cell in the current module, rather than from the generic unification indirection cell. However, the generic unification indirection cell originally contains a *pointer* to the tls index cell, not the tls index itself. Rather than add another indirection to access code, it seemed simpler and safer to just have the generic unification code replace the pointer to the tls index by the tls index itself. That necessitated some changes in the code that reconciles the indirection cells of a "losing" generic instantiation with those of the "winning" one, because for both tls index and tls offset, 0 is a perfectly legal value.
- When I investigated the "No body for ... messages" the binder spits out under /separateCompilation, I realized that many generic method bodies are not generated into the image. I assume they are the ones that the compiler could prove would not be called. However, to make the generic unification work correctly in the face of missing method bodies, I needed to make the copying of indirection cells more subtle because a "winner" may miss a method body that a "loser" has, so if a second "loser" comes along, we need to make sure both losers get the same method body. The simplest way to do this was to just copy the loser's method body pointer over the null one of the winner.
[tfs-changeset: 1627463]
|
|
This is the implementation of generic unification for separate compilation.
When we do not use global analysis, we may end up with multiple instances of generic types and methods in different modules. This causes problems for access to static fields, type casting and reflection, notably GetMethodInfo on delegates.
The implementation proposed has two main components:
- the binder generates "GenericUnificiationDesc" data structures for each generic type and method. It also indirects accesses to generic types and methods through indirection cells. The mechanism is enabled via a new "/separateCompilation" command line switch.
- the runtime enters the generic types and methods into a big hash table. If it finds a duplicate, it declares the existing entry the "winner" and overwrites the indirection cells of the "loser" with those of the winner.
Initial measurements on UnitTests are as follows:
- about 8,000 types and methods are entered into the hash table on startup
- about 2,000 duplicates are found (most are between UnitTests and UnitTests.McgInterop)
- the total number of indirection cells is about 23,000
- the elapsed time to hash the 8000 types and methods is about 3 milliseconds (11 million clock cycles as measured by the rdtsc instruction, see instrumentation in GenericUnification.cpp).
I also added interning of generic composition structures which seems to roughly halve the space taken by them.
[tfs-changeset: 1625336]
|