2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
#include " gcinfoencoder.h"
4
4
#include " interpreter.h"
5
+ #include " stackmap.h"
5
6
6
7
#include < inttypes.h>
7
8
@@ -868,7 +869,7 @@ void InterpCompiler::BuildGCInfo(InterpMethod *pInterpMethod)
868
869
869
870
gcInfoEncoder->SetCodeLength (ConvertOffset (m_methodCodeSize));
870
871
871
- uint32_t stackSlotCount = m_totalVarsStackSize / INTERP_STACK_SLOT_SIZE ,
872
+ uint32_t stackSlotCount = m_totalVarsStackSize / sizeof ( void *) ,
872
873
slotTableSize = stackSlotCount * sizeof (GcSlotId);
873
874
// [pObjects, pByrefs]
874
875
GcSlotId *slotTables[2 ] = {
@@ -879,86 +880,111 @@ void InterpCompiler::BuildGCInfo(InterpMethod *pInterpMethod)
879
880
for (int i = 0 ; i < 2 ; i++)
880
881
memset (slotTables[i], 0xFF , slotTableSize);
881
882
882
- INTERP_DUMP (" Allocating gcinfo slots for %u vars\n " , m_varsSize);
883
-
884
- // Request slot IDs for all our vars, not just IL vars
885
- for (int i = 0 ; i < m_varsSize; i++)
883
+ auto allocateGcSlot = [&] (uint32_t offsetBytes, GcSlotFlags flags)
886
884
{
887
- GcSlotId *slotTable;
888
- InterpVar *pVar = &m_pVars[i];
889
- GcSlotFlags flags;
890
- switch (pVar->interpType ) {
891
- case InterpTypeO:
892
- slotTable = slotTables[0 ];
893
- flags = (GcSlotFlags)0 ;
894
- break ;
895
- case InterpTypeByRef:
896
- slotTable = slotTables[1 ];
897
- flags = (GcSlotFlags)GC_SLOT_INTERIOR;
898
- break ;
899
- default :
900
- continue ;
901
- }
885
+ // Select the appropriate slot table based on the flags
886
+ GcSlotId *slotTable = slotTables[(flags & GC_SLOT_INTERIOR) == GC_SLOT_INTERIOR];
887
+ uint32_t slotIndex = offsetBytes / sizeof (void *);
888
+ bool allocateNewSlot = slotTable[slotIndex] == ((GcSlotId)-1 );
902
889
903
- if (pVar->global )
904
- flags = (GcSlotFlags)(flags | GC_SLOT_UNTRACKED);
905
-
906
- uint32_t slotIndex = pVar->offset / INTERP_STACK_SLOT_SIZE;
907
- uint8_t allocateNewSlot = slotTable[slotIndex] == ((GcSlotId)-1 );
908
890
if (allocateNewSlot)
909
891
{
910
892
// Important to pass GC_FRAMEREG_REL, the default is broken due to GET_CALLER_SP being unimplemented
911
- slotTable[slotIndex] = gcInfoEncoder->GetStackSlotId (pVar-> offset , flags, GC_FRAMEREG_REL);
893
+ slotTable[slotIndex] = gcInfoEncoder->GetStackSlotId (offsetBytes , flags, GC_FRAMEREG_REL);
912
894
}
913
895
else
914
896
{
915
- assert (!pVar-> global );
897
+ assert ((flags & GC_SLOT_UNTRACKED) == 0 );
916
898
}
917
899
918
900
INTERP_DUMP (
919
- " %s gcinfo slot %u for %s%svar #%d at offset %d \n " ,
901
+ " %s %s%sgcslot %u at %u \n " ,
920
902
allocateNewSlot ? " Allocated" : " Reused" ,
903
+ (flags & GC_SLOT_UNTRACKED) ? " global " : " " ,
904
+ (flags & GC_SLOT_INTERIOR) ? " interior " : " " ,
921
905
slotTable[slotIndex],
922
- pVar->global ? " global " : " " ,
923
- pVar->interpType == InterpTypeByRef ? " byref " : " " ,
924
- i, pVar->offset
906
+ offsetBytes
925
907
);
926
- }
927
908
928
- gcInfoEncoder->FinalizeSlotIds ();
909
+ return slotTable[slotIndex];
910
+ };
929
911
930
- // Now that slot IDs are finalized we want to record live ranges for every var that isn't global
931
- for (int i = 0 ; i < m_varsSize; i++)
912
+ auto recordLiveRange = [&] (uint32_t offsetBytes, GcSlotFlags flags, int varIndex)
932
913
{
933
- InterpVar *pVar = &m_pVars[i];
934
- // Even if we have a gc slot for this offset, this var might not be an object reference
935
- if ((pVar->interpType != InterpTypeO) && (pVar->interpType != InterpTypeByRef))
936
- continue ;
937
- // We don't need to report liveness ranges for untracked vars, the gc info decoder will report them
938
- // unconditionally.
914
+ // Select the appropriate slot table based on the flags
915
+ GcSlotId *slotTable = slotTables[(flags & GC_SLOT_INTERIOR) == GC_SLOT_INTERIOR];
916
+ uint32_t slotIndex = offsetBytes / sizeof (void *);
917
+
918
+ InterpVar *pVar = &m_pVars[varIndex];
939
919
if (pVar->global )
940
- continue ;
920
+ return ;
941
921
942
- GcSlotId *slotTable = pVar->interpType == InterpTypeByRef
943
- ? slotTables[1 ] : slotTables[0 ];
944
- uint32_t slotIndex = pVar->offset / INTERP_STACK_SLOT_SIZE;
945
922
GcSlotId slot = slotTable[slotIndex];
946
923
assert (slot != ((GcSlotId)-1 ));
947
924
assert (pVar->liveStart );
948
925
assert (pVar->liveEnd );
949
- uint32_t startOffset = ConvertOffset (GetLiveStartOffset (i )),
950
- endOffset = ConvertOffset (GetLiveEndOffset (i ));
926
+ uint32_t startOffset = ConvertOffset (GetLiveStartOffset (varIndex )),
927
+ endOffset = ConvertOffset (GetLiveEndOffset (varIndex ));
951
928
INTERP_DUMP (
952
- " Recording gcinfo slot %u live range for var #%d at offset %u: [IR_%04x - IR_%04x] [%u - %u]\n " ,
953
- slotTable[slotIndex], i , pVar->offset ,
954
- GetLiveStartOffset (i ), GetLiveEndOffset (i ),
929
+ " Recording slot %u ( var #%d offset %u) live range [IR_%04x - IR_%04x] [%u - %u]\n " ,
930
+ slotTable[slotIndex], varIndex , pVar->offset ,
931
+ GetLiveStartOffset (varIndex ), GetLiveEndOffset (varIndex ),
955
932
startOffset, endOffset
956
933
);
957
934
gcInfoEncoder->SetSlotState (startOffset, slot, GC_SLOT_LIVE);
958
935
gcInfoEncoder->SetSlotState (endOffset, slot, GC_SLOT_DEAD);
959
- }
936
+ };
937
+
938
+ INTERP_DUMP (" Allocating gcinfo slots for %u vars\n " , m_varsSize);
960
939
961
- gcInfoEncoder->Build ();
940
+ for (int pass = 0 ; pass < 2 ; pass++)
941
+ {
942
+ for (int i = 0 ; i < m_varsSize; i++)
943
+ {
944
+ InterpVar *pVar = &m_pVars[i];
945
+ GcSlotFlags flags = pVar->global
946
+ ? (GcSlotFlags)GC_SLOT_UNTRACKED
947
+ : (GcSlotFlags)0 ;
948
+
949
+ switch (pVar->interpType ) {
950
+ case InterpTypeO:
951
+ break ;
952
+ case InterpTypeByRef:
953
+ flags = (GcSlotFlags)(flags | GC_SLOT_INTERIOR);
954
+ break ;
955
+ case InterpTypeVT:
956
+ {
957
+ InterpreterStackMap *stackMap = getInterpreterStackMap (m_compHnd, pVar->clsHnd );
958
+ for (unsigned j = 0 ; j < stackMap->m_slotCount ; j++)
959
+ {
960
+ InterpreterStackMapSlot slotInfo = stackMap->m_slots [j];
961
+ unsigned fieldOffset = pVar->offset + slotInfo.m_offsetBytes ;
962
+ GcSlotFlags fieldFlags = (GcSlotFlags)(flags | slotInfo.m_gcSlotFlags );
963
+ if (pass == 0 )
964
+ allocateGcSlot (fieldOffset, fieldFlags);
965
+ else
966
+ recordLiveRange (fieldOffset, fieldFlags, i);
967
+ }
968
+
969
+ // Don't perform the regular allocateGcSlot call
970
+ continue ;
971
+ }
972
+ default :
973
+ // Neither an object, interior pointer, or vt, so no slot needed
974
+ continue ;
975
+ }
976
+
977
+ if (pass == 0 )
978
+ allocateGcSlot (pVar->offset , flags);
979
+ else
980
+ recordLiveRange (pVar->offset , flags, i);
981
+ }
982
+
983
+ if (pass == 0 )
984
+ gcInfoEncoder->FinalizeSlotIds ();
985
+ else
986
+ gcInfoEncoder->Build ();
987
+ }
962
988
963
989
// GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
964
990
gcInfoEncoder->Emit ();
0 commit comments