// 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. // namespace System.Reflection.Emit { using System; using System.Globalization; using System.Diagnostics.SymbolStore; using System.Runtime.InteropServices; using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Security.Permissions; using System.Threading; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Security; internal class DynamicILGenerator : ILGenerator { internal DynamicScope m_scope; private int m_methodSigToken; internal unsafe DynamicILGenerator(DynamicMethod method, byte[] methodSignature, int size) : base(method, size) { m_scope = new DynamicScope(); m_methodSigToken = m_scope.GetTokenFor(methodSignature); } internal void GetCallableMethod(RuntimeModule module, DynamicMethod dm) { dm.m_methodHandle = ModuleHandle.GetDynamicMethod(dm, module, m_methodBuilder.Name, (byte[])m_scope[m_methodSigToken], new DynamicResolver(this)); } #if FEATURE_APPX private bool ProfileAPICheck { get { return ((DynamicMethod)m_methodBuilder).ProfileAPICheck; } } #endif // FEATURE_APPX // *** ILGenerator api *** public override LocalBuilder DeclareLocal(Type localType, bool pinned) { LocalBuilder localBuilder; if (localType == null) throw new ArgumentNullException(nameof(localType)); Contract.EndContractBlock(); RuntimeType rtType = localType as RuntimeType; if (rtType == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType")); #if FEATURE_APPX if (ProfileAPICheck && (rtType.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtType.FullName)); #endif localBuilder = new LocalBuilder(m_localCount, localType, m_methodBuilder); // add the localType to local signature m_localSignature.AddArgument(localType, pinned); m_localCount++; return localBuilder; } // // // Token resolution calls // // public override void Emit(OpCode opcode, MethodInfo meth) { if (meth == null) throw new ArgumentNullException(nameof(meth)); Contract.EndContractBlock(); int stackchange = 0; int token = 0; DynamicMethod dynMeth = meth as DynamicMethod; if (dynMeth == null) { RuntimeMethodInfo rtMeth = meth as RuntimeMethodInfo; if (rtMeth == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), nameof(meth)); RuntimeType declaringType = rtMeth.GetRuntimeType(); if (declaringType != null && (declaringType.IsGenericType || declaringType.IsArray)) token = GetTokenFor(rtMeth, declaringType); else token = GetTokenFor(rtMeth); } else { // rule out not allowed operations on DynamicMethods if (opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn) || opcode.Equals(OpCodes.Ldvirtftn)) { throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOpCodeOnDynamicMethod")); } token = GetTokenFor(dynMeth); } EnsureCapacity(7); InternalEmit(opcode); if (opcode.StackBehaviourPush == StackBehaviour.Varpush && meth.ReturnType != typeof(void)) { stackchange++; } if (opcode.StackBehaviourPop == StackBehaviour.Varpop) { stackchange -= meth.GetParametersNoCopy().Length; } // Pop the "this" parameter if the method is non-static, // and the instruction is not newobj/ldtoken/ldftn. if (!meth.IsStatic && !(opcode.Equals(OpCodes.Newobj) || opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn))) { stackchange--; } UpdateStackSize(opcode, stackchange); PutInteger4(token); } [System.Runtime.InteropServices.ComVisible(true)] public override void Emit(OpCode opcode, ConstructorInfo con) { if (con == null) throw new ArgumentNullException(nameof(con)); Contract.EndContractBlock(); RuntimeConstructorInfo rtConstructor = con as RuntimeConstructorInfo; if (rtConstructor == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), nameof(con)); RuntimeType declaringType = rtConstructor.GetRuntimeType(); int token; if (declaringType != null && (declaringType.IsGenericType || declaringType.IsArray)) // need to sort out the stack size story token = GetTokenFor(rtConstructor, declaringType); else token = GetTokenFor(rtConstructor); EnsureCapacity(7); InternalEmit(opcode); // need to sort out the stack size story UpdateStackSize(opcode, 1); PutInteger4(token); } public override void Emit(OpCode opcode, Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); Contract.EndContractBlock(); RuntimeType rtType = type as RuntimeType; if (rtType == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType")); int token = GetTokenFor(rtType); EnsureCapacity(7); InternalEmit(opcode); PutInteger4(token); } public override void Emit(OpCode opcode, FieldInfo field) { if (field == null) throw new ArgumentNullException(nameof(field)); Contract.EndContractBlock(); RuntimeFieldInfo runtimeField = field as RuntimeFieldInfo; if (runtimeField == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeFieldInfo"), nameof(field)); int token; if (field.DeclaringType == null) token = GetTokenFor(runtimeField); else token = GetTokenFor(runtimeField, runtimeField.GetRuntimeType()); EnsureCapacity(7); InternalEmit(opcode); PutInteger4(token); } public override void Emit(OpCode opcode, String str) { if (str == null) throw new ArgumentNullException(nameof(str)); Contract.EndContractBlock(); int tempVal = GetTokenForString(str); EnsureCapacity(7); InternalEmit(opcode); PutInteger4(tempVal); } // // // Signature related calls (vararg, calli) // // public override void EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes) { int stackchange = 0; SignatureHelper sig; if (optionalParameterTypes != null) if ((callingConvention & CallingConventions.VarArgs) == 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention")); sig = GetMemberRefSignature(callingConvention, returnType, parameterTypes, optionalParameterTypes); EnsureCapacity(7); Emit(OpCodes.Calli); // If there is a non-void return type, push one. if (returnType != typeof(void)) stackchange++; // Pop off arguments if any. if (parameterTypes != null) stackchange -= parameterTypes.Length; // Pop off vararg arguments. if (optionalParameterTypes != null) stackchange -= optionalParameterTypes.Length; // Pop the this parameter if the method has a this parameter. if ((callingConvention & CallingConventions.HasThis) == CallingConventions.HasThis) stackchange--; // Pop the native function pointer. stackchange--; UpdateStackSize(OpCodes.Calli, stackchange); int token = GetTokenForSig(sig.GetSignature(true)); PutInteger4(token); } public override void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes) { int stackchange = 0; int cParams = 0; int i; SignatureHelper sig; if (parameterTypes != null) cParams = parameterTypes.Length; sig = SignatureHelper.GetMethodSigHelper(unmanagedCallConv, returnType); if (parameterTypes != null) for (i = 0; i < cParams; i++) sig.AddArgument(parameterTypes[i]); // If there is a non-void return type, push one. if (returnType != typeof(void)) stackchange++; // Pop off arguments if any. if (parameterTypes != null) stackchange -= cParams; // Pop the native function pointer. stackchange--; UpdateStackSize(OpCodes.Calli, stackchange); EnsureCapacity(7); Emit(OpCodes.Calli); int token = GetTokenForSig(sig.GetSignature(true)); PutInteger4(token); } public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes) { if (methodInfo == null) throw new ArgumentNullException(nameof(methodInfo)); if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))) throw new ArgumentException(Environment.GetResourceString("Argument_NotMethodCallOpcode"), nameof(opcode)); if (methodInfo.ContainsGenericParameters) throw new ArgumentException(Environment.GetResourceString("Argument_GenericsInvalid"), nameof(methodInfo)); if (methodInfo.DeclaringType != null && methodInfo.DeclaringType.ContainsGenericParameters) throw new ArgumentException(Environment.GetResourceString("Argument_GenericsInvalid"), nameof(methodInfo)); Contract.EndContractBlock(); int tk; int stackchange = 0; tk = GetMemberRefToken(methodInfo, optionalParameterTypes); EnsureCapacity(7); InternalEmit(opcode); // Push the return value if there is one. if (methodInfo.ReturnType != typeof(void)) stackchange++; // Pop the parameters. stackchange -= methodInfo.GetParameterTypes().Length; // Pop the this parameter if the method is non-static and the // instruction is not newobj. if (!(methodInfo is SymbolMethod) && methodInfo.IsStatic == false && !(opcode.Equals(OpCodes.Newobj))) stackchange--; // Pop the optional parameters off the stack. if (optionalParameterTypes != null) stackchange -= optionalParameterTypes.Length; UpdateStackSize(opcode, stackchange); PutInteger4(tk); } public override void Emit(OpCode opcode, SignatureHelper signature) { if (signature == null) throw new ArgumentNullException(nameof(signature)); Contract.EndContractBlock(); int stackchange = 0; EnsureCapacity(7); InternalEmit(opcode); // The only IL instruction that has VarPop behaviour, that takes a // Signature token as a parameter is calli. Pop the parameters and // the native function pointer. To be conservative, do not pop the // this pointer since this information is not easily derived from // SignatureHelper. if (opcode.StackBehaviourPop == StackBehaviour.Varpop) { Debug.Assert(opcode.Equals(OpCodes.Calli), "Unexpected opcode encountered for StackBehaviour VarPop."); // Pop the arguments.. stackchange -= signature.ArgumentCount; // Pop native function pointer off the stack. stackchange--; UpdateStackSize(opcode, stackchange); } int token = GetTokenForSig(signature.GetSignature(true)); ; PutInteger4(token); } // // // Exception related generation // // public override Label BeginExceptionBlock() { return base.BeginExceptionBlock(); } public override void EndExceptionBlock() { base.EndExceptionBlock(); } public override void BeginExceptFilterBlock() { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } public override void BeginCatchBlock(Type exceptionType) { if (CurrExcStackCount == 0) throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock")); Contract.EndContractBlock(); __ExceptionInfo current = CurrExcStack[CurrExcStackCount - 1]; RuntimeType rtType = exceptionType as RuntimeType; if (current.GetCurrentState() == __ExceptionInfo.State_Filter) { if (exceptionType != null) { throw new ArgumentException(Environment.GetResourceString("Argument_ShouldNotSpecifyExceptionType")); } this.Emit(OpCodes.Endfilter); } else { // execute this branch if previous clause is Catch or Fault if (exceptionType == null) throw new ArgumentNullException(nameof(exceptionType)); if (rtType == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType")); Label endLabel = current.GetEndLabel(); this.Emit(OpCodes.Leave, endLabel); // if this is a catch block the exception will be pushed on the stack and we need to update the stack info UpdateStackSize(OpCodes.Nop, 1); } current.MarkCatchAddr(ILOffset, exceptionType); // this is relying on too much implementation details of the base and so it's highly breaking // Need to have a more integreted story for exceptions current.m_filterAddr[current.m_currentCatch - 1] = GetTokenFor(rtType); } public override void BeginFaultBlock() { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } public override void BeginFinallyBlock() { base.BeginFinallyBlock(); } // // // debugger related calls. // // [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. public override void UsingNamespace(String ns) { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. public override void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn) { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } public override void BeginScope() { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } public override void EndScope() { throw new NotSupportedException(Environment.GetResourceString("InvalidOperation_NotAllowedInDynamicMethod")); } private int GetMemberRefToken(MethodBase methodInfo, Type[] optionalParameterTypes) { Type[] parameterTypes; if (optionalParameterTypes != null && (methodInfo.CallingConvention & CallingConventions.VarArgs) == 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention")); RuntimeMethodInfo rtMeth = methodInfo as RuntimeMethodInfo; DynamicMethod dm = methodInfo as DynamicMethod; if (rtMeth == null && dm == null) throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeMethodInfo"), nameof(methodInfo)); ParameterInfo[] paramInfo = methodInfo.GetParametersNoCopy(); if (paramInfo != null && paramInfo.Length != 0) { parameterTypes = new Type[paramInfo.Length]; for (int i = 0; i < paramInfo.Length; i++) parameterTypes[i] = paramInfo[i].ParameterType; } else { parameterTypes = null; } SignatureHelper sig = GetMemberRefSignature(methodInfo.CallingConvention, MethodBuilder.GetMethodBaseReturnType(methodInfo), parameterTypes, optionalParameterTypes); if (rtMeth != null) return GetTokenForVarArgMethod(rtMeth, sig); else return GetTokenForVarArgMethod(dm, sig); } internal override SignatureHelper GetMemberRefSignature( CallingConventions call, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes) { int cParams; int i; SignatureHelper sig; if (parameterTypes == null) cParams = 0; else cParams = parameterTypes.Length; sig = SignatureHelper.GetMethodSigHelper(call, returnType); for (i = 0; i < cParams; i++) sig.AddArgument(parameterTypes[i]); if (optionalParameterTypes != null && optionalParameterTypes.Length != 0) { // add the sentinel sig.AddSentinel(); for (i = 0; i < optionalParameterTypes.Length; i++) sig.AddArgument(optionalParameterTypes[i]); } return sig; } internal override void RecordTokenFixup() { // DynamicMethod doesn't need fixup. } #region GetTokenFor helpers private int GetTokenFor(RuntimeType rtType) { #if FEATURE_APPX if (ProfileAPICheck && (rtType.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtType.FullName)); #endif return m_scope.GetTokenFor(rtType.TypeHandle); } private int GetTokenFor(RuntimeFieldInfo runtimeField) { #if FEATURE_APPX if (ProfileAPICheck) { RtFieldInfo rtField = runtimeField as RtFieldInfo; if (rtField != null && (rtField.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtField.FullName)); } #endif return m_scope.GetTokenFor(runtimeField.FieldHandle); } private int GetTokenFor(RuntimeFieldInfo runtimeField, RuntimeType rtType) { #if FEATURE_APPX if (ProfileAPICheck) { RtFieldInfo rtField = runtimeField as RtFieldInfo; if (rtField != null && (rtField.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtField.FullName)); if ((rtType.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtType.FullName)); } #endif return m_scope.GetTokenFor(runtimeField.FieldHandle, rtType.TypeHandle); } private int GetTokenFor(RuntimeConstructorInfo rtMeth) { #if FEATURE_APPX if (ProfileAPICheck && (rtMeth.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtMeth.FullName)); #endif return m_scope.GetTokenFor(rtMeth.MethodHandle); } private int GetTokenFor(RuntimeConstructorInfo rtMeth, RuntimeType rtType) { #if FEATURE_APPX if (ProfileAPICheck) { if ((rtMeth.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtMeth.FullName)); if ((rtType.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtType.FullName)); } #endif return m_scope.GetTokenFor(rtMeth.MethodHandle, rtType.TypeHandle); } private int GetTokenFor(RuntimeMethodInfo rtMeth) { #if FEATURE_APPX if (ProfileAPICheck && (rtMeth.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtMeth.FullName)); #endif return m_scope.GetTokenFor(rtMeth.MethodHandle); } private int GetTokenFor(RuntimeMethodInfo rtMeth, RuntimeType rtType) { #if FEATURE_APPX if (ProfileAPICheck) { if ((rtMeth.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtMeth.FullName)); if ((rtType.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtType.FullName)); } #endif return m_scope.GetTokenFor(rtMeth.MethodHandle, rtType.TypeHandle); } private int GetTokenFor(DynamicMethod dm) { return m_scope.GetTokenFor(dm); } private int GetTokenForVarArgMethod(RuntimeMethodInfo rtMeth, SignatureHelper sig) { #if FEATURE_APPX if (ProfileAPICheck && (rtMeth.InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", rtMeth.FullName)); #endif VarArgMethod varArgMeth = new VarArgMethod(rtMeth, sig); return m_scope.GetTokenFor(varArgMeth); } private int GetTokenForVarArgMethod(DynamicMethod dm, SignatureHelper sig) { VarArgMethod varArgMeth = new VarArgMethod(dm, sig); return m_scope.GetTokenFor(varArgMeth); } private int GetTokenForString(String s) { return m_scope.GetTokenFor(s); } private int GetTokenForSig(byte[] sig) { return m_scope.GetTokenFor(sig); } #endregion } internal class DynamicResolver : Resolver { #region Private Data Members private __ExceptionInfo[] m_exceptions; private byte[] m_exceptionHeader; private DynamicMethod m_method; private byte[] m_code; private byte[] m_localSignature; private int m_stackSize; private DynamicScope m_scope; #endregion #region Internal Methods internal DynamicResolver(DynamicILGenerator ilGenerator) { m_stackSize = ilGenerator.GetMaxStackSize(); m_exceptions = ilGenerator.GetExceptions(); m_code = ilGenerator.BakeByteArray(); m_localSignature = ilGenerator.m_localSignature.InternalGetSignatureArray(); m_scope = ilGenerator.m_scope; m_method = (DynamicMethod)ilGenerator.m_methodBuilder; m_method.m_resolver = this; } internal DynamicResolver(DynamicILInfo dynamicILInfo) { m_stackSize = dynamicILInfo.MaxStackSize; m_code = dynamicILInfo.Code; m_localSignature = dynamicILInfo.LocalSignature; m_exceptionHeader = dynamicILInfo.Exceptions; //m_exceptions = dynamicILInfo.Exceptions; m_scope = dynamicILInfo.DynamicScope; m_method = dynamicILInfo.DynamicMethod; m_method.m_resolver = this; } // // We can destroy the unmanaged part of dynamic method only after the managed part is definitely gone and thus // nobody can call the dynamic method anymore. A call to finalizer alone does not guarantee that the managed // part is gone. A malicious code can keep a reference to DynamicMethod in long weak reference that survives finalization, // or we can be running during shutdown where everything is finalized. // // The unmanaged resolver keeps a reference to the managed resolver in long weak handle. If the long weak handle // is null, we can be sure that the managed part of the dynamic method is definitely gone and that it is safe to // destroy the unmanaged part. (Note that the managed finalizer has to be on the same object that the long weak handle // points to in order for this to work.) Unfortunately, we can not perform the above check when out finalizer // is called - the long weak handle won't be cleared yet. Instead, we create a helper scout object that will attempt // to do the destruction after next GC. // // The finalization does not have to be done using CriticalFinalizerObject. We have to go over all DynamicMethodDescs // during AppDomain shutdown anyway to avoid leaks e.g. if somebody stores reference to DynamicMethod in static. // ~DynamicResolver() { DynamicMethod method = m_method; if (method == null) return; if (method.m_methodHandle == null) return; DestroyScout scout = null; try { scout = new DestroyScout(); } catch { // We go over all DynamicMethodDesc during AppDomain shutdown and make sure // that everything associated with them is released. So it is ok to skip reregistration // for finalization during appdomain shutdown if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload()) { // Try again later. GC.ReRegisterForFinalize(this); } return; } // We can never ever have two active destroy scouts for the same method. We need to initialize the scout // outside the try/reregister block to avoid possibility of reregistration for finalization with active scout. scout.m_methodHandle = method.m_methodHandle.Value; } private class DestroyScout { internal RuntimeMethodHandleInternal m_methodHandle; ~DestroyScout() { if (m_methodHandle.IsNullHandle()) return; // It is not safe to destroy the method if the managed resolver is alive. if (RuntimeMethodHandle.GetResolver(m_methodHandle) != null) { if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload()) { // Somebody might have been holding a reference on us via weak handle. // We will keep trying. It will be hopefully released eventually. GC.ReRegisterForFinalize(this); } return; } RuntimeMethodHandle.Destroy(m_methodHandle); } } // Keep in sync with vm/dynamicmethod.h [Flags] internal enum SecurityControlFlags { Default = 0x0, SkipVisibilityChecks = 0x1, RestrictedSkipVisibilityChecks = 0x2, HasCreationContext = 0x4, CanSkipCSEvaluation = 0x8, } internal override RuntimeType GetJitContext(ref int securityControlFlags) { RuntimeType typeOwner; SecurityControlFlags flags = SecurityControlFlags.Default; if (m_method.m_restrictedSkipVisibility) flags |= SecurityControlFlags.RestrictedSkipVisibilityChecks; else if (m_method.m_skipVisibility) flags |= SecurityControlFlags.SkipVisibilityChecks; typeOwner = m_method.m_typeOwner; #if FEATURE_COMPRESSEDSTACK if (m_method.m_creationContext != null) { flags |= SecurityControlFlags.HasCreationContext; if(m_method.m_creationContext.CanSkipEvaluation) { flags |= SecurityControlFlags.CanSkipCSEvaluation; } } #endif // FEATURE_COMPRESSEDSTACK securityControlFlags = (int)flags; return typeOwner; } private static int CalculateNumberOfExceptions(__ExceptionInfo[] excp) { int num = 0; if (excp == null) return 0; for (int i = 0; i < excp.Length; i++) num += excp[i].GetNumberOfCatches(); return num; } internal override byte[] GetCodeInfo( ref int stackSize, ref int initLocals, ref int EHCount) { stackSize = m_stackSize; if (m_exceptionHeader != null && m_exceptionHeader.Length != 0) { if (m_exceptionHeader.Length < 4) throw new FormatException(); byte header = m_exceptionHeader[0]; if ((header & 0x40) != 0) // Fat { byte[] size = new byte[4]; for (int q = 0; q < 3; q++) size[q] = m_exceptionHeader[q + 1]; EHCount = (BitConverter.ToInt32(size, 0) - 4) / 24; } else EHCount = (m_exceptionHeader[1] - 2) / 12; } else { EHCount = CalculateNumberOfExceptions(m_exceptions); } initLocals = (m_method.InitLocals) ? 1 : 0; return m_code; } internal override byte[] GetLocalsSignature() { return m_localSignature; } internal override unsafe byte[] GetRawEHInfo() { return m_exceptionHeader; } internal override unsafe void GetEHInfo(int excNumber, void* exc) { CORINFO_EH_CLAUSE* exception = (CORINFO_EH_CLAUSE*)exc; for (int i = 0; i < m_exceptions.Length; i++) { int excCount = m_exceptions[i].GetNumberOfCatches(); if (excNumber < excCount) { // found the right exception block exception->Flags = m_exceptions[i].GetExceptionTypes()[excNumber]; exception->TryOffset = m_exceptions[i].GetStartAddress(); if ((exception->Flags & __ExceptionInfo.Finally) != __ExceptionInfo.Finally) exception->TryLength = m_exceptions[i].GetEndAddress() - exception->TryOffset; else exception->TryLength = m_exceptions[i].GetFinallyEndAddress() - exception->TryOffset; exception->HandlerOffset = m_exceptions[i].GetCatchAddresses()[excNumber]; exception->HandlerLength = m_exceptions[i].GetCatchEndAddresses()[excNumber] - exception->HandlerOffset; // this is cheating because the filter address is the token of the class only for light code gen exception->ClassTokenOrFilterOffset = m_exceptions[i].GetFilterAddresses()[excNumber]; break; } excNumber -= excCount; } } internal override String GetStringLiteral(int token) { return m_scope.GetString(token); } #if FEATURE_COMPRESSEDSTACK internal override CompressedStack GetSecurityContext() { return m_method.m_creationContext; } #endif // FEATURE_COMPRESSEDSTACK internal override void ResolveToken(int token, out IntPtr typeHandle, out IntPtr methodHandle, out IntPtr fieldHandle) { typeHandle = new IntPtr(); methodHandle = new IntPtr(); fieldHandle = new IntPtr(); Object handle = m_scope[token]; if (handle == null) throw new InvalidProgramException(); if (handle is RuntimeTypeHandle) { typeHandle = ((RuntimeTypeHandle)handle).Value; return; } if (handle is RuntimeMethodHandle) { methodHandle = ((RuntimeMethodHandle)handle).Value; return; } if (handle is RuntimeFieldHandle) { fieldHandle = ((RuntimeFieldHandle)handle).Value; return; } DynamicMethod dm = handle as DynamicMethod; if (dm != null) { methodHandle = dm.GetMethodDescriptor().Value; return; } GenericMethodInfo gmi = handle as GenericMethodInfo; if (gmi != null) { methodHandle = gmi.m_methodHandle.Value; typeHandle = gmi.m_context.Value; return; } GenericFieldInfo gfi = handle as GenericFieldInfo; if (gfi != null) { fieldHandle = gfi.m_fieldHandle.Value; typeHandle = gfi.m_context.Value; return; } VarArgMethod vaMeth = handle as VarArgMethod; if (vaMeth != null) { if (vaMeth.m_dynamicMethod == null) { methodHandle = vaMeth.m_method.MethodHandle.Value; typeHandle = vaMeth.m_method.GetDeclaringTypeInternal().GetTypeHandleInternal().Value; } else methodHandle = vaMeth.m_dynamicMethod.GetMethodDescriptor().Value; return; } } internal override byte[] ResolveSignature(int token, int fromMethod) { return m_scope.ResolveSignature(token, fromMethod); } internal override MethodInfo GetDynamicMethod() { return m_method.GetMethodInfo(); } #endregion } [System.Runtime.InteropServices.ComVisible(true)] public class DynamicILInfo { #region Private Data Members private DynamicMethod m_method; private DynamicScope m_scope; private byte[] m_exceptions; private byte[] m_code; private byte[] m_localSignature; private int m_maxStackSize; private int m_methodSignature; #endregion #region Constructor internal DynamicILInfo(DynamicScope scope, DynamicMethod method, byte[] methodSignature) { m_method = method; m_scope = scope; m_methodSignature = m_scope.GetTokenFor(methodSignature); m_exceptions = EmptyArray.Value; m_code = EmptyArray.Value; m_localSignature = EmptyArray.Value; } #endregion #region Internal Methods internal void GetCallableMethod(RuntimeModule module, DynamicMethod dm) { dm.m_methodHandle = ModuleHandle.GetDynamicMethod(dm, module, m_method.Name, (byte[])m_scope[m_methodSignature], new DynamicResolver(this)); } internal byte[] LocalSignature { get { if (m_localSignature == null) m_localSignature = SignatureHelper.GetLocalVarSigHelper().InternalGetSignatureArray(); return m_localSignature; } } internal byte[] Exceptions { get { return m_exceptions; } } internal byte[] Code { get { return m_code; } } internal int MaxStackSize { get { return m_maxStackSize; } } #endregion #region Public ILGenerator Methods public DynamicMethod DynamicMethod { get { return m_method; } } internal DynamicScope DynamicScope { get { return m_scope; } } public void SetCode(byte[] code, int maxStackSize) { m_code = (code != null) ? (byte[])code.Clone() : EmptyArray.Value; m_maxStackSize = maxStackSize; } [CLSCompliant(false)] public unsafe void SetCode(byte* code, int codeSize, int maxStackSize) { if (codeSize < 0) throw new ArgumentOutOfRangeException(nameof(codeSize), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive")); if (codeSize > 0 && code == null) throw new ArgumentNullException(nameof(code)); Contract.EndContractBlock(); m_code = new byte[codeSize]; for (int i = 0; i < codeSize; i++) { m_code[i] = *code; code++; } m_maxStackSize = maxStackSize; } public void SetExceptions(byte[] exceptions) { m_exceptions = (exceptions != null) ? (byte[])exceptions.Clone() : EmptyArray.Value; } [CLSCompliant(false)] public unsafe void SetExceptions(byte* exceptions, int exceptionsSize) { if (exceptionsSize < 0) throw new ArgumentOutOfRangeException(nameof(exceptionsSize), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive")); if (exceptionsSize > 0 && exceptions == null) throw new ArgumentNullException(nameof(exceptions)); Contract.EndContractBlock(); m_exceptions = new byte[exceptionsSize]; for (int i = 0; i < exceptionsSize; i++) { m_exceptions[i] = *exceptions; exceptions++; } } public void SetLocalSignature(byte[] localSignature) { m_localSignature = (localSignature != null) ? (byte[])localSignature.Clone() : EmptyArray.Value; } [CLSCompliant(false)] public unsafe void SetLocalSignature(byte* localSignature, int signatureSize) { if (signatureSize < 0) throw new ArgumentOutOfRangeException(nameof(signatureSize), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive")); if (signatureSize > 0 && localSignature == null) throw new ArgumentNullException(nameof(localSignature)); Contract.EndContractBlock(); m_localSignature = new byte[signatureSize]; for (int i = 0; i < signatureSize; i++) { m_localSignature[i] = *localSignature; localSignature++; } } #endregion #region Public Scope Methods public int GetTokenFor(RuntimeMethodHandle method) { return DynamicScope.GetTokenFor(method); } public int GetTokenFor(DynamicMethod method) { return DynamicScope.GetTokenFor(method); } public int GetTokenFor(RuntimeMethodHandle method, RuntimeTypeHandle contextType) { return DynamicScope.GetTokenFor(method, contextType); } public int GetTokenFor(RuntimeFieldHandle field) { return DynamicScope.GetTokenFor(field); } public int GetTokenFor(RuntimeFieldHandle field, RuntimeTypeHandle contextType) { return DynamicScope.GetTokenFor(field, contextType); } public int GetTokenFor(RuntimeTypeHandle type) { return DynamicScope.GetTokenFor(type); } public int GetTokenFor(string literal) { return DynamicScope.GetTokenFor(literal); } public int GetTokenFor(byte[] signature) { return DynamicScope.GetTokenFor(signature); } #endregion } internal class DynamicScope { #region Private Data Members internal List m_tokens; #endregion #region Constructor internal unsafe DynamicScope() { m_tokens = new List(); m_tokens.Add(null); } #endregion #region Internal Methods internal object this[int token] { get { token &= 0x00FFFFFF; if (token < 0 || token > m_tokens.Count) return null; return m_tokens[token]; } } internal int GetTokenFor(VarArgMethod varArgMethod) { m_tokens.Add(varArgMethod); return m_tokens.Count - 1 | (int)MetadataTokenType.MemberRef; } internal string GetString(int token) { return this[token] as string; } internal byte[] ResolveSignature(int token, int fromMethod) { if (fromMethod == 0) return (byte[])this[token]; VarArgMethod vaMethod = this[token] as VarArgMethod; if (vaMethod == null) return null; return vaMethod.m_signature.GetSignature(true); } #endregion #region Public Methods public int GetTokenFor(RuntimeMethodHandle method) { IRuntimeMethodInfo methodReal = method.GetMethodInfo(); RuntimeMethodHandleInternal rmhi = methodReal.Value; if (methodReal != null && !RuntimeMethodHandle.IsDynamicMethod(rmhi)) { RuntimeType type = RuntimeMethodHandle.GetDeclaringType(rmhi); if ((type != null) && RuntimeTypeHandle.HasInstantiation(type)) { // Do we really need to retrieve this much info just to throw an exception? MethodBase m = RuntimeType.GetMethodBase(methodReal); Type t = m.DeclaringType.GetGenericTypeDefinition(); throw new ArgumentException(String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_MethodDeclaringTypeGenericLcg"), m, t)); } } m_tokens.Add(method); return m_tokens.Count - 1 | (int)MetadataTokenType.MethodDef; } public int GetTokenFor(RuntimeMethodHandle method, RuntimeTypeHandle typeContext) { m_tokens.Add(new GenericMethodInfo(method, typeContext)); return m_tokens.Count - 1 | (int)MetadataTokenType.MethodDef; } public int GetTokenFor(DynamicMethod method) { m_tokens.Add(method); return m_tokens.Count - 1 | (int)MetadataTokenType.MethodDef; } public int GetTokenFor(RuntimeFieldHandle field) { m_tokens.Add(field); return m_tokens.Count - 1 | (int)MetadataTokenType.FieldDef; } public int GetTokenFor(RuntimeFieldHandle field, RuntimeTypeHandle typeContext) { m_tokens.Add(new GenericFieldInfo(field, typeContext)); return m_tokens.Count - 1 | (int)MetadataTokenType.FieldDef; } public int GetTokenFor(RuntimeTypeHandle type) { m_tokens.Add(type); return m_tokens.Count - 1 | (int)MetadataTokenType.TypeDef; } public int GetTokenFor(string literal) { m_tokens.Add(literal); return m_tokens.Count - 1 | (int)MetadataTokenType.String; } public int GetTokenFor(byte[] signature) { m_tokens.Add(signature); return m_tokens.Count - 1 | (int)MetadataTokenType.Signature; } #endregion } internal sealed class GenericMethodInfo { internal RuntimeMethodHandle m_methodHandle; internal RuntimeTypeHandle m_context; internal GenericMethodInfo(RuntimeMethodHandle methodHandle, RuntimeTypeHandle context) { m_methodHandle = methodHandle; m_context = context; } } internal sealed class GenericFieldInfo { internal RuntimeFieldHandle m_fieldHandle; internal RuntimeTypeHandle m_context; internal GenericFieldInfo(RuntimeFieldHandle fieldHandle, RuntimeTypeHandle context) { m_fieldHandle = fieldHandle; m_context = context; } } internal sealed class VarArgMethod { internal RuntimeMethodInfo m_method; internal DynamicMethod m_dynamicMethod; internal SignatureHelper m_signature; internal VarArgMethod(DynamicMethod dm, SignatureHelper signature) { m_dynamicMethod = dm; m_signature = signature; } internal VarArgMethod(RuntimeMethodInfo method, SignatureHelper signature) { m_method = method; m_signature = signature; } } }