Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/coreclr/jit/objectalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3838,6 +3838,20 @@ bool ObjectAllocator::CheckCanClone(CloneInfo* info)
JITDUMP("** Seeing if we can clone to guarantee non-escape under V%02u\n", info->m_local);
BasicBlock* const allocBlock = info->m_allocBlock;

// Cloning redirects the allocation block's sole outgoing edge to the fast path,
// so the allocation block must be a block kind that has a single target.
//
// If the allocation block ends in a conditional (say the def of the enumerator var
// is in the allocation block, and is followed by a GDV guard), we can't simply
// redirect, so bail out.
//
if (!allocBlock->HasTarget())
{
JITDUMP("allocation block " FMT_BB " is a %s, and so has no unique target edge\n", allocBlock->bbNum,
bbKindNames[allocBlock->GetKind()]);
return false;
}

// The allocation site must not be in a loop (stack allocation limitation)
//
// Note if we can prove non-escape but can't stack allocate, we might be
Expand Down
68 changes: 68 additions & 0 deletions src/tests/JIT/opt/ObjectStackAllocation/Runtime_131713.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using Xunit;
using TestLibrary;

public class Runtime_131713
{
[ActiveIssue("needs triage", TestRuntimes.Mono)]
[Fact]
public static void Test()
{
// The bug needs the serializer's methods to reach tier-1 with PGO data, so give
// the background compilations time to land in between calls.
for (int i = 0; i < 100; i++)
{
Serialize();
Thread.Sleep(15);
}
}

private static void Serialize()
{
Foo model = new()
{
Foos =
[
new Foo
{
Bars = [new Bar()]
}
]
};

XmlSerializer serializer = new(typeof(Foo));
using StringWriter stringWriter = new();
using XmlWriter xmlWriter = XmlWriter.Create(stringWriter);
serializer.Serialize(xmlWriter, model);
}
}

public class Foo
{
public CustomList<Bar> Bars { get; set; } = [];

public CustomList<Foo> Foos { get; set; } = [];
}

public class Bar
{
}

public class CustomList<T> : IEnumerable<T>
{
private readonly List<T> _innerList = [];

public void Add(T item) => _innerList.Add(item);

public IEnumerator<T> GetEnumerator() => _innerList.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => _innerList.GetEnumerator();
}
20 changes: 20 additions & 0 deletions src/tests/JIT/opt/ObjectStackAllocation/Runtime_131713.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<CLRTestPriority>1</CLRTestPriority>
<!-- Needed for CLRTestEnvironmentVariable -->
<RequiresProcessIsolation>true</RequiresProcessIsolation>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />

<!-- The bug reproduces only once the serializer's methods reach tier-1 with PGO data,
since conditional escape analysis requires profile weights. -->
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="1" />
<CLRTestEnvironmentVariable Include="DOTNET_TieredPGO" Value="1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(TestLibraryProjectPath)" />
</ItemGroup>
</Project>
Loading