diff options
Diffstat (limited to 'src/jit/gcencode.cpp')
-rw-r--r-- | src/jit/gcencode.cpp | 267 |
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)); |