summaryrefslogtreecommitdiff
path: root/src/jit/gcencode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/gcencode.cpp')
-rw-r--r--src/jit/gcencode.cpp267
1 files changed, 172 insertions, 95 deletions
diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp
index f20183b25a..128fc4addb 100644
--- a/src/jit/gcencode.cpp
+++ b/src/jit/gcencode.cpp
@@ -23,6 +23,89 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "gcinfotypes.h"
+ReturnKind GCTypeToReturnKind(CorInfoGCType gcType)
+{
+ switch (gcType)
+ {
+ case TYPE_GC_NONE:
+ return RT_Scalar;
+ case TYPE_GC_REF:
+ return RT_Object;
+ case TYPE_GC_BYREF:
+ return RT_ByRef;
+ default:
+ _ASSERTE(!"TYP_GC_OTHER is unexpected");
+ return RT_Illegal;
+ }
+}
+
+ReturnKind GCInfo::getReturnKind()
+{
+ switch (compiler->info.compRetType)
+ {
+ case TYP_REF:
+ case TYP_ARRAY:
+ return RT_Object;
+ case TYP_BYREF:
+ return RT_ByRef;
+ case TYP_STRUCT:
+ {
+ CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass;
+ var_types retType = compiler->getReturnTypeForStruct(structType);
+
+ switch (retType)
+ {
+ case TYP_ARRAY:
+ _ASSERTE(false && "TYP_ARRAY unexpected from getReturnTypeForStruct()");
+ // fall through
+ case TYP_REF:
+ return RT_Object;
+
+ case TYP_BYREF:
+ return RT_ByRef;
+
+ case TYP_STRUCT:
+ if (compiler->IsHfa(structType))
+ {
+#ifdef _TARGET_X86_
+ _ASSERTE(false && "HFAs not expected for X86");
+#endif // _TARGET_X86_
+
+ return RT_Scalar;
+ }
+ else
+ {
+ // Multi-reg return
+ BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
+ compiler->info.compCompHnd->getClassGClayout(structType, gcPtrs);
+
+ ReturnKind first = GCTypeToReturnKind((CorInfoGCType)gcPtrs[0]);
+ ReturnKind second = GCTypeToReturnKind((CorInfoGCType)gcPtrs[1]);
+
+ return GetStructReturnKind(first, second);
+ }
+
+#ifdef _TARGET_X86_
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+ return RT_Float;
+#endif // _TARGET_X86_
+ default:
+ return RT_Scalar;
+ }
+ }
+
+#ifdef _TARGET_X86_
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+ return RT_Float;
+#endif // _TARGET_X86_
+
+ default:
+ return RT_Scalar;
+ }
+}
+
#ifdef JIT32_GCENCODER
#include "emit.h"
@@ -104,18 +187,21 @@ static void regenLog(unsigned encoding, InfoHdr* header, InfoHdr* state)
fprintf(logFile, "InfoHdr( %2d, %2d, %1d, %1d, %1d,"
" %1d, %1d, %1d, %1d, %1d,"
- " %1d, %1d, %1d, %1d, %1d,"
- " %1d, %2d, %2d, %2d, %2d,"
- " %2d, %2d), \n",
+ " %1d, %1d, %1d, %1d, %1d, %1d,"
+ " %1d, %1d, %1d,"
+ " %1d, %2d, %2d,"
+ " %2d, %2d, %2d, %2d, %2d, %2d), \n",
state->prologSize, state->epilogSize, state->epilogCount, state->epilogAtEnd, state->ediSaved,
state->esiSaved, state->ebxSaved, state->ebpSaved, state->ebpFrame, state->interruptible,
state->doubleAlign, state->security, state->handlers, state->localloc, state->editNcontinue, state->varargs,
- state->profCallbacks, state->argCount, state->frameSize,
+ state->profCallbacks, state->genericsContext, state->genericsContextIsMethodDesc, state->returnKind,
+ state->argCount, state->frameSize,
(state->untrackedCnt <= SET_UNTRACKED_MAX) ? state->untrackedCnt : HAS_UNTRACKED,
(state->varPtrTableSize == 0) ? 0 : HAS_VARPTR,
(state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET) ? 0 : HAS_GS_COOKIE_OFFSET,
(state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
- (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET);
+ (state->syncStartOffset == INVALID_SYNC_OFFSET) ? 0 : HAS_SYNC_OFFSET,
+ (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET) ? 0 : HAS_REV_PINVOKE_FRAME_OFFSET);
fflush(logFile);
@@ -265,9 +351,11 @@ static int bigEncoding4(unsigned cur, unsigned tgt, unsigned max)
return cnt;
}
-BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
+BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state, BYTE& codeSet)
{
BYTE encoding = 0xff;
+ codeSet = 1; // codeSet is 1 or 2, depending on whether the returned encoding
+ // corresponds to InfoHdrAdjust, or InfoHdrAdjust2 enumerations.
if (state->argCount != header.argCount)
{
@@ -547,6 +635,15 @@ BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
goto DO_RETURN;
}
+ if (GCInfoEncodesReturnKind() && (state->returnKind != header.returnKind))
+ {
+ state->returnKind = header.returnKind;
+ codeSet = 2; // Two byte encoding
+ encoding = header.returnKind;
+ _ASSERTE(encoding < SET_RET_KIND_MAX);
+ goto DO_RETURN;
+ }
+
if (state->gsCookieOffset != header.gsCookieOffset)
{
assert(state->gsCookieOffset == INVALID_GS_COOKIE_OFFSET || state->gsCookieOffset == HAS_GS_COOKIE_OFFSET);
@@ -587,10 +684,31 @@ BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state)
}
}
+ if (GCInfoEncodesRevPInvokeFrame() && (state->revPInvokeOffset != header.revPInvokeOffset))
+ {
+ assert(state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET ||
+ state->revPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET);
+
+ if (state->revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
+ {
+ // header.revPInvokeOffset is non-zero.
+ state->revPInvokeOffset = HAS_REV_PINVOKE_FRAME_OFFSET;
+ encoding = FLIP_REV_PINVOKE_FRAME;
+ goto DO_RETURN;
+ }
+ else if (header.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET)
+ {
+ state->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
+ encoding = FLIP_REV_PINVOKE_FRAME;
+ goto DO_RETURN;
+ }
+ }
+
DO_RETURN:
- assert(encoding < 0x80);
+ _ASSERTE(encoding < MORE_BYTES_TO_FOLLOW);
if (!state->isHeaderMatch(header))
- encoding |= 0x80;
+ encoding |= MORE_BYTES_TO_FOLLOW;
+
return encoding;
}
@@ -806,6 +924,14 @@ static int measureDistance(const InfoHdr& header, const InfoHdrSmall* p, int clo
return distance;
}
+ if (p->returnKind != header.returnKind)
+ {
+ // Setting the ReturnKind requires two bytes of encoding.
+ distance += 2;
+ if (distance >= closeness)
+ return distance;
+ }
+
if (header.gsCookieOffset != INVALID_GS_COOKIE_OFFSET)
{
distance += 1;
@@ -820,6 +946,13 @@ static int measureDistance(const InfoHdr& header, const InfoHdrSmall* p, int clo
return distance;
}
+ if (header.revPInvokeOffset != INVALID_REV_PINVOKE_OFFSET)
+ {
+ distance += 1;
+ if (distance >= closeness)
+ return distance;
+ }
+
return distance;
}
@@ -1164,6 +1297,16 @@ size_t GCInfo::gcInfoBlockHdrSave(
header->genericsContext = compiler->lvaReportParamTypeArg();
header->genericsContextIsMethodDesc =
header->genericsContext && (compiler->info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC));
+
+ if (GCInfoEncodesReturnKind())
+ {
+ ReturnKind returnKind = getReturnKind();
+ _ASSERTE(IsValidReturnKind(returnKind) && "Return Kind must be valid");
+ _ASSERTE(!IsStructReturnKind(returnKind) && "Struct Return Kinds Unexpected for JIT32");
+ _ASSERTE(((int)returnKind < (int)SET_RET_KIND_MAX) && "ReturnKind has no legal encoding");
+ header->returnKind = returnKind;
+ }
+
header->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
if (compiler->getNeedsGSSecurityCookie())
{
@@ -1190,6 +1333,8 @@ size_t GCInfo::gcInfoBlockHdrSave(
assert(header->epilogCount <= 1);
}
+ header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
+
assert((compiler->compArgSize & 0x3) == 0);
size_t argCount =
@@ -1224,12 +1369,21 @@ size_t GCInfo::gcInfoBlockHdrSave(
*dest++ = headerEncoding;
BYTE encoding = headerEncoding;
- while (encoding & 0x80)
+ BYTE codeSet = 1;
+ while (encoding & MORE_BYTES_TO_FOLLOW)
{
- encoding = encodeHeaderNext(*header, &state);
+ encoding = encodeHeaderNext(*header, &state, codeSet);
+
#if REGEN_SHORTCUTS
regenLog(headerEncoding, header, &state);
#endif
+ _ASSERTE(codeSet == 1 || codeSet == 2 && "Encoding must correspond to InfoHdrAdjust or InfoHdrAdjust2");
+ if (codeSet == 2)
+ {
+ *dest++ = NEXT_OPCODE | MORE_BYTES_TO_FOLLOW;
+ ++size;
+ }
+
*dest++ = encoding;
++size;
}
@@ -1771,12 +1925,12 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
}
else
{
- /* Stack-passed arguments which are not enregistered
- * are always reported in this "untracked stack
- * pointers" section of the GC info even if lvTracked==true
- */
+/* Stack-passed arguments which are not enregistered
+ * are always reported in this "untracked stack
+ * pointers" section of the GC info even if lvTracked==true
+ */
- /* Has this argument been enregistered? */
+/* Has this argument been enregistered? */
#ifndef LEGACY_BACKEND
if (!varDsc->lvOnFrame)
#else // LEGACY_BACKEND
@@ -3277,7 +3431,7 @@ void GCInfo::gcFindPtrsInFrame(const void* infoBlock, const void* codeBlock, uns
GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
- gcDump.DumpPtrsInFrame((const BYTE*)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
+ gcDump.DumpPtrsInFrame((PTR_CBYTE)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
}
#endif // DUMP_GC_TABLES
@@ -3504,23 +3658,6 @@ public:
#endif // DEBUG
-ReturnKind GCTypeToReturnKind(CorInfoGCType gcType)
-{
-
- switch (gcType)
- {
- case TYPE_GC_NONE:
- return RT_Scalar;
- case TYPE_GC_REF:
- return RT_Object;
- case TYPE_GC_BYREF:
- return RT_ByRef;
- default:
- _ASSERTE(!"TYP_GC_OTHER is unexpected");
- return RT_Illegal;
- }
-}
-
void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSize, unsigned prologSize)
{
#ifdef DEBUG
@@ -3536,65 +3673,7 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz
gcInfoEncoderWithLog->SetCodeLength(methodSize);
- ReturnKind returnKind = RT_Illegal;
-
- switch (compiler->info.compRetType)
- {
- case TYP_REF:
- case TYP_ARRAY:
- returnKind = RT_Object;
- break;
- case TYP_BYREF:
- returnKind = RT_ByRef;
- break;
- case TYP_STRUCT:
- {
- CORINFO_CLASS_HANDLE structType = compiler->info.compMethodInfo->args.retTypeClass;
- var_types retType = compiler->getReturnTypeForStruct(structType);
-
- switch (retType)
- {
- case TYP_ARRAY:
- _ASSERTE(false && "TYP_ARRAY unexpected from getReturnTypeForStruct()");
-
- case TYP_REF:
- returnKind = RT_Object;
- break;
-
- case TYP_BYREF:
- returnKind = RT_ByRef;
- break;
-
- case TYP_STRUCT:
- if (compiler->IsHfa(structType))
- {
- returnKind = RT_Scalar;
- }
- else
- {
- // Multi-reg return
- BYTE gcPtrs[2] = { TYPE_GC_NONE, TYPE_GC_NONE };
- compiler->info.compCompHnd->getClassGClayout(structType, gcPtrs);
-
- ReturnKind first = GCTypeToReturnKind((CorInfoGCType)gcPtrs[0]);
- ReturnKind second = GCTypeToReturnKind((CorInfoGCType)gcPtrs[1]);
-
- returnKind = GetStructReturnKind(first, second);
- }
- break;
-
- default:
- returnKind = RT_Scalar;
- break;
- }
- break;
- }
- default:
- returnKind = RT_Scalar;
- }
-
- _ASSERTE(returnKind != RT_Illegal);
- gcInfoEncoderWithLog->SetReturnKind(returnKind);
+ gcInfoEncoderWithLog->SetReturnKind(getReturnKind());
if (compiler->isFramePointerUsed())
{
@@ -3682,10 +3761,8 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz
}
#if FEATURE_EH_FUNCLETS
- if (compiler->ehNeedsPSPSym())
+ if (compiler->lvaPSPSym != BAD_VAR_NUM)
{
- assert(compiler->lvaPSPSym != BAD_VAR_NUM);
-
#ifdef _TARGET_AMD64_
// The PSPSym is relative to InitialSP on X64 and CallerSP on other platforms.
gcInfoEncoderWithLog->SetPSPSymStackSlot(compiler->lvaGetInitialSPRelativeOffset(compiler->lvaPSPSym));