{
CORINFO_METHOD_HANDLE methodHnd = info.compMethodHnd;
- info.compCode = methodInfo->ILCode;
- info.compILCodeSize = methodInfo->ILCodeSize;
+ info.compCode = methodInfo->ILCode;
+ info.compILCodeSize = methodInfo->ILCodeSize;
+ info.compILImportSize = 0;
if (info.compILCodeSize == 0)
{
const BYTE* compCode;
IL_OFFSET compILCodeSize; // The IL code size
+ IL_OFFSET compILImportSize; // Estimated amount of IL actually imported
UNATIVE_OFFSET compNativeCodeSize; // The native code size, after instructions are issued. This
// is less than (compTotalHotCodeSize + compTotalColdCodeSize) only if:
// (1) the code is not hot/cold split, and we issued less code than we expected, or
verFlag = tiIsVerifiableCode ? CORINFO_FLG_VERIFIABLE : CORINFO_FLG_UNVERIFIABLE;
info.compCompHnd->setMethodAttribs(info.compMethodHnd, verFlag);
}
+
+ // Estimate how much of method IL was actually imported.
+ //
+ // Note this includes (to some extent) the impact of importer folded
+ // branches, provided the folded tree covered the entire block's IL.
+ unsigned importedILSize = 0;
+ for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
+ {
+ if ((block->bbFlags & BBF_IMPORTED) != 0)
+ {
+ // Assume if we generate any IR for the block we generate IR for the entire block.
+ if (!block->isEmpty())
+ {
+ unsigned blockILSize = blockILSize = block->bbCodeOffsEnd - block->bbCodeOffs;
+ importedILSize += blockILSize;
+ }
+ }
+ }
+
+ // Could be tripped up if we ever duplicate blocks
+ assert(importedILSize <= info.compILCodeSize);
+
+ // Leave a note if we only did a partial import.
+ if (importedILSize != info.compILCodeSize)
+ {
+ JITDUMP("\n** Note: %s IL was partially imported -- imported %u of %u bytes of method IL\n",
+ compIsForInlining() ? "inlinee" : "root method", importedILSize, info.compILCodeSize);
+ }
+
+ // Record this for diagnostics and for the inliner's budget computations
+ info.compILImportSize = importedILSize;
+
+ if (compIsForInlining())
+ {
+ compInlineResult->SetImportedILSize(info.compILImportSize);
+ }
}
/*****************************************************************************
, m_Sibling(nullptr)
, m_Code(nullptr)
, m_ILSize(0)
+ , m_ImportedILSize(0)
, m_Offset(BAD_IL_OFFSET)
, m_Observation(InlineObservation::CALLEE_UNUSED_INITIAL)
, m_CodeSizeEstimate(0)
, m_InlineContext(nullptr)
, m_Caller(nullptr)
, m_Callee(nullptr)
+ , m_ImportedILSize(0)
, m_Description(description)
, m_Reported(false)
{
{
// Simple linear models based on observations
// show time is fairly well predicted by IL size.
- unsigned ilSize = context->GetILSize();
-
+ //
// Prediction varies for root and inlines.
if (context == m_RootContext)
{
- return EstimateRootTime(ilSize);
+ return EstimateRootTime(context->GetILSize());
}
else
{
- return EstimateInlineTime(ilSize);
+ // Use amount of IL actually imported
+ return EstimateInlineTime(context->GetImportedILSize());
}
}
}
//------------------------------------------------------------------------
-// BudgetCheck: return true if as inline of this size would exceed the
-// jit time budget for this method
+// BudgetCheck: return true if an inline of this size would likely
+// exceed the jit time budget for this method
//
// Arguments:
// ilSize - size of the method's IL
//
// Return Value:
// true if the inline would go over budget
+//
+// Notes:
+// Presumes all IL in the method will be imported.
bool InlineStrategy::BudgetCheck(unsigned ilSize)
{
calleeContext->m_Parent = parentContext;
// Push on front here will put siblings in reverse lexical
// order which we undo in the dumper
- calleeContext->m_Sibling = parentContext->m_Child;
- parentContext->m_Child = calleeContext;
- calleeContext->m_Child = nullptr;
- calleeContext->m_Offset = stmt->gtStmtILoffsx;
- calleeContext->m_Observation = inlineInfo->inlineResult->GetObservation();
- calleeContext->m_Success = true;
- calleeContext->m_Devirtualized = originalCall->IsDevirtualized();
- calleeContext->m_Guarded = originalCall->IsGuarded();
- calleeContext->m_Unboxed = originalCall->IsUnboxed();
+ calleeContext->m_Sibling = parentContext->m_Child;
+ parentContext->m_Child = calleeContext;
+ calleeContext->m_Child = nullptr;
+ calleeContext->m_Offset = stmt->gtStmtILoffsx;
+ calleeContext->m_Observation = inlineInfo->inlineResult->GetObservation();
+ calleeContext->m_Success = true;
+ calleeContext->m_Devirtualized = originalCall->IsDevirtualized();
+ calleeContext->m_Guarded = originalCall->IsGuarded();
+ calleeContext->m_Unboxed = originalCall->IsUnboxed();
+ calleeContext->m_ImportedILSize = inlineInfo->inlineResult->GetImportedILSize();
#if defined(DEBUG) || defined(INLINE_DATA)
m_Reported = true;
}
- // Get the InlineContext for this inline
+ // Get the InlineContext for this inline.
InlineContext* GetInlineContext() const
{
return m_InlineContext;
}
+ unsigned GetImportedILSize() const
+ {
+ return m_ImportedILSize;
+ }
+
+ void SetImportedILSize(unsigned x)
+ {
+ m_ImportedILSize = x;
+ }
+
private:
// No copying or assignment allowed.
InlineResult(const InlineResult&) = delete;
InlineContext* m_InlineContext;
CORINFO_METHOD_HANDLE m_Caller; // immediate caller's handle
CORINFO_METHOD_HANDLE m_Callee;
+ unsigned m_ImportedILSize; // estimated size of imported IL
const char* m_Description;
bool m_Reported;
};
return m_Unboxed;
}
+ unsigned GetImportedILSize() const
+ {
+ return m_ImportedILSize;
+ }
+
private:
InlineContext(InlineStrategy* strategy);
InlineContext* m_Sibling; // next child of the parent
BYTE* m_Code; // address of IL buffer for the method
unsigned m_ILSize; // size of IL buffer for the method
+ unsigned m_ImportedILSize; // estimated size of imported IL
IL_OFFSETX m_Offset; // call site location within parent
InlineObservation m_Observation; // what lead to this inline
int m_CodeSizeEstimate; // in bytes * 10