Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dadhi/3d2b3b74809832d45d571d219fbc603a to your computer and use it in GitHub Desktop.
Save dadhi/3d2b3b74809832d45d571d219fbc603a to your computer and use it in GitHub Desktop.
Optimize ILGenerator.Emit(OpCodes.Newobj, ctor)
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