void InlineContext::Dump(unsigned indent) { // Handle fact that siblings are in reverse order. if (m_Sibling != nullptr) { m_Sibling->Dump(indent); } // We may not know callee name in some of the failing cases Compiler* compiler = m_InlineStrategy->GetCompiler(); const char* calleeName = nullptr; if (m_Callee == nullptr) { assert(!m_Success); calleeName = "<unknown>"; } else { #if defined(DEBUG) calleeName = compiler->eeGetMethodFullName(m_Callee); #else calleeName = "callee"; #endif // defined(DEBUG) } mdMethodDef calleeToken = compiler->info.compCompHnd->getMethodDefFromMethod(m_Callee); // Dump this node if (m_Parent == nullptr) { // Root method printf("Inlines into %08X %s\n", calleeToken, calleeName); } else { // Inline attempt. const char* inlineReason = InlGetObservationString(m_Observation); const char* inlineResult = m_Success ? "" : "FAILED: "; if (m_Offset == BAD_IL_OFFSET) { printf("%*s[%u IL=???? TR=%06u %08X] [%s%s] %s\n", indent, "", m_Ordinal, m_TreeID, calleeToken, inlineResult, inlineReason, calleeName); } else { IL_OFFSET offset = jitGetILoffs(m_Offset); printf("%*s[%u IL=%04d TR=%06u %08X] [%s%s] %s\n", indent, "", m_Ordinal, offset, m_TreeID, calleeToken, inlineResult, inlineReason, calleeName); } } // Recurse to first child if (m_Child != nullptr) { m_Child->Dump(indent + 2); } }
void InlineContext::DumpXml(FILE* file, unsigned indent) { // Handle fact that siblings are in reverse order. if (m_Sibling != nullptr) { m_Sibling->DumpXml(file, indent); } Compiler* compiler = m_InlineStrategy->GetCompiler(); mdMethodDef calleeToken = compiler->info.compCompHnd->getMethodDefFromMethod(m_Callee); const bool isRoot = m_Parent == nullptr; const bool hasChild = m_Child != nullptr; const char* inlineType = m_Success ? "Inline" : "FailedInline"; unsigned newIndent = indent; if (!isRoot) { const char* inlineReason = InlGetObservationString(m_Observation); int offset = -1; if (m_Offset != BAD_IL_OFFSET) { offset = (int) jitGetILoffs(m_Offset); } fprintf(file, "%*s<%s>\n", indent, "", inlineType); fprintf(file, "%*s<Token>%u</Token>\n", indent + 2, "", calleeToken); fprintf(file, "%*s<Offset>%u</Offset>\n", indent + 2, "", offset); fprintf(file, "%*s<Reason>%s</Reason>\n", indent + 2, "", inlineReason); newIndent = indent + 2; } // Handle children if (hasChild) { fprintf(file, "%*s<Inlines>\n", newIndent, ""); m_Child->DumpXml(file, newIndent + 2); fprintf(file, "%*s</Inlines>\n", newIndent, ""); } else { fprintf(file, "%*s<Inlines />\n", newIndent, ""); } // Close out if (!isRoot) { fprintf(file, "%*s</%s>\n", indent, "", inlineType); } }
void InlineContext::Dump(Compiler* compiler, int indent) { // Handle fact that siblings are in reverse order. if (m_Sibling != nullptr) { m_Sibling->Dump(compiler, indent); } // We may not know callee name in some of the failing cases const char* calleeName = nullptr; if (m_Callee == nullptr) { assert(!m_Success); calleeName = "<unknown>"; } else { calleeName = compiler->eeGetMethodFullName(m_Callee); } // Dump this node if (m_Parent == nullptr) { // Root method printf("Inlines into %s\n", calleeName); } else { // Inline attempt. const char* inlineReason = InlGetObservationString(m_Observation); const char* inlineResult = m_Success ? "" : "FAILED: "; for (int i = 0; i < indent; i++) { printf(" "); } if (m_Offset == BAD_IL_OFFSET) { printf("[IL=???? TR=%06u] [%s%s] %s\n", m_TreeID, inlineResult, inlineReason, calleeName); } else { IL_OFFSET offset = jitGetILoffs(m_Offset); printf("[IL=%04d TR=%06u] [%s%s] %s\n", offset, m_TreeID, inlineResult, inlineReason, calleeName); } } // Recurse to first child if (m_Child != nullptr) { m_Child->Dump(compiler, indent + 2); } }
void InlineContext::DumpData(unsigned indent) { // Handle fact that siblings are in reverse order. if (m_Sibling != nullptr) { m_Sibling->DumpData(indent); } Compiler* compiler = m_InlineStrategy->GetCompiler(); #if defined(DEBUG) const char* calleeName = compiler->eeGetMethodFullName(m_Callee); #else const char* calleeName = "callee"; #endif // defined(DEBUG) if (m_Parent == nullptr) { // Root method... cons up a policy so we can display the name InlinePolicy* policy = InlinePolicy::GetPolicy(compiler, true); printf("\nInlines [%u] into \"%s\" [%s]\n", m_InlineStrategy->GetInlineCount(), calleeName, policy->GetName()); } else if (m_Success) { const char* inlineReason = InlGetObservationString(m_Observation); printf("%*s%u,\"%s\",\"%s\"", indent, "", m_Ordinal, inlineReason, calleeName); m_Policy->DumpData(stdout); printf("\n"); } // Recurse to first child if (m_Child != nullptr) { m_Child->DumpData(indent + 2); } }
void InlineResult::Report() { // If we weren't actually inlining, user may have suppressed // reporting via setReported(). If so, do nothing. if (m_Reported) { return; } m_Reported = true; #ifdef DEBUG const char* callee = nullptr; // Optionally dump the result if (VERBOSE) { const char* format = "INLINER: during '%s' result '%s' reason '%s' for '%s' calling '%s'\n"; const char* caller = (m_Caller == nullptr) ? "n/a" : m_RootCompiler->eeGetMethodFullName(m_Caller); callee = (m_Callee == nullptr) ? "n/a" : m_RootCompiler->eeGetMethodFullName(m_Callee); JITDUMP(format, m_Context, ResultString(), ReasonString(), caller, callee); } // If the inline failed, leave information on the call so we can // later recover what observation lead to the failure. if (IsFailure() && (m_Call != nullptr)) { // compiler should have revoked candidacy on the call by now assert((m_Call->gtFlags & GTF_CALL_INLINE_CANDIDATE) == 0); m_Call->gtInlineObservation = m_Policy->GetObservation(); } #endif // DEBUG // Was the result NEVER? If so we might want to propagate this to // the runtime. if (IsNever() && m_Policy->PropagateNeverToRuntime()) { // If we know the callee, and if the observation that got us // to this Never inline state is something *other* than // IS_NOINLINE, then we've uncovered a reason why this method // can't ever be inlined. Update the callee method attributes // so that future inline attempts for this callee fail faster. InlineObservation obs = m_Policy->GetObservation(); if ((m_Callee != nullptr) && (obs != InlineObservation::CALLEE_IS_NOINLINE)) { #ifdef DEBUG if (VERBOSE) { const char* obsString = InlGetObservationString(obs); JITDUMP("\nINLINER: Marking %s as NOINLINE because of %s\n", callee, obsString); } #endif // DEBUG COMP_HANDLE comp = m_RootCompiler->info.compCompHnd; comp->setMethodAttribs(m_Callee, CORINFO_FLG_BAD_INLINEE); } } if (IsDecided()) { const char* format = "INLINER: during '%s' result '%s' reason '%s'\n"; JITLOG_THIS(m_RootCompiler, (LL_INFO100000, format, m_Context, ResultString(), ReasonString())); COMP_HANDLE comp = m_RootCompiler->info.compCompHnd; comp->reportInliningDecision(m_Caller, m_Callee, Result(), ReasonString()); } }