Environment.FailFast("Unable to create comparer");
}
- return RuntimeAugments.NewObject(comparerType);
+ return RuntimeAugments.RawNewObject(comparerType);
}
// This one is an intrinsic that is used to make enum comparisons more efficient.
Environment.FailFast("Unable to create comparer");
}
- return RuntimeAugments.NewObject(comparerType);
+ return RuntimeAugments.RawNewObject(comparerType);
}
//-----------------------------------------------------------------------
//==============================================================================================
// Access to the underlying execution engine's object allocation routines.
//==============================================================================================
- public abstract object NewObject(RuntimeTypeHandle typeHandle);
public abstract Array NewArray(RuntimeTypeHandle typeHandleForArrayType, int count);
public abstract Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArrayType, int[] lengths, int[] lowerBounds);
System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
return result;
}
+
+ [DebuggerGuidedStepThrough]
+ public object CreateInstance(object?[] arguments, Binder? binder, BindingFlags invokeAttr, CultureInfo? cultureInfo)
+ {
+ BinderBundle binderBundle = binder.ToBinderBundle(invokeAttr, cultureInfo);
+ bool wrapInTargetInvocationException = (invokeAttr & BindingFlags.DoNotWrapExceptions) == 0;
+ object result = CreateInstance(arguments, binderBundle, wrapInTargetInvocationException);
+ System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
+ return result;
+ }
+
protected abstract object? Invoke(object? thisObject, object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException);
+ protected abstract object CreateInstance(object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException);
public abstract Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen);
// This property is used to retrieve the target method pointer. It is used by the RuntimeMethodHandle.GetFunctionPointer API
//==============================================================================================
//
- // Perform the equivalent of a "newobj", but without invoking any constructors. Other than the MethodTable, the result object is zero-initialized.
- //
- // Special cases:
- //
- // Strings: The .ctor performs both the construction and initialization
- // and compiler special cases these.
- //
- // Nullable<T>: the boxed result is the underlying type rather than Nullable so the constructor
- // cannot truly initialize it.
- //
- // In these cases, this helper returns "null" and ConstructorInfo.Invoke() must deal with these specially.
- //
- public static object NewObject(RuntimeTypeHandle typeHandle)
- {
- EETypePtr eeType = typeHandle.ToEETypePtr();
- if (eeType.IsNullable
- || eeType == EETypePtr.EETypePtrOf<string>()
- )
- return null;
- if (eeType.IsByRefLike)
- throw new System.Reflection.TargetException();
- return RuntimeImports.RhNewObject(eeType);
- }
-
- //
// Helper API to perform the equivalent of a "newobj" for any MethodTable.
- // Unlike the NewObject API, this is the raw version that does not special case any MethodTable, and should be used with
+ // This is the raw version that does not special case any MethodTable, and should be used with
// caution for very specific scenarios.
//
public static object RawNewObject(RuntimeTypeHandle typeHandle)
if (constructor == null)
{
if (type.IsValueType)
- return RuntimeAugments.NewObject(type.TypeHandle);
+ {
+ RuntimeTypeHandle typeHandle = type.TypeHandle;
+
+ if (RuntimeAugments.IsNullable(typeHandle))
+ return null;
+
+ return RuntimeAugments.RawNewObject(typeHandle);
+ }
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, type));
}
if (matches.Count == 0)
{
if (numArgs == 0 && type.IsValueType)
- return RuntimeAugments.NewObject(type.TypeHandle);
+ {
+ RuntimeTypeHandle typeHandle = type.TypeHandle;
+
+ if (RuntimeAugments.IsNullable(typeHandle))
+ return null;
+
+ return RuntimeAugments.RawNewObject(typeHandle);
+ }
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, type));
}
return result;
}
+ protected sealed override object CreateInstance(object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+ {
+ // Custom method invokers need to also create the instance, so we just pass a null this.
+ Debug.Assert((_options & InvokerOptions.AllowNullThis) != 0);
+ return Invoke(null, arguments, binderBundle, wrapInTargetInvocationException);
+ }
+
public sealed override Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen)
{
if (_thisType.IsConstructedGenericType && _thisType.GetGenericTypeDefinition() == typeof(Nullable<>))
throw new InvalidOperationException(SR.Arg_UnboundGenParam);
}
+ protected sealed override object CreateInstance(object?[]? arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+ {
+ throw new InvalidOperationException(SR.Arg_UnboundGenParam);
+ }
+
public sealed override Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen)
{
throw new InvalidOperationException(SR.Arg_UnboundGenParam);
[DebuggerGuidedStepThrough]
public sealed override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
{
- // Most objects are allocated by NewObject and their constructors return "void". But in many frameworks,
- // there are "weird" cases (e.g. String) where the constructor must do both the allocation and initialization.
- // Reflection.Core does not hardcode these special cases. It's up to the ExecutionEnvironment to steer
- // us the right way by coordinating the implementation of NewObject and MethodInvoker.
- object newObject = ReflectionCoreExecution.ExecutionEnvironment.NewObject(this.DeclaringType.TypeHandle);
- object ctorAllocatedObject = this.MethodInvoker.Invoke(newObject, parameters, binder, invokeAttr, culture)!;
+ object ctorAllocatedObject = this.MethodInvoker.CreateInstance(parameters, binder, invokeAttr, culture);
System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
- return newObject ?? ctorAllocatedObject;
+ return ctorAllocatedObject;
}
public sealed override MethodBase MetadataDefinitionMethod
//==========================================================================================================
internal sealed partial class ExecutionEnvironmentImplementation : ExecutionEnvironment
{
- public sealed override object NewObject(RuntimeTypeHandle typeHandle)
- {
- return RuntimeAugments.NewObject(typeHandle);
- }
-
public sealed override Array NewArray(RuntimeTypeHandle typeHandleForArrayType, int count)
{
return RuntimeAugments.NewArray(typeHandleForArrayType, count);
using global::System;
using global::System.Threading;
using global::System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using global::System.Diagnostics;
using global::System.Collections.Generic;
//
// Implements Invoke() for non-virtual instance methods.
//
- internal sealed class InstanceMethodInvoker : MethodInvokerWithMethodInvokeInfo
+ internal sealed unsafe class InstanceMethodInvoker : MethodInvokerWithMethodInvokeInfo
{
public InstanceMethodInvoker(MethodInvokeInfo methodInvokeInfo, RuntimeTypeHandle declaringTypeHandle)
: base(methodInvokeInfo)
{
_declaringTypeHandle = declaringTypeHandle;
+
+ if (methodInvokeInfo.Method.IsConstructor && !methodInvokeInfo.Method.IsStatic)
+ {
+ if (RuntimeAugments.IsByRefLike(declaringTypeHandle))
+ {
+ _allocatorMethod = &ThrowTargetException;
+ }
+ else
+ {
+ _allocatorMethod = (delegate*<nint, object>)RuntimeAugments.GetAllocateObjectHelperForType(declaringTypeHandle);
+ }
+ }
+ }
+
+ private static object ThrowTargetException(IntPtr _)
+ {
+ throw new TargetException();
}
[DebuggerGuidedStepThroughAttribute]
return result;
}
+ [DebuggerGuidedStepThroughAttribute]
+ protected sealed override object CreateInstance(object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+ {
+ object thisObject = RawCalliHelper.Call<object>(_allocatorMethod, _declaringTypeHandle.Value);
+ MethodInvokeInfo.Invoke(
+ thisObject,
+ MethodInvokeInfo.LdFtnResult,
+ arguments,
+ binderBundle,
+ wrapInTargetInvocationException);
+ System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode();
+ return thisObject;
+ }
+
public sealed override Delegate CreateDelegate(RuntimeTypeHandle delegateType, object target, bool isStatic, bool isVirtual, bool isOpen)
{
if (isOpen)
public sealed override IntPtr LdFtnResult => MethodInvokeInfo.LdFtnResult;
private RuntimeTypeHandle _declaringTypeHandle;
+ private delegate*<nint, object> _allocatorMethod;
+
+ private static class RawCalliHelper
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T Call<T>(delegate*<IntPtr, T> pfn, IntPtr arg)
+ => pfn(arg);
+ }
}
}
return result;
}
+ protected sealed override object CreateInstance(object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+ {
+ throw NotImplemented.ByDesign;
+ }
+
public sealed override IntPtr LdFtnResult => MethodInvokeInfo.LdFtnResult;
}
}
return result;
}
+ protected sealed override object CreateInstance(object[] arguments, BinderBundle binderBundle, bool wrapInTargetInvocationException)
+ {
+ throw NotImplemented.ByDesign;
+ }
+
internal IntPtr ResolveTarget(RuntimeTypeHandle type)
{
return OpenMethodResolver.ResolveMethod(MethodInvokeInfo.VirtualResolveData, type);
if (state.GcDataSize != 0)
{
// Statics are allocated on GC heap
- object obj = RuntimeAugments.NewObject(((MethodTable*)state.GcStaticDesc)->ToRuntimeTypeHandle());
+ object obj = RuntimeAugments.RawNewObject(((MethodTable*)state.GcStaticDesc)->ToRuntimeTypeHandle());
gcStaticData = RuntimeAugments.RhHandleAlloc(obj, GCHandleType.Normal);
pEEType->DynamicGcStaticsData = gcStaticData;