// The lookup of the code pointer will be handled by CALL in this case
if (clsFlags & CORINFO_FLG_VALUECLASS)
{
+ if (compIsForInlining())
+ {
+ if (impInlineInfo->iciBlock->isRunRarely())
+ {
+ // If value class has GC fields, inform
+ // the inliner. It may choose to bail out
+ // on the inline, if the call site is
+ // rare.
+ DWORD typeFlags = info.compCompHnd->getClassAttribs(resolvedToken.hClass);
+ if ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0)
+ {
+ compInlineResult->Note(InlineObservation::CALLSITE_RARE_GC_STRUCT);
+ if (compInlineResult->IsFailure())
+ {
+ return;
+ }
+ }
+ }
+ }
+
CorInfoType jitTyp = info.compCompHnd->asCorInfoType(resolvedToken.hClass);
unsigned size = info.compCompHnd->getClassSize(resolvedToken.hClass);
var_types sigType = (var_types)eeGetArgType(argLst, &methInfo->args);
lclVarInfo[i].lclVerTypeInfo = verParseArgSigToTypeInfo(&methInfo->args, argLst);
+
#ifdef FEATURE_SIMD
if ((!foundSIMDType || (sigType == TYP_STRUCT)) && isSIMDClass(&(lclVarInfo[i].lclVerTypeInfo)))
{
lclVarInfo[i + argCnt].lclVerTypeInfo = verParseArgSigToTypeInfo(&methInfo->locals, localsSig);
+ // If this local is a struct type with GC fields, inform the
+ // inliner. It may choose to bail out on the inline, if the call
+ // site is rare.
+ if (pInlineInfo->iciBlock->isRunRarely())
+ {
+ if (type == TYP_STRUCT)
+ {
+ CORINFO_CLASS_HANDLE lclHandle = lclVarInfo[i + argCnt].lclVerTypeInfo.GetClassHandle();
+ DWORD typeFlags = info.compCompHnd->getClassAttribs(lclHandle);
+ if ((typeFlags & CORINFO_FLG_CONTAINS_GC_PTR) != 0)
+ {
+ inlineResult->Note(InlineObservation::CALLSITE_RARE_GC_STRUCT);
+ if (inlineResult->IsFailure())
+ {
+ return;
+ }
+ }
+ }
+ }
+
localsSig = info.compCompHnd->getArgNext(localsSig);
#ifdef FEATURE_SIMD
// ------ Call Site Performance -------
+INLINE_OBSERVATION(RARE_GC_STRUCT, bool, "rarely called, has gc struct", FATAL, CALLSITE)
// ------ Call Site Information -------
// NoteBool: handle a boolean observation with non-fatal impact
//
// Arguments:
-// obs - the current obsevation
+// obs - the current observation
// value - the value of the observation
void EnhancedLegacyPolicy::NoteBool(InlineObservation obs, bool value)
m_IsNoReturnKnown = true;
break;
+ case InlineObservation::CALLSITE_RARE_GC_STRUCT:
+ // If this is a discretionary or always inline candidate
+ // with a gc struct, we may change our mind about inlining
+ // if the call site is rare, to avoid costs associated with
+ // zeroing the GC struct up in the root prolog.
+ if (m_Observation == InlineObservation::CALLEE_BELOW_ALWAYS_INLINE_SIZE)
+ {
+ assert(m_CallsiteFrequency == InlineCallsiteFrequency::UNUSED);
+ SetFailure(obs);
+ return;
+ }
+ else if (m_Observation == InlineObservation::CALLEE_IS_DISCRETIONARY_INLINE)
+ {
+ assert(m_CallsiteFrequency == InlineCallsiteFrequency::RARE);
+ SetFailure(obs);
+ return;
+ }
+ break;
+
default:
// Pass all other information to the legacy policy
LegacyPolicy::NoteBool(obs, value);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Xunit.Performance;
+using System;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+[assembly: OptimizeForBenchmarks]
+[assembly: MeasureInstructionsRetired]
+
+public class InlineGCStruct
+{
+
+#if DEBUG
+ public const int Iterations = 1;
+#else
+ public const int Iterations = 2500000;
+#endif
+
+[MethodImpl(MethodImplOptions.NoInlining)]
+public static int FastFunctionNotCallingStringFormat(int param)
+{
+ if (param < 0) {
+ throw new Exception(String.Format("We do not like the value {0:N0}.", param));
+ }
+
+ if (param == int.MaxValue) {
+ throw new Exception(String.Format("{0:N0} is maxed out.", param));
+ }
+
+ if (param > int.MaxValue / 2) {
+ throw new Exception(String.Format("We do not like the value {0:N0} either.", param));
+ }
+
+ return param * 2;
+}
+
+[MethodImpl(MethodImplOptions.NoInlining)]
+public static int FastFunctionNotHavingStringFormat(int param)
+{
+ if (param < 0) {
+ throw new ArgumentOutOfRangeException("param", "We do not like this value.");
+ }
+
+ if (param == int.MaxValue) {
+ throw new ArgumentOutOfRangeException("param", "Maxed out.");
+ }
+
+ if (param > int.MaxValue / 2) {
+ throw new ArgumentOutOfRangeException("param", "We do not like this value either.");
+ }
+
+ return param * 2;
+}
+
+[Benchmark]
+public static bool WithFormat()
+{
+ int result = 0;
+
+ foreach (var iteration in Benchmark.Iterations) {
+ using (iteration.StartMeasurement()) {
+ for (int i = 0; i < Iterations; i++) {
+ result |= FastFunctionNotCallingStringFormat(11);
+ }
+ }
+ }
+
+ return (result == 22);
+}
+
+[Benchmark]
+public static bool WithoutFormat()
+{
+ int result = 0;
+
+ foreach (var iteration in Benchmark.Iterations) {
+ using (iteration.StartMeasurement()) {
+ for (int i = 0; i < Iterations; i++) {
+ result |= FastFunctionNotHavingStringFormat(11);
+ }
+ }
+ }
+
+ return (result == 22);
+}
+
+public static bool WithoutFormatBase()
+{
+ int result = 0;
+
+ for (int i = 0; i < Iterations; i++) {
+ result |= FastFunctionNotHavingStringFormat(11);
+ }
+
+ return (result == 22);
+}
+
+public static bool WithFormatBase()
+{
+ int result = 0;
+
+ for (int i = 0; i < Iterations; i++) {
+ result |= FastFunctionNotCallingStringFormat(11);
+ }
+
+ return (result == 22);
+}
+
+public static int Main()
+{
+ bool withFormat = WithFormatBase();
+ bool withoutFormat = WithoutFormatBase();
+
+ return (withFormat && withoutFormat ? 100 : -1);
+}
+
+}
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="InlineGCStruct.cs" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>$(JitPackagesConfigFileDirectory)benchmark\project.json</ProjectJson>
+ <ProjectLockJson>$(JitPackagesConfigFileDirectory)benchmark\project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>