// equal, or the comparison needs to be resolved at runtime.
TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
LWM(IsValueClass, DWORDLONG, DWORD)
LWM(IsWriteBarrierHelperRequired, DWORDLONG, DWORD)
LWM(MergeClasses, DLDL, DWORDLONG)
+LWM(IsMoreSpecificType, DLDL, DWORD)
LWM(PInvokeMarshalingRequired, PInvokeMarshalingRequiredValue, DWORD)
LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue)
LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethod, DWORDLONG)
return (CORINFO_CLASS_HANDLE)value;
}
+void MethodContext::recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result)
+{
+ if (IsMoreSpecificType == nullptr)
+ IsMoreSpecificType = new LightWeightMap<DLDL, DWORD>();
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ IsMoreSpecificType->Add(key, (DWORD)result);
+}
+void MethodContext::dmpIsMoreSpecificType(DLDL key, DWORD value)
+{
+ printf("IsMoreSpecificType key cls1-%016llX cls2-%016llX, value %u", key.A, key.B, value);
+}
+BOOL MethodContext::repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+ DWORD value;
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ AssertCodeMsg(IsMoreSpecificType->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX", (DWORDLONG)cls1,
+ (DWORDLONG)cls2);
+
+ value = IsMoreSpecificType->Get(key);
+
+ return (BOOL)value;
+}
+
void MethodContext::recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result)
{
if (GetCookieForPInvokeCalliSig == nullptr)
void dmpMergeClasses(DLDL key, DWORDLONG value);
CORINFO_CLASS_HANDLE repMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ void recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, BOOL result);
+ void dmpIsMoreSpecificType(DLDL key, DWORD value);
+ BOOL repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
void recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result);
void dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value);
LPVOID repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection);
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 173
+// Highest packet number: 174
// *************************************************************************************
enum mcPackets
{
Packet_IsValueClass = 105,
Packet_IsWriteBarrierHelperRequired = 106,
Packet_MergeClasses = 107,
+ Packet_IsMoreSpecificType = 174, // Added 2/14/2019
Packet_PInvokeMarshalingRequired = 108,
Packet_ResolveToken = 109,
Packet_ResolveVirtualMethod = 160, // Added 2/13/17
return temp;
}
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
mc->cr->AddCall("mergeClasses");
return temp;
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mc->cr->AddCall("isMoreSpecificType");
+ BOOL temp = original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+ mc->recIsMoreSpecificType(cls1, cls2, temp);
+ return temp;
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
return original_ICorJitInfo->mergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mcs->AddCall("isMoreSpecificType");
+ return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
return original_ICorJitInfo->mergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1.
+BOOL interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return original_ICorJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
return jitInstance->mc->repCompareTypesForEquality(cls1, cls2);
}
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE MyICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
jitInstance->mc->cr->AddCall("mergeClasses");
return jitInstance->mc->repMergeClasses(cls1, cls2);
}
+// Returns true if cls2 is known to be a more specific type than cls1
+BOOL MyICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ jitInstance->mc->cr->AddCall("isMoreSpecificType");
+ return jitInstance->mc->repIsMoreSpecificType(cls1, cls2);
+}
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
#define SELECTANY extern __declspec(selectany)
#endif
-SELECTANY const GUID JITEEVersionIdentifier = { /* 8903fe7b-a82a-4e2e-b691-f58430b485d1 */
- 0x8903fe7b,
- 0xa82a,
- 0x4e2e,
- {0xb6, 0x91, 0xf5, 0x84, 0x30, 0xb4, 0x85, 0xd1}
+SELECTANY const GUID JITEEVersionIdentifier = { /* d609bed1-7831-49fc-bd49-b6f054dd4d46 */
+ 0xd609bed1,
+ 0x7831,
+ 0x49fc,
+ {0xbd, 0x49, 0xb6, 0xf0, 0x54, 0xdd, 0x4d, 0x46}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
CORINFO_CLASS_HANDLE cls2
) = 0;
- // returns is the intersection of cls1 and cls2.
+ // Returns the intersection of cls1 and cls2.
virtual CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2
) = 0;
+ // Returns true if cls2 is known to be a more specific type
+ // than cls1 (a subtype or more restrictive shared type)
+ // for purposes of jit type tracking. This is a hint to the
+ // jit for optimization; it does not have correctness
+ // implications.
+ virtual BOOL isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ ) = 0;
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
// updating exact classes.
if (!varDsc->lvClassIsExact && isNewClass)
{
- // Todo: improve this analysis by adding a new jit interface method
- DWORD newAttrs = info.compCompHnd->getClassAttribs(clsHnd);
- DWORD oldAttrs = info.compCompHnd->getClassAttribs(varDsc->lvClassHnd);
-
- // Avoid funny things with __Canon by only merging if both shared or both unshared
- if ((newAttrs & CORINFO_FLG_SHAREDINST) == (oldAttrs & CORINFO_FLG_SHAREDINST))
- {
- // If we merge types and we get back the old class, the new class is more
- // specific and we should update to it.
- CORINFO_CLASS_HANDLE mergeClass = info.compCompHnd->mergeClasses(clsHnd, varDsc->lvClassHnd);
-
- if (mergeClass == varDsc->lvClassHnd)
- {
- shouldUpdate = true;
- }
- }
- else if ((newAttrs & CORINFO_FLG_SHAREDINST) == 0)
- {
- // Update if we go from shared to unshared
- shouldUpdate = true;
- }
+ shouldUpdate = info.compCompHnd->isMoreSpecificType(varDsc->lvClassHnd, clsHnd);
}
// Else are we attempting to update exactness?
else if (isExact && !varDsc->lvClassIsExact && !isNewClass)
if (isNewClass || (isExact != varDsc->lvClassIsExact))
{
JITDUMP("\nlvaUpdateClass:%s Updating class for V%02u", shouldUpdate ? "" : " NOT", varNum);
- JITDUMP(" from(%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
+ JITDUMP(" from (%p) %s%s", dspPtr(varDsc->lvClassHnd), info.compCompHnd->getClassName(varDsc->lvClassHnd),
varDsc->lvClassIsExact ? " [exact]" : "");
- JITDUMP(" to(%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
+ JITDUMP(" to (%p) %s%s\n", dspPtr(clsHnd), info.compCompHnd->getClassName(clsHnd), isExact ? " [exact]" : "");
}
#endif // DEBUG
}
/*********************************************************************/
-// returns is the intersection of cls1 and cls2.
+// returns the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2)
}
/*********************************************************************/
+static BOOL isMoreSpecificTypeHelper(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ TypeHandle hnd1 = TypeHandle(cls1);
+ TypeHandle hnd2 = TypeHandle(cls2);
+
+ // We can't really reason about equivalent types. Just
+ // assume the new type is not more specific.
+ if (hnd1.HasTypeEquivalence() || hnd2.HasTypeEquivalence())
+ {
+ return FALSE;
+ }
+
+ // If we have a mixture of shared and unshared types,
+ // consider the unshared type as more specific.
+ BOOL isHnd1CanonSubtype = hnd1.IsCanonicalSubtype();
+ BOOL isHnd2CanonSubtype = hnd2.IsCanonicalSubtype();
+ if (isHnd1CanonSubtype != isHnd2CanonSubtype)
+ {
+ // Only one of hnd1 and hnd2 is shared.
+ // hdn2 is more specific if hnd1 is the shared type.
+ return isHnd1CanonSubtype;
+ }
+
+ // Otherwise both types are either shared or not shared.
+ // Look for a common parent type.
+ TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(hnd1, hnd2);
+
+ // If the common parent is hnd1, then hnd2 is more specific.
+ return merged == hnd1;
+}
+
+// Returns true if cls2 is known to be a more specific type
+// than cls1 (a subtype or more restrictive shared type).
+BOOL CEEInfo::isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ BOOL result = FALSE;
+
+ JIT_TO_EE_TRANSITION();
+
+ result = isMoreSpecificTypeHelper(cls1, cls2);
+
+ EE_TO_JIT_TRANSITION();
+ return result;
+}
+
+/*********************************************************************/
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
CORINFO_CLASS_HANDLE cls2
);
+ // Returns true if cls2 is known to be a more specific type
+ // than cls1 (a subtype or more restrictive shared type).
+ BOOL isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ );
+
// Given a class handle, returns the Parent type.
// For COMObjectType, it returns Class Handle of System.Object.
// Returns 0 if System.Object is passed in.
return m_pEEJitInfo->mergeClasses(cls1, cls2);
}
+BOOL ZapInfo::isMoreSpecificType(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ return m_pEEJitInfo->isMoreSpecificType(cls1, cls2);
+}
+
BOOL ZapInfo::shouldEnforceCallvirtRestriction(
CORINFO_MODULE_HANDLE scopeHnd)
{
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2);
+ BOOL isMoreSpecificType(CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2);
+
BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope);
CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls);
CorInfoType getChildType (CORINFO_CLASS_HANDLE clsHnd,
--- /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 System;
+using System.Runtime.InteropServices;
+
+// Test case where a type-equvalent delegate is assigned
+
+class X
+{
+ static int F() => 3;
+
+ public static int Main()
+ {
+ XD x = F;
+ XD y = Lib.GetDelegate();
+ return x() + y() + 64;
+ }
+
+}
--- /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>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <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>
+ <!-- Test unsupported outside of windows (type equivalence) -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="GitHub_22583.cs" />
+ <ProjectReference Include="lib.csproj" />
+ <ProjectReference Include="base.csproj">
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
\ No newline at end of file
--- /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 System;
+using System.Runtime.InteropServices;
+
+[assembly:Guid("a95d54f0-5e7c-46e0-a15f-59ab08d41c38")]
+[assembly:ImportedFromTypeLib("test")]
+
+public delegate int XD();
--- /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>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <GenerateRunScript>false</GenerateRunScript>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="base.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
\ No newline at end of file
--- /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 System;
+
+public class Lib
+{
+ public static int F() => 33;
+
+ public static XD GetDelegate() => F;
+}
--- /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>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Library</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>
+ <GenerateRunScript>false</GenerateRunScript>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="lib.cs" />
+ <ProjectReference Include="base.csproj">
+ <EmbedInteropTypes>True</EmbedInteropTypes>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
\ No newline at end of file