Created
July 26, 2022 11:33
-
-
Save dadhi/3d2b3b74809832d45d571d219fbc603a to your computer and use it in GitHub Desktop.
Optimize ILGenerator.Emit(OpCodes.Newobj, ctor)
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
using System; | |
using System.Reflection.Emit; | |
using System.Diagnostics; | |
public class Program | |
{ | |
public static void Main() | |
{ | |
var con = typeof(B<int>).GetConstructors()[0]; | |
/* | |
public static readonly OpCode Newobj = new OpCode(OpCodeValues.Newobj, | |
((int)OperandType.InlineMethod) | | |
((int)FlowControl.Call << OpCode.FlowControlShift) | | |
((int)OpCodeType.Objmodel << OpCode.OpCodeTypeShift) | | |
((int)StackBehaviour.Varpop << OpCode.StackBehaviourPopShift) | | |
((int)StackBehaviour.Pushref << OpCode.StackBehaviourPushShift) | | |
(1 << OpCode.SizeShift) | | |
(1 << OpCode.StackChangeShift) | |
); | |
*/ | |
Console.WriteLine("Newobj.StackBehaviourPush: " + OpCodes.Newobj.StackBehaviourPush); | |
Console.WriteLine("Newobj.StackBehaviourPop: " + OpCodes.Newobj.StackBehaviourPop); | |
var ps = con.GetParameters(); | |
Console.WriteLine("Parameters count: " + ps.Length); | |
// Start from public `virtual void Emit(OpCode opcode, ConstructorInfo con)` | |
// Call to `private int GetMethodToken(MethodBase method, Type[]? optionalParameterTypes, bool useMethodDef)` | |
// as `int tk = GetMethodToken(con, null, true);` | |
// the full code: | |
/* | |
int stackexchange = 0; | |
int tk = GetMethodToken(con, null, true); // @perf most work is here!!! | |
EnsureCapacity(7); | |
Debug.Assert(opcode.StackBehaviourPop == StackBehaviour.Varpop) | |
Type[] parameters = con.GetParameterTypes(); // @perf allocation here!!! we know hoy many parameters already | |
if (parameters != null) | |
stackchange -= parameters.Length; | |
InternalEmit(opcode); | |
UpdateStackSize(opcode, stackexchange); | |
RecordTokenFixup(); | |
PutInteger4(tk); | |
*/ | |
// Call to `internal int GetMethodTokenInternal(MethodBase method, Type[]? optionalParameterTypes, bool useMethodDef)` | |
Console.WriteLine(con.IsGenericMethod); // ctors are not generic | |
Console.WriteLine(con.CallingConvention); // normally are CallingConvention.Standard | CallingConvention.HasThis | |
Console.WriteLine(con.DeclaringType.IsGenericType); | |
// <Then for generic class> | |
// Call for `private int GetMemberRefToken(MethodBase method, Type[]? optionalParameterTypes)` | |
// as `tk = GetMemberRefToken(method, optionalParameterTypes);` | |
// (for non-generic call to `internal int GetConstructorToken(ConstructorInfo con)`) // todo: @per @wip to check - it goes deep | |
// Call for `private static MethodBase GetGenericMethodBaseDefinition(MethodBase methodBase)` | |
var ctorDef = con.Module.ResolveMethod(con.MetadataToken, con.DeclaringType.GetGenericArguments(), null); | |
// Next is the call to `internal SignatureHelper GetMemberRefSignature(MethodBase? method, int cGenericParameters)` | |
// as `GetMemberRefSignature(ctorDef, 0)` where cGenericParameters are for method own generic parameters | |
// here its code | |
/* | |
Debug.Assert(con is RuntimeConstructorInfo); | |
ParameterInfo[] parameters = method.GetParametersNoCopy(); // @perf again, maaan | |
Type[] parameterTypes = new Type[parameters.Length]; | |
Type[][] requiredCustomModifiers = new Type[parameterTypes.Length][]; // @perf usually there is nothing here | |
Type[][] optionalCustomModifiers = new Type[parameterTypes.Length][]; // @perf usually there is nothing here | |
for (int i = 0; i < parameters.Length; i++) | |
{ | |
parameterTypes[i] = parameters[i].ParameterType; | |
requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers(); | |
optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers(); | |
} | |
ParameterInfo? returnParameter = method is MethodInfo mi ? mi.ReturnParameter : null; | |
SignatureHelper sigHelp = SignatureHelper.GetMethodSigHelper(this, method.CallingConvention, cGenericParameters, returnParameter?.ParameterType, returnParameter?.GetRequiredCustomModifiers(), returnParameter?.GetOptionalCustomModifiers(), parameterTypes, requiredCustomModifiers, optionalCustomModifiers); | |
return sigHelp; | |
*/ | |
for (int i = 0; i < ps.Length; i++) | |
{ | |
//var pType = ps[i].ParameterType; | |
Console.WriteLine("parameter GetRequiredCustomModifiers(): " + ps[i].GetRequiredCustomModifiers().Length); | |
Console.WriteLine("parameter GetOptionalCustomModifiers(): " + ps[i].GetOptionalCustomModifiers().Length); | |
} | |
// Now calling | |
// internal static SignatureHelper GetMethodSigHelper( | |
// Module? scope, CallingConventions callingConvention, int cGenericParam, | |
// Type? returnType, Type[]? requiredReturnTypeCustomModifiers, Type[]? optionalReturnTypeCustomModifiers, | |
// Type[]? parameterTypes, Type[][]? requiredParameterTypeCustomModifiers, Type[][]? optionalParameterTypeCustomModifiers) | |
// as | |
// GetMethodSigHelper(scope = this/*m_moduleBuilder*/, con.CallingConvention, cGenericParam = 0, returnType = typeof(void), requiredParameterTypeCustomModifiers = null, | |
// parameterTypes, requiredParameterTypeCustomModifiers = null, optionalParameterTypeCustomModifiers = null) | |
// Then we calling `byte[] sigBytes = sigHelp.InternalGetSignature(out int sigLength);` | |
// Then.. for generic class | |
// byte[] sig = SignatureHelper.GetTypeSigToken(this, method.DeclaringType).InternalGetSignature(out int length); | |
// tkParent = GetTokenFromTypeSpec(sig, length); // not optimizable | |
// And.. | |
// return GetMemberRefFromSignature(tkParent, method.Name, sigBytes, sigLength); | |
// AND this is our token `tk` | |
// </Then for generic class> | |
Console.WriteLine(ctorDef); | |
} | |
public class B<T> | |
{ | |
public B(params T[] ts) {} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment