TryClause FindOrCreateTryClause(int tryStart, int tryEnd) { // the CIL exception table lists exception handlers (which we call // CatchClauses), with the protected region for each handler. // we use a two-level hierarchy, with TryClauses listing protected // regions, and each TryClause listing the CatchClauses within it. // this function creates a new TryClause or reuses an existing one. if (tryStart >= tryEnd) { return(null); } foreach (var oldTryClause in tryClauses) { if (oldTryClause.tryStart == tryStart && oldTryClause.tryEnd == tryEnd) { return(oldTryClause); } } var newTryClause = new TryClause(); newTryClause.tryStart = tryStart; newTryClause.tryEnd = tryEnd; newTryClause.catchClauses = new List <CatchClause>(); tryClauses.Add(newTryClause); return(newTryClause); }
/// <summary> /// </summary> /// <param name="tryClause"> /// </param> /// <param name="opCodeMethodInfo"> /// </param> /// <param name="llvmWriter"> /// </param> public static void WriteFunctionCallUnwind( this TryClause tryClause, OpCodePart opCodeMethodInfo, LlvmWriter llvmWriter) { if (tryClause == null) { llvmWriter.WriteDbgLine(opCodeMethodInfo); return; } var writer = llvmWriter.Output; var nextAddress = llvmWriter.GetBlockJumpAddress(); var label = string.Concat("next", nextAddress); writer.WriteLine(string.Empty); writer.Indent++; writer.Write("to label %.{0} unwind label %.catch{1}", label, tryClause.Catches.First().Offset); writer.Indent--; llvmWriter.WriteDbgLine(opCodeMethodInfo); writer.WriteLine(string.Empty); writer.Indent--; writer.WriteLine(".{0}:", label); writer.Indent++; LlvmHelpersGen.SetCustomLabel(opCodeMethodInfo, label); }
/// <summary> /// </summary> /// <param name="writer"> /// </param> /// <param name="tryClause"> /// </param> public static void WriteFunctionCall(this LlvmIndentedTextWriter writer, TryClause tryClause) { if (tryClause != null) { writer.Write("invoke "); } else { writer.Write("call "); } }
void SaveExceptionObject(TryClause tryClause, bool keepOnStack = true) { if (keepOnStack) { stackMap.PushStack(ThrowableType); code.NewInstruction(0x59 /* dup */, null, null); } tryClause.localIndex = locals.GetTempIndex(ThrowableType); code.NewInstruction(0x3A /* astore */, null, tryClause.localIndex); stackMap.PopStack(CilMain.Where); }
TryClause FindNearestTryClause(int instOffset) { TryClause nearestClause = null; foreach (var tryClause in tryClauses) { if (instOffset >= tryClause.tryStart && instOffset < tryClause.tryEnd) { if (nearestClause == null || IsNearest(instOffset, nearestClause.tryStart, nearestClause.tryEnd, tryClause.tryStart, tryClause.tryEnd)) { nearestClause = tryClause; } } } return(nearestClause); }
CatchClause RollbackStackFrame(int instOffset) { TryClause tryClause = FindNearestTryClause(instOffset); var clauseClause = FindNearestCatchClause(instOffset); if (clauseClause != null) { if (tryClause == null || IsNearest(instOffset, tryClause.tryStart, tryClause.tryEnd, clauseClause.catchStart, clauseClause.catchEnd)) { tryClause = clauseClause.tryClause; } else { clauseClause = null; } } if (tryClause == null) { throw new InvalidProgramException(); } if (!stackMap.LoadFrame((ushort)tryClause.tryStart, true, CilMain.Where)) { throw new InvalidProgramException(); } if (stackMap.StackArray().Length != 0) { throw new InvalidProgramException(); } return(clauseClause); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCodeMethodInfo"> /// </param> /// <param name="methodInfo"> /// </param> /// <param name="isVirtual"> /// </param> /// <param name="hasThis"> /// </param> /// <param name="isCtor"> /// </param> /// <param name="thisResultNumber"> /// </param> /// <param name="tryClause"> /// </param> public static void WriteCall( this LlvmWriter llvmWriter, OpCodePart opCodeMethodInfo, IMethod methodInfo, bool isVirtual, bool hasThis, bool isCtor, FullyDefinedReference thisResultNumber, TryClause tryClause) { var writer = llvmWriter.Output; llvmWriter.CheckIfExternalDeclarationIsRequired(methodInfo); llvmWriter.CheckIfExternalDeclarationIsRequired(methodInfo.DeclaringType); IType thisType; bool hasThisArgument; OpCodePart opCodeFirstOperand; BaseWriter.ReturnResult resultOfFirstOperand; bool isIndirectMethodCall; IType ownerOfExplicitInterface; IType requiredType; methodInfo.WriteFunctionCallProlog( opCodeMethodInfo, isVirtual, hasThis, llvmWriter, out thisType, out hasThisArgument, out opCodeFirstOperand, out resultOfFirstOperand, out isIndirectMethodCall, out ownerOfExplicitInterface, out requiredType); if (hasThisArgument) { opCodeMethodInfo.WriteFunctionCallPrepareThisExpression(thisType, opCodeFirstOperand, resultOfFirstOperand, llvmWriter); } FullyDefinedReference methodAddressResultNumber = null; if (isIndirectMethodCall) { methodAddressResultNumber = llvmWriter.GenerateVirtualCall( opCodeMethodInfo, methodInfo, thisType, opCodeFirstOperand, resultOfFirstOperand, ref requiredType); } methodInfo.WriteFunctionCallLoadFunctionAddress(opCodeMethodInfo, thisType, ref methodAddressResultNumber, llvmWriter); methodInfo.PreProcessCallParameters(opCodeMethodInfo, llvmWriter); if (llvmWriter.ProcessPluggableMethodCall(opCodeMethodInfo, methodInfo)) { return; } var returnFullyDefinedReference = methodInfo.WriteFunctionCallResult(opCodeMethodInfo, llvmWriter); writer.WriteFunctionCall(tryClause); methodInfo.WriteFunctionCallAttributes(writer); if (methodInfo.CallingConvention.HasFlag(CallingConventions.VarArgs)) { llvmWriter.WriteMethodPointerType(writer, methodInfo); writer.Write(" "); } else { methodInfo.WriteFunctionCallReturnType(llvmWriter); writer.Write(' '); // extra support if (methodInfo.IsExternalLibraryMethod()) { writer.Write("(...)* "); } } methodInfo.WriteFunctionNameExpression(methodAddressResultNumber, ownerOfExplicitInterface, llvmWriter); methodInfo.GetParameters() .WriteFunctionCallArguments( opCodeMethodInfo.OpCodeOperands, isVirtual, hasThis, isCtor, thisResultNumber, thisType, returnFullyDefinedReference, methodInfo != null ? methodInfo.ReturnType : null, llvmWriter, methodInfo.CallingConvention.HasFlag(CallingConventions.VarArgs)); tryClause.WriteFunctionCallUnwind(opCodeMethodInfo, llvmWriter); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCodeMethodInfo"> /// </param> /// <param name="methodInfo"> /// </param> /// <param name="isVirtual"> /// </param> /// <param name="hasThis"> /// </param> /// <param name="isCtor"> /// </param> /// <param name="thisResultNumber"> /// </param> /// <param name="tryClause"> /// </param> public static void WriteCall( this LlvmWriter llvmWriter, OpCodePart opCodeMethodInfo, IMethod methodInfo, bool isVirtual, bool hasThis, bool isCtor, FullyDefinedReference thisResultNumber, TryClause tryClause) { var writer = llvmWriter.Output; IType thisType; bool hasThisArgument; OpCodePart opCodeFirstOperand; BaseWriter.ReturnResult resultOfFirstOperand; bool isIndirectMethodCall; IType ownerOfExplicitInterface; IType requiredType; methodInfo.WriteFunctionCallProlog( opCodeMethodInfo, isVirtual, hasThis, llvmWriter, out thisType, out hasThisArgument, out opCodeFirstOperand, out resultOfFirstOperand, out isIndirectMethodCall, out ownerOfExplicitInterface, out requiredType); llvmWriter.CheckIfMethodExternalDeclarationIsRequired(methodInfo, ownerOfExplicitInterface); llvmWriter.CheckIfExternalDeclarationIsRequired(methodInfo.DeclaringType); if (hasThisArgument) { opCodeMethodInfo.WriteFunctionCallPrepareThisExpression( thisType, opCodeFirstOperand, resultOfFirstOperand, llvmWriter); } FullyDefinedReference methodAddressResultNumber = null; if (isIndirectMethodCall) { methodAddressResultNumber = llvmWriter.GenerateVirtualCall( opCodeMethodInfo, methodInfo, thisType, opCodeFirstOperand, resultOfFirstOperand, ref requiredType); } methodInfo.WriteFunctionCallLoadFunctionAddress( opCodeMethodInfo, thisType, ref methodAddressResultNumber, llvmWriter); methodInfo.PreProcessCallParameters(opCodeMethodInfo, llvmWriter); if (llvmWriter.ProcessPluggableMethodCall(opCodeMethodInfo, methodInfo)) { return; } var returnFullyDefinedReference = methodInfo.WriteFunctionCallResult(opCodeMethodInfo, llvmWriter); writer.WriteFunctionCall(tryClause); methodInfo.WriteFunctionCallAttributes(writer); if (methodInfo.CallingConvention.HasFlag(CallingConventions.VarArgs)) { llvmWriter.WriteMethodPointerType(writer, methodInfo); writer.Write(" "); } else { methodInfo.WriteFunctionCallReturnType(llvmWriter); writer.Write(' '); // extra support if (methodInfo.IsExternalLibraryMethod()) { writer.Write("(...)* "); } } methodInfo.WriteFunctionNameExpression(methodAddressResultNumber, ownerOfExplicitInterface, llvmWriter); methodInfo.GetParameters() .WriteFunctionCallArguments( opCodeMethodInfo.OpCodeOperands, isVirtual, hasThis, isCtor, thisResultNumber, thisType, returnFullyDefinedReference, methodInfo != null ? methodInfo.ReturnType : null, llvmWriter, methodInfo.CallingConvention.HasFlag(CallingConventions.VarArgs)); tryClause.WriteFunctionCallUnwind(opCodeMethodInfo, llvmWriter); }
static CatchClause CreateCatchClause(TryClause tryClause, ExceptionHandler cilClause) { // convert a CIL exception table entry to a CatchClause, while doing // some validity checks on the input. in particular, we expect that // there are no gaps between catch clauses, and at most one finally // (or fault) clause within a protected region. var catchClause = new CatchClause(); catchClause.catchStart = cilClause.HandlerStart.Offset; catchClause.catchEnd = cilClause.HandlerEnd?.Offset ?? 0xFFFF; int handlerStart = catchClause.catchStart; if (catchClause.catchStart >= catchClause.catchEnd || catchClause.catchStart < tryClause.tryEnd) { return(null); } if (cilClause.HandlerType == ExceptionHandlerType.Catch) { // note that we treat 'catch (System.Exception)' // as 'catch (Throwable)' so that our try/catch blocks // can really see all exceptions var myType = CilType.From(cilClause.CatchType); if (myType.JavaName == "system.Exception" && (!myType.Equals(ThrowableType))) { throw CilMain.Where.Exception( "catch of system.Exception (use System.Exception)"); } if (myType.Equals(JavaType.ObjectType)) { catchClause.catchType = ThrowableType; } else { catchClause.catchType = myType; } if (myType.HasGenericParameters) { catchClause.catchFromType = cilClause.CatchType; } } else if (cilClause.HandlerType == ExceptionHandlerType.Filter) { catchClause.catchType = ThrowableType; catchClause.filterCondStart = cilClause.FilterStart.Offset; handlerStart = catchClause.filterCondStart; if (catchClause.filterCondStart < tryClause.tryEnd) { return(null); } } else if (cilClause.HandlerType == ExceptionHandlerType.Finally || cilClause.HandlerType == ExceptionHandlerType.Fault) { catchClause.catchType = ThrowableType; catchClause.finallyClause = true; // note that we treat a 'fault' clause as a special form of a // 'finally' clause, so only one of these is allowed per 'try'. catchClause.faultClause = (cilClause.HandlerType == ExceptionHandlerType.Fault); } else { return(null); } bool consecutiveClauses = true; if (tryClause.catchClauses.Count == 0) { consecutiveClauses = (handlerStart == tryClause.tryEnd); } else { foreach (var oldCatchClause in tryClause.catchClauses) { if (handlerStart <= oldCatchClause.catchStart) { consecutiveClauses = false; } if (oldCatchClause.finallyClause) { consecutiveClauses = false; } } } if (!consecutiveClauses) { throw CilMain.Where.Exception("non-consecutive clauses in a try block"); } if (catchClause.catchEnd > tryClause.catchEnd) { tryClause.catchEnd = catchClause.catchEnd; } return(catchClause); }