Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
30 changes: 29 additions & 1 deletion src/coreclr/src/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5902,13 +5902,13 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken, const B
break;

case CEE_ISINST:
// box + isinst + br_true/false
if (codeAddr + 1 + sizeof(mdToken) + 1 <= codeEndp)
{
const BYTE* nextCodeAddr = codeAddr + 1 + sizeof(mdToken);

switch (nextCodeAddr[0])
{
// box + isinst + br_true/false
case CEE_BRTRUE:
case CEE_BRTRUE_S:
case CEE_BRFALSE:
Expand Down Expand Up @@ -5941,6 +5941,34 @@ int Compiler::impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken, const B
}
}
}
break;

// box + isinst + unbox.any
case CEE_UNBOX_ANY:
if ((nextCodeAddr + 1 + sizeof(mdToken)) <= codeEndp)
{
CORINFO_RESOLVED_TOKEN isinstResolvedToken = {};
impResolveToken(codeAddr + 1, &isinstResolvedToken, CORINFO_TOKENKIND_Class);

CORINFO_RESOLVED_TOKEN unboxResolvedToken = {};
impResolveToken(nextCodeAddr + 1, &unboxResolvedToken, CORINFO_TOKENKIND_Class);

// See if the resolved tokens describe types that are equal.
const TypeCompareState compareBoxIsInst =
info.compCompHnd->compareTypesForEquality(isinstResolvedToken.hClass,
pResolvedToken->hClass);
const TypeCompareState compareBoxUnbox =
info.compCompHnd->compareTypesForEquality(unboxResolvedToken.hClass,
pResolvedToken->hClass);

// If so, box/unbox.any is a nop.
if (compareBoxIsInst == TypeCompareState::Must && compareBoxUnbox == TypeCompareState::Must)
{
JITDUMP("\n Importing BOX; ISINST, UNBOX.ANY as NOP\n");
return 2 + sizeof(mdToken) * 2;
}
}
break;
}
}
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="box_isinst_unbox.cs" />
</ItemGroup>
<PropertyGroup>
<CLRTestBatchPreCommands><![CDATA[
$(CLRTestBatchPreCommands)
set COMPlus_JitNoInline=1
]]></CLRTestBatchPreCommands>
<BashCLRTestPreCommands><![CDATA[
$(BashCLRTestPreCommands)
export COMPlus_JitNoInline=1
]]></BashCLRTestPreCommands>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// 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 System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public static class Tests
{
private static int returnCode = 100;

public static int BoxIsInstUnbox1<T>(T t) => t is int n ? n : -1;
public static int BoxIsInstUnbox2<T>(T t) => t is string n ? n.Length : -1;
public static int BoxIsInstUnbox3<T>(T t) => t is Struct1<int> n ? n.a : -1;
public static int BoxIsInstUnbox4<T>(T t) => t is Struct1<IDisposable> n ? n.GetHashCode() : -1;
public static int BoxIsInstUnbox5<T>(T t) => t is Class1<int> n ? n.a : -1;
public static int BoxIsInstUnbox6<T>(T t) => t is RefBase n ? n.a : -1;
public static int BoxIsInstUnbox7<T>(T t) => t is object[] n ? n.Length : -1;

public static void Expect(this int actual, int expected, [CallerLineNumber] int line = 0)
{
if (expected != actual)
{
Console.WriteLine($"{actual} != {expected}, line {line}.");
returnCode++;
}
}

public static int Main()
{
BoxIsInstUnbox1<int>(1).Expect(1);
BoxIsInstUnbox1<uint>(1).Expect(-1);
BoxIsInstUnbox1<byte>(1).Expect(-1);
BoxIsInstUnbox1<long>(1).Expect(-1);
BoxIsInstUnbox1<decimal>(1).Expect(-1);
BoxIsInstUnbox1<int?>(1).Expect(1);
BoxIsInstUnbox1<int?>(null).Expect(-1);
BoxIsInstUnbox1<uint?>(1).Expect(-1);
BoxIsInstUnbox1<string>("1").Expect(-1);
BoxIsInstUnbox1<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox1<string>(null).Expect(-1);
BoxIsInstUnbox1<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox1<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox1<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox1<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox1<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox2<int>(1).Expect(-1);
BoxIsInstUnbox2<uint>(1).Expect(-1);
BoxIsInstUnbox2<byte>(1).Expect(-1);
BoxIsInstUnbox2<long>(1).Expect(-1);
BoxIsInstUnbox2<decimal>(1).Expect(-1);
BoxIsInstUnbox2<int?>(1).Expect(-1);
BoxIsInstUnbox2<int?>(null).Expect(-1);
BoxIsInstUnbox2<uint?>(1).Expect(-1);
BoxIsInstUnbox2<string>("1").Expect(1);
BoxIsInstUnbox2<string>(1.ToString()).Expect(1);
BoxIsInstUnbox2<string>(null).Expect(-1);
BoxIsInstUnbox2<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox2<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox2<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox2<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox2<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox3<int>(1).Expect(-1);
BoxIsInstUnbox3<uint>(1).Expect(-1);
BoxIsInstUnbox3<byte>(1).Expect(-1);
BoxIsInstUnbox3<long>(1).Expect(-1);
BoxIsInstUnbox3<decimal>(1).Expect(-1);
BoxIsInstUnbox3<int?>(1).Expect(-1);
BoxIsInstUnbox3<int?>(null).Expect(-1);
BoxIsInstUnbox3<uint?>(1).Expect(-1);
BoxIsInstUnbox3<string>("1").Expect(-1);
BoxIsInstUnbox3<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox3<string>(null).Expect(-1);
BoxIsInstUnbox3<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox3<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox3<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox3<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox3<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox3<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox3<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox4<int>(1).Expect(-1);
BoxIsInstUnbox4<uint>(1).Expect(-1);
BoxIsInstUnbox4<byte>(1).Expect(-1);
BoxIsInstUnbox4<long>(1).Expect(-1);
BoxIsInstUnbox4<decimal>(1).Expect(-1);
BoxIsInstUnbox4<int?>(1).Expect(-1);
BoxIsInstUnbox4<int?>(null).Expect(-1);
BoxIsInstUnbox4<uint?>(1).Expect(-1);
BoxIsInstUnbox4<string>("1").Expect(-1);
BoxIsInstUnbox4<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox4<string>(null).Expect(-1);
BoxIsInstUnbox4<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox4<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox4<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox4<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox4<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox5<int>(1).Expect(-1);
BoxIsInstUnbox5<uint>(1).Expect(-1);
BoxIsInstUnbox5<byte>(1).Expect(-1);
BoxIsInstUnbox5<long>(1).Expect(-1);
BoxIsInstUnbox5<decimal>(1).Expect(-1);
BoxIsInstUnbox5<int?>(1).Expect(-1);
BoxIsInstUnbox5<int?>(null).Expect(-1);
BoxIsInstUnbox5<uint?>(1).Expect(-1);
BoxIsInstUnbox5<string>("1").Expect(-1);
BoxIsInstUnbox5<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox5<string>(null).Expect(-1);
BoxIsInstUnbox5<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox5<Class1<int>>(new Class1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox5<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Class1<int>>(new Class1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox5<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox5<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox5<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox5<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox6<int>(1).Expect(-1);
BoxIsInstUnbox6<uint>(1).Expect(-1);
BoxIsInstUnbox6<byte>(1).Expect(-1);
BoxIsInstUnbox6<long>(1).Expect(-1);
BoxIsInstUnbox6<decimal>(1).Expect(-1);
BoxIsInstUnbox6<int?>(1).Expect(-1);
BoxIsInstUnbox6<int?>(null).Expect(-1);
BoxIsInstUnbox6<uint?>(1).Expect(-1);
BoxIsInstUnbox6<string>("1").Expect(-1);
BoxIsInstUnbox6<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox6<string>(null).Expect(-1);
BoxIsInstUnbox6<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox6<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox6<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox6<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox6<Class1<int>>(new Class1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<string>>(new Class1<string> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<int>>(new Class1<int> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<string>>(new Class1<string> { a = 1 }).Expect(1);
BoxIsInstUnbox6<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(1);
BoxIsInstUnbox6<string[]>(new string[1]).Expect(-1);
BoxIsInstUnbox6<object[]>(new string[1]).Expect(-1);
BoxIsInstUnbox6<IEnumerable<object>>(new string[1]).Expect(-1);

BoxIsInstUnbox7<int>(1).Expect(-1);
BoxIsInstUnbox7<uint>(1).Expect(-1);
BoxIsInstUnbox7<byte>(1).Expect(-1);
BoxIsInstUnbox7<long>(1).Expect(-1);
BoxIsInstUnbox7<decimal>(1).Expect(-1);
BoxIsInstUnbox7<int?>(1).Expect(-1);
BoxIsInstUnbox7<int?>(null).Expect(-1);
BoxIsInstUnbox7<uint?>(1).Expect(-1);
BoxIsInstUnbox7<string>("1").Expect(-1);
BoxIsInstUnbox7<string>(1.ToString()).Expect(-1);
BoxIsInstUnbox7<string>(null).Expect(-1);
BoxIsInstUnbox7<Struct1<int>>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Struct1<int>?>(new Struct1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Struct1<uint>>(new Struct1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Struct2<IDisposable>>(new Struct2<IDisposable>()).Expect(-1);
BoxIsInstUnbox7<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<int>>(new Class1<int> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<uint>>(new Class1<uint> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<string>>(new Class1<string> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<Class1<IDisposable>>(new Class1<IDisposable> { a = 1 }).Expect(-1);
BoxIsInstUnbox7<string[]>(new string[1]).Expect(1);
BoxIsInstUnbox7<object[]>(new string[1]).Expect(1);
BoxIsInstUnbox7<IEnumerable<object>>(new string[1]).Expect(1);

return returnCode;
}
}

public struct Struct1<T>
{
public T a;
}

public struct Struct2<T>
{
public T a;
}

public class RefBase : IDisposable
{
public int a;
public void Dispose() { }
}

public class Class1<T> : RefBase
{
public T b;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="box_isinst_unbox.cs" />
</ItemGroup>
</Project>