用 Reflector 发现这个类 (System.Internal) 发现里面有这么三个静态方法:
CommonlyUsedGenericInstantiations_HACK
NullableHelper_HACK<T>
SZArrayHelper_HACK<T>
它们的名字很奇怪, 方法里的内容更奇怪, 比如 CommonlyUsedGenericInstantiations_HACK 里的代码是:
这是看上去完全没有意义的代码啊... 而且其中调用 SZArrayHelper_HACK<T> 的地方传进去的参数是 null, 必然会抛出异常的:
不解的我Google之, 只搜到一篇相关的文章, 作者觉得这和JIT的编译效率有关, 和我的猜想也差不多, 但是没有任何地方调用它的方法啊.. 何况调用它还有抛出异常..
该不会是VM调用了它?
于是我想到了传说中的 SSCLI(Shared Source CLI, 就是共享源代码的CLI实现, 涵盖了.Net Framework (CLR, BCL, Compiler 的核心源代码)) ...
找到 System.Internal 类的源文件, 里面赫然写道:
看完它的注释, 虽然不是太懂 (IBC是什么?), 但也大概有个答案了:
这个类存在的意义是为了让这些一般的泛型类型的 Native Code 能在 Native Image 中存在 (我们都知道安装.Net Framework的时候, 像 Mscorlib.dll 这样的程序集已经安装到了 GAC 中了), 避免了 JIT 在运行时进行编译 (生成泛型类型的 Native Code)而造成的效率损失.
注释中还提到, 下一个版本的 .Net CLR(4.0? 3.0? 谁知道呢..) 将不会有这个 Trick.. 开发人员将会使用另外一种泛型的实现方案.
关于 .Net 2.0 中的泛型在运行时是如何编译的, 可以参考 Introducing Generics in the CLR
CommonlyUsedGenericInstantiations_HACK
NullableHelper_HACK<T>
SZArrayHelper_HACK<T>
它们的名字很奇怪, 方法里的内容更奇怪, 比如 CommonlyUsedGenericInstantiations_HACK 里的代码是:
private static void CommonlyUsedGenericInstantiations_HACK()
{
new ArraySegment<byte>(new byte[1], 0, 0);
new Dictionary<char, object>();
new Dictionary<short, IntPtr>();
new Dictionary<int, byte>();
new Dictionary<int, int>();
new Dictionary<int, object>();
new Dictionary<IntPtr, short>();
new Dictionary<object, char>();
new Dictionary<object, Guid>();
new Dictionary<object, int>();
NullableHelper_HACK<bool>();
NullableHelper_HACK<byte>();
NullableHelper_HACK<char>();
NullableHelper_HACK<DateTime>();
NullableHelper_HACK<decimal>();
NullableHelper_HACK<double>();
NullableHelper_HACK<Guid>();
NullableHelper_HACK<short>();
NullableHelper_HACK<int>();
NullableHelper_HACK<long>();
NullableHelper_HACK<float>();
NullableHelper_HACK<TimeSpan>();
new List<bool>();
new List<byte>();
new List<DateTime>();
new List<decimal>();
new List<double>();
new List<Guid>();
new List<short>();
new List<int>();
new List<long>();
new List<TimeSpan>();
new List<sbyte>();
new List<float>();
new List<ushort>();
new List<uint>();
new List<ulong>();
new List<KeyValuePair<object, object>>();
RuntimeType.RuntimeTypeCache.Prejitinit_HACK();
new CerArrayList<RuntimeMethodInfo>(0);
new CerArrayList<RuntimeConstructorInfo>(0);
new CerArrayList<RuntimePropertyInfo>(0);
new CerArrayList<RuntimeEventInfo>(0);
new CerArrayList<RuntimeFieldInfo>(0);
new CerArrayList<RuntimeType>(0);
new KeyValuePair<char, ushort>('\0', 0);
new KeyValuePair<ushort, double>(0, double.MinValue);
SZArrayHelper_HACK<bool>(null);
SZArrayHelper_HACK<byte>(null);
SZArrayHelper_HACK<DateTime>(null);
SZArrayHelper_HACK<decimal>(null);
SZArrayHelper_HACK<double>(null);
SZArrayHelper_HACK<Guid>(null);
SZArrayHelper_HACK<short>(null);
SZArrayHelper_HACK<int>(null);
SZArrayHelper_HACK<long>(null);
SZArrayHelper_HACK<TimeSpan>(null);
SZArrayHelper_HACK<sbyte>(null);
SZArrayHelper_HACK<float>(null);
SZArrayHelper_HACK<ushort>(null);
SZArrayHelper_HACK<uint>(null);
SZArrayHelper_HACK<ulong>(null);
SZArrayHelper_HACK<CustomAttributeTypedArgument>(null);
SZArrayHelper_HACK<CustomAttributeNamedArgument>(null);
}
{
new ArraySegment<byte>(new byte[1], 0, 0);
new Dictionary<char, object>();
new Dictionary<short, IntPtr>();
new Dictionary<int, byte>();
new Dictionary<int, int>();
new Dictionary<int, object>();
new Dictionary<IntPtr, short>();
new Dictionary<object, char>();
new Dictionary<object, Guid>();
new Dictionary<object, int>();
NullableHelper_HACK<bool>();
NullableHelper_HACK<byte>();
NullableHelper_HACK<char>();
NullableHelper_HACK<DateTime>();
NullableHelper_HACK<decimal>();
NullableHelper_HACK<double>();
NullableHelper_HACK<Guid>();
NullableHelper_HACK<short>();
NullableHelper_HACK<int>();
NullableHelper_HACK<long>();
NullableHelper_HACK<float>();
NullableHelper_HACK<TimeSpan>();
new List<bool>();
new List<byte>();
new List<DateTime>();
new List<decimal>();
new List<double>();
new List<Guid>();
new List<short>();
new List<int>();
new List<long>();
new List<TimeSpan>();
new List<sbyte>();
new List<float>();
new List<ushort>();
new List<uint>();
new List<ulong>();
new List<KeyValuePair<object, object>>();
RuntimeType.RuntimeTypeCache.Prejitinit_HACK();
new CerArrayList<RuntimeMethodInfo>(0);
new CerArrayList<RuntimeConstructorInfo>(0);
new CerArrayList<RuntimePropertyInfo>(0);
new CerArrayList<RuntimeEventInfo>(0);
new CerArrayList<RuntimeFieldInfo>(0);
new CerArrayList<RuntimeType>(0);
new KeyValuePair<char, ushort>('\0', 0);
new KeyValuePair<ushort, double>(0, double.MinValue);
SZArrayHelper_HACK<bool>(null);
SZArrayHelper_HACK<byte>(null);
SZArrayHelper_HACK<DateTime>(null);
SZArrayHelper_HACK<decimal>(null);
SZArrayHelper_HACK<double>(null);
SZArrayHelper_HACK<Guid>(null);
SZArrayHelper_HACK<short>(null);
SZArrayHelper_HACK<int>(null);
SZArrayHelper_HACK<long>(null);
SZArrayHelper_HACK<TimeSpan>(null);
SZArrayHelper_HACK<sbyte>(null);
SZArrayHelper_HACK<float>(null);
SZArrayHelper_HACK<ushort>(null);
SZArrayHelper_HACK<uint>(null);
SZArrayHelper_HACK<ulong>(null);
SZArrayHelper_HACK<CustomAttributeTypedArgument>(null);
SZArrayHelper_HACK<CustomAttributeNamedArgument>(null);
}
这是看上去完全没有意义的代码啊... 而且其中调用 SZArrayHelper_HACK<T> 的地方传进去的参数是 null, 必然会抛出异常的:
private static void SZArrayHelper_HACK<T>(SZArrayHelper oSZArrayHelper)
{
oSZArrayHelper.get_Count<T>();
oSZArrayHelper.get_Item<T>(0);
oSZArrayHelper.GetEnumerator<T>();
}
{
oSZArrayHelper.get_Count<T>();
oSZArrayHelper.get_Item<T>(0);
oSZArrayHelper.GetEnumerator<T>();
}
不解的我Google之, 只搜到一篇相关的文章, 作者觉得这和JIT的编译效率有关, 和我的猜想也差不多, 但是没有任何地方调用它的方法啊.. 何况调用它还有抛出异常..
该不会是VM调用了它?
于是我想到了传说中的 SSCLI(Shared Source CLI, 就是共享源代码的CLI实现, 涵盖了.Net Framework (CLR, BCL, Compiler 的核心源代码)) ...
找到 System.Internal 类的源文件, 里面赫然写道:
// ==++==
//
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
/*============================================================
**
** This file exists to contain miscellaneous module-level attributes
** and other miscellaneous stuff.
**
**
**
===========================================================*/
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Reflection;
[assembly:DefaultDependencyAttribute(LoadHint.Always)]
// mscorlib would like to have its literal strings frozen if possible
[assembly: System.Runtime.CompilerServices.StringFreezingAttribute()]
namespace System
{
static class Internal
{
// This method is purely an aid for NGen to statically deduce which
// instantiations to save in the ngen image.
// Otherwise, the JIT-compiler gets used, which is bad for working-set.
// Note that IBC can provide this information too.
// However, this helps in keeping the JIT-compiler out even for
// test scenarios which do not use IBC.
// This can be removed after V2, when we implement other schemes
// of keeping the JIT-compiler out for generic instantiations.
static void CommonlyUsedGenericInstantiations_HACK()
{
// Make absolutely sure we include some of the most common
// instantiations here in mscorlib's ngen image.
// Note that reference type instantiations are already included
// automatically for us.
new ArraySegment<byte>(new byte[1], 0, 0);
new Dictionary<Char, Object>();
................
SZArrayHelper_HACK<UInt64>(null);
SZArrayHelper_HACK<CustomAttributeTypedArgument>(null);
SZArrayHelper_HACK<CustomAttributeNamedArgument>(null);
}
static T NullableHelper_HACK<T>() where T : struct
{
Nullable.Compare<T>(null, null);
Nullable.Equals<T>(null, null);
Nullable<T> nullable = new Nullable<T>();
return nullable.GetValueOrDefault();
}
static void SZArrayHelper_HACK<T>(SZArrayHelper oSZArrayHelper)
{
// Instantiate common methods for IList implementation on Array
oSZArrayHelper.get_Count<T>();
oSZArrayHelper.get_Item<T>(0);
oSZArrayHelper.GetEnumerator<T>();
}
}
}
//
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
/*============================================================
**
** This file exists to contain miscellaneous module-level attributes
** and other miscellaneous stuff.
**
**
**
===========================================================*/
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Reflection;
[assembly:DefaultDependencyAttribute(LoadHint.Always)]
// mscorlib would like to have its literal strings frozen if possible
[assembly: System.Runtime.CompilerServices.StringFreezingAttribute()]
namespace System
{
static class Internal
{
// This method is purely an aid for NGen to statically deduce which
// instantiations to save in the ngen image.
// Otherwise, the JIT-compiler gets used, which is bad for working-set.
// Note that IBC can provide this information too.
// However, this helps in keeping the JIT-compiler out even for
// test scenarios which do not use IBC.
// This can be removed after V2, when we implement other schemes
// of keeping the JIT-compiler out for generic instantiations.
static void CommonlyUsedGenericInstantiations_HACK()
{
// Make absolutely sure we include some of the most common
// instantiations here in mscorlib's ngen image.
// Note that reference type instantiations are already included
// automatically for us.
new ArraySegment<byte>(new byte[1], 0, 0);
new Dictionary<Char, Object>();
................
SZArrayHelper_HACK<UInt64>(null);
SZArrayHelper_HACK<CustomAttributeTypedArgument>(null);
SZArrayHelper_HACK<CustomAttributeNamedArgument>(null);
}
static T NullableHelper_HACK<T>() where T : struct
{
Nullable.Compare<T>(null, null);
Nullable.Equals<T>(null, null);
Nullable<T> nullable = new Nullable<T>();
return nullable.GetValueOrDefault();
}
static void SZArrayHelper_HACK<T>(SZArrayHelper oSZArrayHelper)
{
// Instantiate common methods for IList implementation on Array
oSZArrayHelper.get_Count<T>();
oSZArrayHelper.get_Item<T>(0);
oSZArrayHelper.GetEnumerator<T>();
}
}
}
看完它的注释, 虽然不是太懂 (IBC是什么?), 但也大概有个答案了:
这个类存在的意义是为了让这些一般的泛型类型的 Native Code 能在 Native Image 中存在 (我们都知道安装.Net Framework的时候, 像 Mscorlib.dll 这样的程序集已经安装到了 GAC 中了), 避免了 JIT 在运行时进行编译 (生成泛型类型的 Native Code)而造成的效率损失.
注释中还提到, 下一个版本的 .Net CLR(4.0? 3.0? 谁知道呢..) 将不会有这个 Trick.. 开发人员将会使用另外一种泛型的实现方案.
关于 .Net 2.0 中的泛型在运行时是如何编译的, 可以参考 Introducing Generics in the CLR