-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Eliminates ObjectFactory<T> except when caller explicitly wants a Func<T> - Uses C# 9.0 function pointers to avoid introducing new JIT intrinsics
- Loading branch information
1 parent
e18250b
commit d0bde83
Showing
17 changed files
with
696 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
src/coreclr/src/System.Private.CoreLib/src/System/Reflection/ObjectFactory.CoreCLR.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// 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.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
using Internal.Runtime.CompilerServices; | ||
|
||
namespace System.Reflection | ||
{ | ||
// Creates initialized instances of reference types or of value types. | ||
// For reference types, calls the parameterless ctor. | ||
// For value types, calls the parameterless ctor if it exists; otherwise | ||
// return a boxed default(T). Must not be used with Nullable<T>. | ||
internal unsafe sealed class ObjectFactory : UninitializedObjectFactory | ||
{ | ||
private readonly void* _pfnCtor; | ||
private readonly bool _isNonPublicCtor; | ||
|
||
// Creates a factory from an existing parameterless ctor | ||
internal ObjectFactory(RuntimeMethodHandleInternal hCtor) | ||
: base(RuntimeMethodHandle.GetDeclaringType(hCtor)) | ||
{ | ||
_pfnCtor = (void*)RuntimeMethodHandle.GetFunctionPointer(hCtor); | ||
Debug.Assert(_pfnCtor != null); | ||
|
||
_isNonPublicCtor = (RuntimeMethodHandle.GetAttributes(hCtor) & MethodAttributes.MemberAccessMask) != MethodAttributes.Public; | ||
} | ||
|
||
private ObjectFactory(RuntimeType type) | ||
: base(type) | ||
{ | ||
Debug.Assert(_pMT->IsValueType); | ||
_isNonPublicCtor = false; // default(T) is always "public" | ||
} | ||
|
||
// Creates a factory for "box(default(T))" around a value type | ||
internal static ObjectFactory CreateFactoryForValueTypeDefaultOfT(RuntimeType type) | ||
{ | ||
return new ObjectFactory(type); | ||
} | ||
|
||
public bool IsNonPublicCtor => _isNonPublicCtor; | ||
|
||
public object CreateInstance() | ||
{ | ||
object newObj = CreateUninitializedInstance(); | ||
|
||
if (!_pMT->IsValueType) | ||
{ | ||
// Common case: we're creating a reference type | ||
((delegate*<object, void>)_pfnCtor)(newObj); | ||
} | ||
else | ||
{ | ||
// Less common case: we're creating a boxed value type | ||
// If an explicit parameterless ctor exists, call it now. | ||
if (_pfnCtor != null) | ||
{ | ||
((delegate*<ref byte, void>)_pfnCtor)(ref newObj.GetRawData()); | ||
} | ||
} | ||
|
||
return newObj; | ||
} | ||
} | ||
|
||
// Similar to ObjectFactory, but does not box value types 'T'. | ||
internal unsafe sealed class ObjectFactory<T> : UninitializedObjectFactory | ||
{ | ||
private readonly void* _pfnCtor; | ||
|
||
internal ObjectFactory() | ||
: base((RuntimeType)typeof(T)) | ||
{ | ||
RuntimeType type = (RuntimeType)typeof(T); | ||
|
||
// It's ok if there's no default constructor on a value type. | ||
// We'll return default(T). For reference types, the constructor | ||
// must be present. In all cases, if a constructor is present, it | ||
// must be public. | ||
|
||
RuntimeMethodHandleInternal hCtor = RuntimeMethodHandleInternal.EmptyHandle; | ||
if (_pMT->HasDefaultConstructor) | ||
{ | ||
hCtor = RuntimeTypeHandle.GetDefaultConstructor(type); | ||
Debug.Assert(!hCtor.IsNullHandle()); | ||
if ((RuntimeMethodHandle.GetAttributes(hCtor) & MethodAttributes.MemberAccessMask) != MethodAttributes.Public) | ||
{ | ||
// parameterless ctor exists but is not public | ||
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, type)); | ||
} | ||
|
||
_pfnCtor = (void*)RuntimeMethodHandle.GetFunctionPointer(hCtor); | ||
} | ||
else | ||
{ | ||
if (!_pMT->IsValueType) | ||
{ | ||
// parameterless ctor missing on reference type | ||
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, type)); | ||
} | ||
} | ||
} | ||
|
||
public T CreateInstance() | ||
{ | ||
if (typeof(T).IsValueType) | ||
{ | ||
T value = default!; | ||
if (_pfnCtor != null) | ||
{ | ||
((delegate*<ref T, void>)_pfnCtor)(ref value); | ||
} | ||
return value; | ||
} | ||
else | ||
{ | ||
object value = CreateUninitializedInstance(); | ||
Debug.Assert(_pfnCtor != null); | ||
((delegate*<object, void>)_pfnCtor)(value!); | ||
return Unsafe.As<object, T>(ref value); | ||
} | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...lr/src/System.Private.CoreLib/src/System/Reflection/UninitializedObjectFactory.CoreCLR.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// 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.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace System.Reflection | ||
{ | ||
// Creates zero-initialized instances of types. | ||
// For reference types, equivalent of allocating memory without running ctor. | ||
// For value types, equivalent of boxing default(T). | ||
// Must not be used with Nullable<T>. | ||
internal unsafe class UninitializedObjectFactory | ||
{ | ||
protected readonly MethodTable* _pMT; | ||
private readonly delegate*<MethodTable*, object> _pfnAllocate; | ||
private readonly RuntimeType _type; | ||
|
||
internal UninitializedObjectFactory(RuntimeType type) | ||
{ | ||
Debug.Assert(type != null); | ||
Debug.Assert(RuntimeHelpers.IsFastInstantiable(type)); | ||
|
||
_type = type; | ||
_pMT = RuntimeTypeHandle.GetMethodTable(type); | ||
_pfnAllocate = RuntimeHelpers.GetNewobjHelper(type); | ||
|
||
Debug.Assert(_pMT != null); | ||
Debug.Assert(!_pMT->IsNullable); | ||
Debug.Assert(_pfnAllocate != null); | ||
} | ||
|
||
public object CreateUninitializedInstance() | ||
{ | ||
// If a GC kicks in between the time we load the newobj | ||
// helper address and the time we calli it, we don't want | ||
// the Type object to be eligible for collection. To avoid | ||
// this, we KeepAlive(this) - and the referenced Type - | ||
// until we have an instance of the object. From that point | ||
// onward, the object itself will keep the Type alive. | ||
|
||
object newObj = _pfnAllocate(_pMT); | ||
GC.KeepAlive(this); | ||
return newObj; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.