public void Emit(ILGenerator il, int offset, ExceptionHandlingClauseData clause) { if (offset == clause.TryOffset) { il.BeginExceptionBlock(); } if (offset == clause.HandlerOffset) { switch (clause.Flags) { case ExceptionHandlingClauseOptions.Finally: il.BeginFinallyBlock(); break; case ExceptionHandlingClauseOptions.Fault: il.BeginFaultBlock(); break; case ExceptionHandlingClauseOptions.Clause: il.BeginCatchBlock(typeResolver.GetType(clause.CatchType)); break; default: throw new DelegateDeserializationException(string.Format("Unknown clause {0}", clause.Flags)); } } if (offset == clause.HandlerOffset + clause.HandlerLength) { il.EndExceptionBlock(); } }
public FaultBlock FaultBlock() { if (hasCatchBlocks) { throw new InvalidOperationException("Exception block already has catch blocks - cannot use both catch and fault block"); } if (hasFaultBlock) { throw new InvalidOperationException("Exception block already has fault block"); } if (hasFinallyBlock) { throw new InvalidOperationException( "Exception block already has a finally block - cannot have both fault and finally - try nesting this exception block in another that has its own fault block"); } EnsureTryBlockEnded(); hasFaultBlock = true; generator.BeginFaultBlock(); return(new FaultBlock()); }
// internal static void Proceed(MethodBuilder method, ILGenerator ILGen) { var @ret = ILGen.DefineLabel(); var @endTry = ILGen.DefineLabel(); //.try var @try = ILGen.BeginExceptionBlock(); ILGen.Emit(OpCodes.Ldstr, "Body"); ILGen.Emit(OpCodes.Call, mInfo_WriteLine); ILGen.Emit(OpCodes.Ldarg_1); ILGen.Emit(OpCodes.Brfalse_S, @endTry); ILGen.Emit(OpCodes.Newobj, cInfo_Exception); ILGen.Emit(OpCodes.Throw); ILGen.MarkLabel(@endTry); ILGen.Emit(OpCodes.Leave_S, @ret); //.end try //.fault ILGen.BeginFaultBlock(); ILGen.Emit(OpCodes.Ldstr, "Fault"); ILGen.Emit(OpCodes.Call, mInfo_WriteLine); ILGen.EndExceptionBlock(); //.end fault ILGen.MarkLabel(@ret); ILGen.Emit(OpCodes.Ret); }
public static void MarkBlockBefore(ILGenerator il, ExceptionBlock block, out Label?label) { label = null; switch (block.blockType) { case ExceptionBlockType.BeginExceptionBlock: label = il.BeginExceptionBlock(); return; case ExceptionBlockType.BeginCatchBlock: il.BeginCatchBlock(block.catchType); return; case ExceptionBlockType.BeginExceptFilterBlock: il.BeginExceptFilterBlock(); return; case ExceptionBlockType.BeginFaultBlock: il.BeginFaultBlock(); return; case ExceptionBlockType.BeginFinallyBlock: il.BeginFinallyBlock(); return; } }
public IFluentILGenerator BeginFaultBlock() { _logger?.LogMeta("fault"); _logger?.LogMeta("{"); _generator.BeginFaultBlock(); return(this); }
internal void BeginFaultBlock() { _ilg.BeginFaultBlock(); AdvanceOffsetWithLabel(OpCodes.Leave); _exceptionState.Pop(); _exceptionState.Push(ExceptionState.Fault); AssertOffsetMatches(); }
public void ValidFilterBlock1() { DefineBasicMethod(); ILGenerator il = il_gen; il.BeginExceptionBlock(); il.BeginExceptFilterBlock(); il.BeginFaultBlock(); il.EndExceptionBlock(); }
private void HandleException(IOperation op) { bool ignore; uint offset = op.Offset; if (offsetsUsedInExceptionInformation.TryGetValue(offset, out ignore)) { foreach (var exceptionInfo in this.methodBody.OperationExceptionInformation) { if (offset == exceptionInfo.TryStartOffset) { generator.BeginTryBody(); } // Never need to do anthing when offset == exceptionInfo.TryEndOffset because // we pick up an EndTryBody from the HandlerEndOffset below // generator.EndTryBody(); if (offset == exceptionInfo.HandlerStartOffset) { switch (exceptionInfo.HandlerKind) { case HandlerKind.Catch: generator.BeginCatchBlock(exceptionInfo.ExceptionType); break; case HandlerKind.Fault: generator.BeginFaultBlock(); break; case HandlerKind.Filter: generator.BeginFilterBody(); break; case HandlerKind.Finally: generator.BeginFinallyBlock(); break; } } if (exceptionInfo.HandlerKind == HandlerKind.Filter && offset == exceptionInfo.FilterDecisionStartOffset) { generator.BeginFilterBlock(); } if (offset == exceptionInfo.HandlerEndOffset) { generator.EndTryBody(); } } } }
public void PosTest6() { MethodBuilder method = TestTypeBuilder.DefineMethod("PosTest6_Method", DefaultMethodAttribute); ILGenerator generator = method.GetILGenerator(); LocalBuilder arg = generator.DeclareLocal(typeof(int)); generator.BeginExceptionBlock(); generator.Emit(OpCodes.Throw, arg); generator.BeginFaultBlock(); generator.Emit(OpCodes.Ldnull, arg); generator.Emit(OpCodes.Ldarg_0, arg); generator.Emit(OpCodes.Nop, arg); // Try emit opcode which takes multiple args generator.Emit(OpCodes.Add, arg); }
public void PosTest6() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic); MethodBuilder method = type.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static); ILGenerator generator = method.GetILGenerator(); LocalBuilder arg = generator.DeclareLocal(typeof(int)); generator.BeginExceptionBlock(); generator.Emit(OpCodes.Throw, arg); generator.BeginFaultBlock(); generator.Emit(OpCodes.Ldnull, arg); generator.Emit(OpCodes.Ldarg_0, arg); generator.Emit(OpCodes.Nop, arg); // Try emit opcode which takes multiple args generator.Emit(OpCodes.Add, arg); }
private void MarkExceptionHandlers(ExceptionHandlerCollection exceptionHandlers) { foreach (ExceptionHandler exceptionHandler in exceptionHandlers) { AddActionAfter(exceptionHandler.TryStart, delegate { generator.BeginExceptionBlock(); }); if (exceptionHandler.Type == ExceptionHandlerType.Filter) { AddActionAfter(exceptionHandler.FilterStart, delegate { generator.BeginExceptFilterBlock(); }); } AddActionAfter(exceptionHandler.HandlerStart, delegate { switch (exceptionHandler.Type) { case ExceptionHandlerType.Catch: generator.BeginCatchBlock(outer.ResolveType(exceptionHandler.CatchType)); break; case ExceptionHandlerType.Fault: generator.BeginFaultBlock(); break; case ExceptionHandlerType.Finally: generator.BeginFinallyBlock(); break; } }); AddActionBefore(exceptionHandler.HandlerEnd, delegate { generator.EndExceptionBlock(); }); } }
#pragma warning restore protected virtual void MarkExceptionBlock(ILGenerator il, ExceptionBlockInfo info) { ExceptionBlockType btype = info.blockType; if ((btype & ExceptionBlockType.End) != 0) { il.EndExceptionBlock(); } else // begin { switch (btype & flagValue) { case ExceptionBlockType.BigBlock: il.BeginExceptionBlock(); return; case ExceptionBlockType.FilterBlock: il.BeginExceptFilterBlock(); return; case ExceptionBlockType.FinallyBlock: il.BeginFinallyBlock(); return; case ExceptionBlockType.CatchBlock: il.BeginCatchBlock(info.catchType); return; case ExceptionBlockType.FaultBlock: il.BeginFaultBlock(); return; default: #if DEBUG System.Diagnostics.Debug.WriteLine($"[ERROR] {btype}"); #endif return; } } }
internal void MarkBlockBefore(ExceptionBlock block, out Label?label) { label = null; switch (block.blockType) { case ExceptionBlockType.BeginExceptionBlock: if (debug) { FileLog.LogBuffered(".try"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } label = il.BeginExceptionBlock(); return; case ExceptionBlockType.BeginCatchBlock: if (debug) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(OpCodes.Leave, new LeaveTry(), true); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered($".catch {block.catchType}"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginCatchBlock(block.catchType); return; case ExceptionBlockType.BeginExceptFilterBlock: if (debug) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(OpCodes.Leave, new LeaveTry(), true); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".filter"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginExceptFilterBlock(); return; case ExceptionBlockType.BeginFaultBlock: if (debug) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(OpCodes.Leave, new LeaveTry(), true); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".fault"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFaultBlock(); return; case ExceptionBlockType.BeginFinallyBlock: if (debug) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(OpCodes.Leave, new LeaveTry(), true); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".finally"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFinallyBlock(); return; } }
public virtual void BeginFaultBlock() { il.BeginFaultBlock(); }
internal static void MarkBlockBefore(ILGenerator il, ExceptionBlock block, out Label?label) { label = null; switch (block.blockType) { case ExceptionBlockType.BeginExceptionBlock: if (HarmonyInstance.DEBUG) { FileLog.LogBuffered(".try"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } label = il.BeginExceptionBlock(); return; case ExceptionBlockType.BeginCatchBlock: if (HarmonyInstance.DEBUG) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(il, OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".catch " + block.catchType); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginCatchBlock(block.catchType); return; case ExceptionBlockType.BeginExceptFilterBlock: if (HarmonyInstance.DEBUG) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(il, OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".filter"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginExceptFilterBlock(); return; case ExceptionBlockType.BeginFaultBlock: if (HarmonyInstance.DEBUG) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(il, OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".fault"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFaultBlock(); return; case ExceptionBlockType.BeginFinallyBlock: if (HarmonyInstance.DEBUG) { // fake log a LEAVE code since BeginCatchBlock() does add it LogIL(il, OpCodes.Leave, new LeaveTry()); FileLog.ChangeIndent(-1); FileLog.LogBuffered("} // end try"); FileLog.LogBuffered(".finally"); FileLog.LogBuffered("{"); FileLog.ChangeIndent(1); } il.BeginFinallyBlock(); return; } }
public void BeginFaultBlock() => generator.BeginFaultBlock();
public DynamicMethod Generate() { MethodDefinition def = Definition; // Fix up any mistakes which might accidentally pop up. def.ConvertShortLongOps(); Type[] genericArgsType = Method.DeclaringType.GetTypeInfo().IsGenericType ? Method.DeclaringType.GetGenericArguments() : null; Type[] genericArgsMethod = Method.IsGenericMethod ? Method.GetGenericArguments() : null; ParameterInfo[] args = Method.GetParameters(); Type[] argTypes; if (!Method.IsStatic) { argTypes = new Type[args.Length + 1]; argTypes[0] = Method.GetThisParamType(); for (int i = 0; i < args.Length; i++) { argTypes[i + 1] = args[i].ParameterType; } } else { argTypes = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { argTypes[i] = args[i].ParameterType; } } DynamicMethod dm = new DynamicMethod( $"DynamicMethodDefinition<{Method}>", (Method as MethodInfo)?.ReturnType ?? typeof(void), argTypes, Method.DeclaringType, true // If any random errors pop up, try setting this to false first. ); ILGenerator il = dm.GetILGenerator(); LocalBuilder[] locals = def.Body.Variables.Select( var => il.DeclareLocal(var.VariableType.ResolveReflection(), var.IsPinned) ).ToArray(); // Pre-pass - Set up label map. Dictionary <int, Label> labelMap = new Dictionary <int, Label>(); foreach (Instruction instr in def.Body.Instructions) { if (instr.Operand is Instruction[] targets) { foreach (Instruction target in targets) { if (!labelMap.ContainsKey(target.Offset)) { labelMap[target.Offset] = il.DefineLabel(); } } } else if (instr.Operand is Instruction target) { if (!labelMap.ContainsKey(target.Offset)) { labelMap[target.Offset] = il.DefineLabel(); } } } object[] emitArgs = new object[2]; foreach (Instruction instr in def.Body.Instructions) { if (labelMap.TryGetValue(instr.Offset, out Label label)) { il.MarkLabel(label); } // TODO: This can be improved perf-wise! foreach (ExceptionHandler handler in def.Body.ExceptionHandlers) { if (handler.TryStart == instr) { il.BeginExceptionBlock(); } else if (handler.FilterStart == instr) { il.BeginExceptFilterBlock(); } else if (handler.HandlerStart == instr) { switch (handler.HandlerType) { case ExceptionHandlerType.Filter: // Handled by FilterStart break; case ExceptionHandlerType.Catch: il.BeginCatchBlock(handler.CatchType.ResolveReflection()); break; case ExceptionHandlerType.Finally: il.BeginFinallyBlock(); break; case ExceptionHandlerType.Fault: il.BeginFaultBlock(); break; } } } if (instr.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone) { il.Emit(_ReflOpCodes[instr.OpCode.Value]); } else { object operand = instr.Operand; if (operand is Instruction[] targets) { operand = targets.Select(target => labelMap[target.Offset]).ToArray(); } else if (operand is Instruction target) { operand = labelMap[target.Offset]; } else if (operand is VariableDefinition var) { operand = locals[var.Index]; } else if (operand is ParameterDefinition param) { operand = param.Index; } else if (operand is MemberReference mref) { operand = mref.ResolveReflection(); } else if (operand is CallSite csite) { // SignatureHelper in unmanaged contexts cannot be fully made use of for DynamicMethods. EmitCallSite(dm, il, _ReflOpCodes[instr.OpCode.Value], csite); continue; } if (operand == null) { throw new NullReferenceException($"Unexpected null in {def} @ {instr}"); } Type operandType = operand.GetType(); if (!_Emitters.TryGetValue(operandType, out MethodInfo emit)) { emit = _Emitters.FirstOrDefault(kvp => kvp.Key.IsAssignableFrom(operandType)).Value; } if (emit == null) { throw new InvalidOperationException($"Unexpected unemittable {operand.GetType().FullName} in {def} @ {instr}"); } emitArgs[0] = _ReflOpCodes[instr.OpCode.Value]; emitArgs[1] = operand; emit.Invoke(il, emitArgs); } // TODO: This can be improved perf-wise! foreach (ExceptionHandler handler in def.Body.ExceptionHandlers) { if (handler.HandlerEnd == instr.Next) { il.EndExceptionBlock(); } } } return(dm); }
private void ProcessOperations(IMethodBody methodBody) { List <IOperation> operations = ((methodBody.Operations == null) ? new List <IOperation>(): new List <IOperation>(methodBody.Operations)); int count = operations.Count; ILGenerator generator = new ILGenerator(this.host, methodBody.MethodDefinition); if (this.pdbReader != null) { foreach (var ns in this.pdbReader.GetNamespaceScopes(methodBody)) { foreach (var uns in ns.UsedNamespaces) { generator.UseNamespace(uns.NamespaceName.Value); } } } this.currentGenerator = generator; this.scopeEnumerator = this.pdbReader == null ? null : this.pdbReader.GetLocalScopes(methodBody).GetEnumerator(); this.scopeEnumeratorIsValid = this.scopeEnumerator != null && this.scopeEnumerator.MoveNext(); var methodName = MemberHelper.GetMemberSignature(methodBody.MethodDefinition, NameFormattingOptions.SmartTypeName); #region Record all offsets that appear as part of an exception handler Dictionary <uint, bool> offsetsUsedInExceptionInformation = new Dictionary <uint, bool>(); foreach (var exceptionInfo in methodBody.OperationExceptionInformation ?? Enumerable <IOperationExceptionInformation> .Empty) { uint x = exceptionInfo.TryStartOffset; if (!offsetsUsedInExceptionInformation.ContainsKey(x)) { offsetsUsedInExceptionInformation.Add(x, true); } x = exceptionInfo.TryEndOffset; if (!offsetsUsedInExceptionInformation.ContainsKey(x)) { offsetsUsedInExceptionInformation.Add(x, true); } x = exceptionInfo.HandlerStartOffset; if (!offsetsUsedInExceptionInformation.ContainsKey(x)) { offsetsUsedInExceptionInformation.Add(x, true); } x = exceptionInfo.HandlerEndOffset; if (!offsetsUsedInExceptionInformation.ContainsKey(x)) { offsetsUsedInExceptionInformation.Add(x, true); } if (exceptionInfo.HandlerKind == HandlerKind.Filter) { x = exceptionInfo.FilterDecisionStartOffset; if (!offsetsUsedInExceptionInformation.ContainsKey(x)) { offsetsUsedInExceptionInformation.Add(x, true); } } } #endregion Record all offsets that appear as part of an exception handler Dictionary <uint, ILGeneratorLabel> offset2Label = new Dictionary <uint, ILGeneratorLabel>(); #region Pass 1: Make a label for each branch target for (int i = 0; i < count; i++) { IOperation op = operations[i]; switch (op.OperationCode) { case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bge_Un: case OperationCode.Bgt: case OperationCode.Bgt_Un: case OperationCode.Ble: case OperationCode.Ble_Un: case OperationCode.Blt: case OperationCode.Blt_Un: case OperationCode.Bne_Un: case OperationCode.Br: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Leave: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_S: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un_S: case OperationCode.Br_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: case OperationCode.Leave_S: uint x = (uint)op.Value; if (!offset2Label.ContainsKey(x)) { offset2Label.Add(x, new ILGeneratorLabel()); } break; case OperationCode.Switch: uint[] offsets = op.Value as uint[]; foreach (var offset in offsets) { if (!offset2Label.ContainsKey(offset)) { offset2Label.Add(offset, new ILGeneratorLabel()); } } break; default: break; } } #endregion Pass 1: Make a label for each branch target #region Pass 2: Emit each operation, along with labels for (int i = 0; i < count; i++) { IOperation op = operations[i]; ILGeneratorLabel label; this.EmitDebugInformationFor(op); #region Mark operation if it is a label for a branch if (offset2Label.TryGetValue(op.Offset, out label)) { generator.MarkLabel(label); } #endregion Mark operation if it is a label for a branch #region Mark operation if it is pointed to by an exception handler bool ignore; uint offset = op.Offset; if (offsetsUsedInExceptionInformation.TryGetValue(offset, out ignore)) { foreach (var exceptionInfo in methodBody.OperationExceptionInformation) { if (offset == exceptionInfo.TryStartOffset) { generator.BeginTryBody(); } // Never need to do anthing when offset == exceptionInfo.TryEndOffset because // we pick up an EndTryBody from the HandlerEndOffset below // generator.EndTryBody(); if (offset == exceptionInfo.HandlerStartOffset) { switch (exceptionInfo.HandlerKind) { case HandlerKind.Catch: generator.BeginCatchBlock(exceptionInfo.ExceptionType); break; case HandlerKind.Fault: generator.BeginFaultBlock(); break; case HandlerKind.Filter: generator.BeginFilterBody(); break; case HandlerKind.Finally: generator.BeginFinallyBlock(); break; } } if (exceptionInfo.HandlerKind == HandlerKind.Filter && offset == exceptionInfo.FilterDecisionStartOffset) { generator.BeginFilterBlock(); } if (offset == exceptionInfo.HandlerEndOffset) { generator.EndTryBody(); } } } #endregion Mark operation if it is pointed to by an exception handler #region Emit operation along with any injection switch (op.OperationCode) { #region Branches case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bge_Un: case OperationCode.Bgt: case OperationCode.Bgt_Un: case OperationCode.Ble: case OperationCode.Ble_Un: case OperationCode.Blt: case OperationCode.Blt_Un: case OperationCode.Bne_Un: case OperationCode.Br: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Leave: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_S: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un_S: case OperationCode.Br_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: case OperationCode.Leave_S: generator.Emit(ILGenerator.LongVersionOf(op.OperationCode), offset2Label[(uint)op.Value]); break; case OperationCode.Switch: uint[] offsets = op.Value as uint[]; ILGeneratorLabel[] labels = new ILGeneratorLabel[offsets.Length]; for (int j = 0, n = offsets.Length; j < n; j++) { labels[j] = offset2Label[offsets[j]]; } generator.Emit(OperationCode.Switch, labels); break; #endregion Branches #region Everything else case OperationCode.Stloc_0: case OperationCode.Stloc_1: case OperationCode.Stloc_2: case OperationCode.Stloc_3: generator.Emit(op.OperationCode); EmitStoreLocal(generator, op); break; case OperationCode.Stloc: case OperationCode.Stloc_S: generator.Emit(op.OperationCode, op.Value); EmitStoreLocal(generator, op); break; default: if (op.Value == null) { generator.Emit(op.OperationCode); break; } var typeCode = System.Convert.GetTypeCode(op.Value); switch (typeCode) { case TypeCode.Byte: generator.Emit(op.OperationCode, (byte)op.Value); break; case TypeCode.Double: generator.Emit(op.OperationCode, (double)op.Value); break; case TypeCode.Int16: generator.Emit(op.OperationCode, (short)op.Value); break; case TypeCode.Int32: generator.Emit(op.OperationCode, (int)op.Value); break; case TypeCode.Int64: generator.Emit(op.OperationCode, (long)op.Value); break; case TypeCode.Object: IFieldReference fieldReference = op.Value as IFieldReference; if (fieldReference != null) { generator.Emit(op.OperationCode, this.Rewrite(fieldReference)); break; } ILocalDefinition localDefinition = op.Value as ILocalDefinition; if (localDefinition != null) { generator.Emit(op.OperationCode, localDefinition); break; } IMethodReference methodReference = op.Value as IMethodReference; if (methodReference != null) { generator.Emit(op.OperationCode, this.Rewrite(methodReference)); break; } IParameterDefinition parameterDefinition = op.Value as IParameterDefinition; if (parameterDefinition != null) { generator.Emit(op.OperationCode, parameterDefinition); break; } ISignature signature = op.Value as ISignature; if (signature != null) { generator.Emit(op.OperationCode, signature); break; } ITypeReference typeReference = op.Value as ITypeReference; if (typeReference != null) { generator.Emit(op.OperationCode, this.Rewrite(typeReference)); break; } throw new ILMutatorException("Should never get here: no other IOperation argument types should exist"); case TypeCode.SByte: generator.Emit(op.OperationCode, (sbyte)op.Value); break; case TypeCode.Single: generator.Emit(op.OperationCode, (float)op.Value); break; case TypeCode.String: generator.Emit(op.OperationCode, (string)op.Value); break; default: // The other cases are the other enum values that TypeCode has. // But no other argument types should be in the Operations. ILGenerator cannot handle anything else, // so such IOperations should never exist. //case TypeCode.Boolean: //case TypeCode.Char: //case TypeCode.DateTime: //case TypeCode.DBNull: //case TypeCode.Decimal: //case TypeCode.Empty: // this would be the value for null, but the case when op.Value is null is handled before the switch statement //case TypeCode.UInt16: //case TypeCode.UInt32: //case TypeCode.UInt64: throw new ILMutatorException("Should never get here: no other IOperation argument types should exist"); } break; #endregion Everything else } #endregion Emit operation along with any injection } while (generator.InTryBody) { generator.EndTryBody(); } while (this.scopeStack.Count > 0) { this.currentGenerator.EndScope(); this.scopeStack.Pop(); } #endregion Pass 2: Emit each operation, along with labels }
public void BeginFaultBlock() { _ilGeneratorField.BeginFaultBlock(); }
static SqlDataReaderExtensions() { Type typeSqlDataReader = typeof(SqlDataReader); Type typeSqlStatistics = typeSqlDataReader.Assembly.GetType("System.Data.SqlClient.SqlStatistics", true); Type typeFieldNameLookup = typeSqlDataReader.Assembly.GetType("System.Data.ProviderBase.FieldNameLookup", true); BindingFlags staticflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Static; BindingFlags instflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance; DynamicMethod dynmethod = new DynamicMethod("SqlDataReader_IndexOf", typeof(int), new Type[2] { typeSqlDataReader, typeof(string) }, true); ILGenerator gen = dynmethod.GetILGenerator(); gen.DeclareLocal(typeSqlStatistics); gen.DeclareLocal(typeof(int)); // SqlStatistics statistics = (SqlStatistics) null; gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Stloc_0); // try { gen.BeginExceptionBlock(); // statistics = SqlStatistics.StartTimer(this.Statistics); gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Call, typeSqlDataReader.GetProperty("Statistics", instflags | BindingFlags.GetProperty, null, typeSqlStatistics, Type.EmptyTypes, null).GetMethod); gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StartTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null)); gen.Emit(OpCodes.Stloc_0); //statistics // if(this._fieldNameLookup == null) { Label branchTarget = gen.DefineLabel(); gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField)); gen.Emit(OpCodes.Brtrue_S, branchTarget); // this.CheckMetaDataIsReady(); gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Call, typeSqlDataReader.GetMethod("CheckMetaDataIsReady", instflags | BindingFlags.InvokeMethod, null, Type.EmptyTypes, null)); // this._fieldNameLookup = new FieldNameLookup((IDataRecord)this, this._defaultLCID); gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_defaultLCID", instflags | BindingFlags.GetField)); gen.Emit(OpCodes.Newobj, typeFieldNameLookup.GetConstructor(instflags, null, new Type[] { typeof(IDataReader), typeof(int) }, null)); gen.Emit(OpCodes.Stfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.SetField)); // } gen.MarkLabel(branchTarget); gen.Emit(OpCodes.Ldarg_0); //this gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField)); gen.Emit(OpCodes.Ldarg_1); //name gen.Emit(OpCodes.Call, typeFieldNameLookup.GetMethod("IndexOf", instflags | BindingFlags.InvokeMethod, null, new Type[] { typeof(string) }, null)); gen.Emit(OpCodes.Stloc_1); //int output Label leaveProtectedRegion = gen.DefineLabel(); gen.Emit(OpCodes.Leave_S, leaveProtectedRegion); // } finally { gen.BeginFaultBlock(); // SqlStatistics.StopTimer(statistics); gen.Emit(OpCodes.Ldloc_0); //statistics gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StopTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null)); // } gen.EndExceptionBlock(); gen.MarkLabel(leaveProtectedRegion); gen.Emit(OpCodes.Ldloc_1); gen.Emit(OpCodes.Ret); IndexOf = (IndexOfDelegate)dynmethod.CreateDelegate(typeof(IndexOfDelegate)); }
public static void Generate(DynamicMethodDefinition dmd, MethodBase _mb, ILGenerator il) { MethodDefinition def = dmd.Definition; DynamicMethod dm = _mb as DynamicMethod; #if !NETSTANDARD MethodBuilder mb = _mb as MethodBuilder; ModuleBuilder moduleBuilder = mb?.Module as ModuleBuilder; // moduleBuilder.Assembly sometimes avoids the .Assembly override under mysterious circumstances. AssemblyBuilder assemblyBuilder = (mb?.DeclaringType as TypeBuilder)?.Assembly as AssemblyBuilder; HashSet <Assembly> accessChecksIgnored = null; if (mb != null) { accessChecksIgnored = new HashSet <Assembly>(); } #endif #if !CECIL0_9 MethodDebugInformation defInfo = dmd.Debug ? def.DebugInformation : null; #endif if (dm != null) { foreach (ParameterDefinition param in def.Parameters) { dm.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name); } } #if !NETSTANDARD if (mb != null) { foreach (ParameterDefinition param in def.Parameters) { mb.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name); } } #endif LocalBuilder[] locals = def.Body.Variables.Select( var => { LocalBuilder local = il.DeclareLocal(var.VariableType.ResolveReflection(), var.IsPinned); #if !NETSTANDARD && !CECIL0_9 if (mb != null && defInfo != null && defInfo.TryGetName(var, out string name)) { local.SetLocalSymInfo(name); } #endif return(local); } ).ToArray(); // Pre-pass - Set up label map. Dictionary <Instruction, Label> labelMap = new Dictionary <Instruction, Label>(); foreach (Instruction instr in def.Body.Instructions) { if (instr.Operand is Instruction[] targets) { foreach (Instruction target in targets) { if (!labelMap.ContainsKey(target)) { labelMap[target] = il.DefineLabel(); } } } else if (instr.Operand is Instruction target) { if (!labelMap.ContainsKey(target)) { labelMap[target] = il.DefineLabel(); } } } #if !NETSTANDARD && !CECIL0_9 Dictionary <Document, ISymbolDocumentWriter> infoDocCache = mb == null ? null : new Dictionary <Document, ISymbolDocumentWriter>(); #endif int paramOffs = def.HasThis ? 1 : 0; object[] emitArgs = new object[2]; bool checkTryEndEarly = false; foreach (Instruction instr in def.Body.Instructions) { if (labelMap.TryGetValue(instr, out Label label)) { il.MarkLabel(label); } #if !NETSTANDARD && !CECIL0_9 SequencePoint instrInfo = defInfo?.GetSequencePoint(instr); if (mb != null && instrInfo != null) { if (!infoDocCache.TryGetValue(instrInfo.Document, out ISymbolDocumentWriter infoDoc)) { infoDocCache[instrInfo.Document] = infoDoc = moduleBuilder.DefineDocument( instrInfo.Document.Url, instrInfo.Document.LanguageGuid, instrInfo.Document.LanguageVendorGuid, instrInfo.Document.TypeGuid ); } il.MarkSequencePoint(infoDoc, instrInfo.StartLine, instrInfo.StartColumn, instrInfo.EndLine, instrInfo.EndColumn); } #endif foreach (ExceptionHandler handler in def.Body.ExceptionHandlers) { if (checkTryEndEarly && handler.HandlerEnd == instr) { il.EndExceptionBlock(); } if (handler.TryStart == instr) { il.BeginExceptionBlock(); } else if (handler.FilterStart == instr) { il.BeginExceptFilterBlock(); } else if (handler.HandlerStart == instr) { switch (handler.HandlerType) { case ExceptionHandlerType.Filter: il.BeginCatchBlock(null); break; case ExceptionHandlerType.Catch: il.BeginCatchBlock(handler.CatchType.ResolveReflection()); break; case ExceptionHandlerType.Finally: il.BeginFinallyBlock(); break; case ExceptionHandlerType.Fault: il.BeginFaultBlock(); break; } } // Avoid duplicate endfilter / endfinally if (handler.HandlerStart == instr.Next) { switch (handler.HandlerType) { case ExceptionHandlerType.Filter: if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfilter) { goto SkipEmit; } break; case ExceptionHandlerType.Finally: if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfinally) { goto SkipEmit; } break; } } } if (instr.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone) { il.Emit(_ReflOpCodes[instr.OpCode.Value]); } else { object operand = instr.Operand; if (operand is Instruction[] targets) { operand = targets.Select(target => labelMap[target]).ToArray(); // Let's hope that the JIT treats the long forms identically to the short forms. instr.OpCode = instr.OpCode.ToLongOp(); } else if (operand is Instruction target) { operand = labelMap[target]; // Let's hope that the JIT treats the long forms identically to the short forms. instr.OpCode = instr.OpCode.ToLongOp(); } else if (operand is VariableDefinition var) { operand = locals[var.Index]; } else if (operand is ParameterDefinition param) { operand = param.Index + paramOffs; } else if (operand is MemberReference mref) { MemberInfo member = mref.ResolveReflection(); operand = member; #if !NETSTANDARD if (mb != null && member != null) { Assembly asm = member.Module?.Assembly; if (asm != null && !accessChecksIgnored.Contains(asm)) { // while (member.DeclaringType != null) // member = member.DeclaringType; assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(DynamicMethodDefinition.c_IgnoresAccessChecksToAttribute, new object[] { asm.GetName().Name })); accessChecksIgnored.Add(asm); } } #endif } else if (operand is CallSite csite) { if (dm != null) { // SignatureHelper in unmanaged contexts cannot be fully made use of for DynamicMethods. _EmitCallSite(dm, il, _ReflOpCodes[instr.OpCode.Value], csite); continue; } #if !NETSTANDARD operand = csite.ResolveReflection(mb.Module); #else throw new NotSupportedException(); #endif } #if !NETSTANDARD if (mb != null && operand is MethodBase called && called.DeclaringType == null) { // "Global" methods (f.e. DynamicMethods) cannot be tokenized. if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Call) { if (operand is DynamicMethod target) { // This should be heavily optimizable. operand = _CreateMethodProxy(mb, target); } else { IntPtr ptr = called.GetLdftnPointer(); if (IntPtr.Size == 4) { il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)ptr); } else { il.Emit(System.Reflection.Emit.OpCodes.Ldc_I8, (long)ptr); } il.Emit(System.Reflection.Emit.OpCodes.Conv_I); instr.OpCode = Mono.Cecil.Cil.OpCodes.Calli; operand = ((MethodReference)instr.Operand).ResolveReflectionSignature(mb.Module); } } else { throw new NotSupportedException($"Unsupported global method operand on opcode {instr.OpCode.Name}"); } } #endif if (operand == null) { throw new NullReferenceException($"Unexpected null in {def} @ {instr}"); } il.DynEmit(_ReflOpCodes[instr.OpCode.Value], operand); } if (!checkTryEndEarly) { foreach (ExceptionHandler handler in def.Body.ExceptionHandlers) { if (handler.HandlerEnd == instr.Next) { il.EndExceptionBlock(); } } } checkTryEndEarly = false; continue; SkipEmit: checkTryEndEarly = true; continue; } }
public static Type AddType() { // Create an assembly. AssemblyName myAssemblyName = new AssemblyName(); myAssemblyName.Name = "AdderExceptionAsm"; // Create dynamic assembly. AppDomain myAppDomain = Thread.GetDomain(); AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run); // Create a dynamic module. ModuleBuilder myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod"); TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder"); Type[] myAdderParams = new Type[] { typeof(int), typeof(int) }; // Method to add two numbers. MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public | MethodAttributes.Static, typeof(int), myAdderParams); ILGenerator myAdderIL = myMethodBuilder.GetILGenerator(); // Create constructor. ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor( new Type[] { typeof(string) }); MethodInfo myExToStrMI = typeof(OverflowException).GetMethod("ToString"); MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) }); // Declare local variable. LocalBuilder myLocalBuilder1 = myAdderIL.DeclareLocal(typeof(int)); LocalBuilder myLocalBuilder2 = myAdderIL.DeclareLocal(typeof(OverflowException)); // Define label. Label myFailedLabel = myAdderIL.DefineLabel(); Label myEndOfMethodLabel = myAdderIL.DefineLabel(); // Begin exception block. Label myLabel = myAdderIL.BeginExceptionBlock(); myAdderIL.Emit(OpCodes.Ldarg_0); myAdderIL.Emit(OpCodes.Ldc_I4_S, 10); myAdderIL.Emit(OpCodes.Bgt_S, myFailedLabel); myAdderIL.Emit(OpCodes.Ldarg_1); myAdderIL.Emit(OpCodes.Ldc_I4_S, 10); myAdderIL.Emit(OpCodes.Bgt_S, myFailedLabel); myAdderIL.Emit(OpCodes.Ldarg_0); myAdderIL.Emit(OpCodes.Ldarg_1); myAdderIL.Emit(OpCodes.Add_Ovf_Un); myAdderIL.Emit(OpCodes.Stloc_S, myLocalBuilder1); myAdderIL.Emit(OpCodes.Br_S, myEndOfMethodLabel); myAdderIL.MarkLabel(myFailedLabel); myAdderIL.Emit(OpCodes.Ldstr, "Cannot accept values over 10 for addition."); myAdderIL.Emit(OpCodes.Newobj, myConstructorInfo); myAdderIL.Emit(OpCodes.Stloc_S, myLocalBuilder2); myAdderIL.Emit(OpCodes.Ldloc_S, myLocalBuilder2); // Call fault block. myAdderIL.BeginFaultBlock(); Console.WriteLine("Fault block called."); //Throw exception. myAdderIL.ThrowException(typeof(NotSupportedException)); // Call finally block. myAdderIL.BeginFinallyBlock(); myAdderIL.Emit(OpCodes.Ldstr, "{0}"); myAdderIL.Emit(OpCodes.Ldloc_S, myLocalBuilder2); myAdderIL.EmitCall(OpCodes.Callvirt, myExToStrMI, null); myAdderIL.EmitCall(OpCodes.Call, myWriteLineMI, null); myAdderIL.Emit(OpCodes.Ldc_I4_M1); myAdderIL.Emit(OpCodes.Stloc_S, myLocalBuilder1); // End exception block. myAdderIL.EndExceptionBlock(); myAdderIL.MarkLabel(myEndOfMethodLabel); myAdderIL.Emit(OpCodes.Ldloc_S, myLocalBuilder1); myAdderIL.Emit(OpCodes.Ret); return(myTypeBuilder.CreateType()); }
public void BeginFaultBlock() { sb.Append("\r\n\t\tBeginFaultBlock"); gen.BeginFaultBlock(); }