diff options
author | Peter Sollich <petersol@microsoft.com> | 2016-09-15 17:22:00 +0300 |
---|---|---|
committer | Peter Sollich <petersol@microsoft.com> | 2016-09-15 17:22:00 +0300 |
commit | 4693e6cd2acdcd3a6307872e290890d6583b509d (patch) | |
tree | 8560160316e3f9bb7a89825c8ea7a86e317af0fa /src/Native/Runtime/GenericUnification.cpp | |
parent | 775c6cfa8ea563c9d12cb4c143e4c70bc4bed935 (diff) |
More fixes for generic unification:
- 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]
Diffstat (limited to 'src/Native/Runtime/GenericUnification.cpp')
-rw-r--r-- | src/Native/Runtime/GenericUnification.cpp | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/src/Native/Runtime/GenericUnification.cpp b/src/Native/Runtime/GenericUnification.cpp index 6486afa5d..03313cc84 100644 --- a/src/Native/Runtime/GenericUnification.cpp +++ b/src/Native/Runtime/GenericUnification.cpp @@ -95,6 +95,11 @@ bool GenericUnificationHashtable::EnterDesc(GenericUnificationDesc *pDesc, UIntT { UInt32 indirCellIndex = pDesc->GetIndirCellIndex(GUF_THREAD_STATICS); UInt32 tlsIndex = *(UInt32 *)pIndirCells[indirCellIndex]; + + // replace the pointer to the tls index by the tls index itself + // this is done so code referencing the tls index does not have to do an additional indirection + pIndirCells[indirCellIndex] = tlsIndex; + UInt32 tlsOffset = (UInt32)pIndirCells[indirCellIndex + 1]; StaticGcDesc *pGcStaticsDesc = (StaticGcDesc *)pIndirCells[indirCellIndex + 2]; if (!GetRuntimeInstance()->AddDynamicThreadStaticGcData(tlsIndex, tlsOffset, pGcStaticsDesc)) @@ -116,12 +121,32 @@ void GenericUnificationHashtable::CopyIndirCells(Entry *pWinnerEntry, GenericUni UInt32 winnerIndirCellCount = pWinnerDesc->GetIndirCellCount(); UInt32 loserIndirCellCount = pLoserDesc->GetIndirCellCount(); + if (pWinnerDesc->m_flags & GUF_THREAD_STATICS) + { + // the cells for the thread static index and thread static offset should be + // copied always because 0 can be a valid value + UInt32 threadStaticIndirCellIndex = pWinnerDesc->GetIndirCellIndex(GUF_THREAD_STATICS); + pLoserIndirCells[threadStaticIndirCellIndex] = pWinnerIndirCells[threadStaticIndirCellIndex]; + pLoserIndirCells[threadStaticIndirCellIndex + 1] = pWinnerIndirCells[threadStaticIndirCellIndex + 1]; + } + ASSERT(winnerIndirCellCount == loserIndirCellCount); for (UInt32 i = 0; i < winnerIndirCellCount; i++) { - if (i < loserIndirCellCount && pWinnerIndirCells[i] != 0) + if (i < loserIndirCellCount) { - pLoserIndirCells[i] = pWinnerIndirCells[i]; + // pointers to method bodies can be null if the body was not present + if (pWinnerIndirCells[i] != 0) + { + // don't overwrite the loser's cells with null + pLoserIndirCells[i] = pWinnerIndirCells[i]; + } + else if (pLoserIndirCells[i] != 0) + { + // overwrite winner's null with a loser's non-null + // so that later losers get the unified value + pWinnerIndirCells[i] = pLoserIndirCells[i]; + } } } } |