/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> private static void WriteRethrowInvoke(LlvmWriter llvmWriter, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; writer.WriteLine("invoke void @__cxa_rethrow()"); if (exceptionHandlingClause != null) { writer.Indent++; writer.WriteLine( "to label %.unreachable unwind label %.catch_with_cleanup_{0}_{1}", exceptionHandlingClause.Offset, exceptionHandlingClause.Offset + exceptionHandlingClause.Length); writer.Indent--; exceptionHandlingClause.RethrowCatchWithCleanUpRequired = true; } else { writer.Indent++; writer.WriteLine("to label %.unreachable unwind label %.unwind_exception"); writer.Indent--; llvmWriter.needToWriteUnwindException = true; } llvmWriter.needToWriteUnreachable = true; }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> /// <returns> /// </returns> private static IType WriteThrowInvoke( LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; var errorAllocationResultNumber = llvmWriter.WriteAllocateException(opCode); var exceptionPointerType = opCode.OpCodeOperands[0].Result.Type; writer.Write("invoke void @__cxa_throw(i8* {0}, i8* bitcast (", errorAllocationResultNumber); exceptionPointerType.WriteRttiPointerClassInfoDeclaration(writer); writer.WriteLine("* @\"{0}\" to i8*), i8* null)", exceptionPointerType.GetRttiPointerInfoName()); writer.Indent++; if (exceptionHandlingClause != null) { writer.Write("to label %.unreachable unwind label %.catch{0}", exceptionHandlingClause.Offset); } else { writer.Write("to label %.unreachable unwind label %.unwind_exception"); llvmWriter.needToWriteUnwindException = true; } llvmWriter.WriteDbgLine(opCode); writer.WriteLine(string.Empty); writer.Indent--; llvmWriter.needToWriteUnreachable = true; return(exceptionPointerType); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> /// <param name="upperLevelExceptionHandlingClause"> /// </param> public static void WriteRethrow( this LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause, CatchOfFinallyClause upperLevelExceptionHandlingClause) { var writer = llvmWriter.Output; writer.WriteLine("; Rethrow"); WriteRethrowInvoke(llvmWriter, exceptionHandlingClause); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="finallyClause"> /// </param> public static void WriteFinallyLeave(this LlvmWriter llvmWriter, CatchOfFinallyClause finallyClause) { var writer = llvmWriter.Output; llvmWriter.WriteFinallyVariables(finallyClause); writer.WriteLine("store i32 {0}, i32* %.finally_jump{1}", finallyClause.FinallyJumps.Count, finallyClause.Offset); writer.WriteLine("br label %.finally_no_error_entry{0}", finallyClause.Offset); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> public static void WriteCatchBegin(this LlvmWriter llvmWriter, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; var isFinally = exceptionHandlingClause.Flags.HasFlag(ExceptionHandlingClauseOptions.Finally); if (isFinally) { writer.WriteLine("; Begin of Finally"); } else { writer.WriteLine("; Begin of Catch"); } var catchType = exceptionHandlingClause.Catch; var opCodeNone = OpCodePart.CreateNop; var bytePointerType = llvmWriter.System.System_Byte.ToPointerType(); var errorObjectOfCatchResultNumber = llvmWriter.WriteSetResultNumber(opCodeNone, bytePointerType); writer.WriteLine("load i8** %.error_object"); var beginCatchResultNumber = llvmWriter.WriteSetResultNumber(opCodeNone, bytePointerType); writer.WriteLine("call i8* @__cxa_begin_catch(i8* {0})", errorObjectOfCatchResultNumber); if (catchType != null) { llvmWriter.WriteBitcast(opCodeNone, beginCatchResultNumber, catchType); writer.WriteLine(string.Empty); exceptionHandlingClause.ExceptionResult = opCodeNone.Result; } if (isFinally) { // set default error handler jump to carry on try/catch execution writer.WriteLine("store i32 0, i32* %.finally_jump{0}", exceptionHandlingClause.Offset); writer.WriteLine("br label %.finally_no_error_entry{0}", exceptionHandlingClause.Offset); writer.Indent--; writer.WriteLine(".finally_no_error_entry{0}:", exceptionHandlingClause.Offset); writer.Indent++; } if (isFinally) { writer.WriteLine("; Begin of Finally Handler Body"); } else { writer.WriteLine("; Begin of Catch Handler Body"); } }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> public static void WriteThrow(this LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; writer.WriteLine("; Throw"); var exceptionPointerType = exceptionHandlingClause != null ? WriteThrowInvoke(llvmWriter, opCode, exceptionHandlingClause) : WriteThrowCall(llvmWriter, opCode); llvmWriter.typeRttiPointerDeclRequired.Add(exceptionPointerType); llvmWriter.CheckIfExternalDeclarationIsRequired(exceptionPointerType); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="finallyClause"> /// </param> public static void WriteFinallyVariables(this LlvmWriter llvmWriter, CatchOfFinallyClause finallyClause) { if (finallyClause.FinallyVariablesAreWritten) { return; } finallyClause.FinallyVariablesAreWritten = true; var writer = llvmWriter.Output; writer.Write("%.finally_jump{0} = ", finallyClause.Offset); writer.Write("alloca i32, align " + LlvmWriter.PointerSize); writer.WriteLine(string.Empty); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> /// <param name="nextExceptionHandlingClause"> /// </param> public static void WriteCatchTest( this LlvmWriter llvmWriter, CatchOfFinallyClause exceptionHandlingClause, CatchOfFinallyClause nextExceptionHandlingClause) { var writer = llvmWriter.Output; writer.WriteLine("br label %.exception_switch{0}", exceptionHandlingClause.Offset); writer.Indent--; writer.WriteLine(".exception_switch{0}:", exceptionHandlingClause.Offset); writer.Indent++; writer.WriteLine("; Test Exception type"); var catchType = exceptionHandlingClause.Catch; var opCodeNone = OpCodePart.CreateNop; var errorTypeIdOfCatchResultNumber = llvmWriter.WriteSetResultNumber( opCodeNone, llvmWriter.System.System_Int32); writer.WriteLine("load i32* %.error_typeid"); var errorTypeIdOfExceptionResultNumber = llvmWriter.WriteSetResultNumber( opCodeNone, llvmWriter.System.System_Byte.ToPointerType()); writer.Write("call i32 @llvm.eh.typeid.for(i8* bitcast ("); catchType.WriteRttiPointerClassInfoDeclaration(writer); writer.WriteLine("* @\"{0}\" to i8*))", catchType.GetRttiPointerInfoName()); var compareResultResultNumber = llvmWriter.WriteSetResultNumber( opCodeNone, llvmWriter.System.System_Boolean); writer.WriteLine("icmp eq i32 {0}, {1}", errorTypeIdOfCatchResultNumber, errorTypeIdOfExceptionResultNumber); writer.WriteLine( "br i1 {0}, label %.exception_handler{1}, label %.{2}", compareResultResultNumber, exceptionHandlingClause.Offset, nextExceptionHandlingClause != null ? string.Concat("exception_switch", nextExceptionHandlingClause.Offset) : "resume"); writer.Indent--; writer.WriteLine(".exception_handler{0}:", exceptionHandlingClause.Offset); writer.Indent++; }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> /// <param name="upperLevelExceptionHandlingClause"> /// </param> public static void WriteCatchEnd( this LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause, CatchOfFinallyClause upperLevelExceptionHandlingClause) { var writer = llvmWriter.Output; var isFinally = exceptionHandlingClause.Flags.HasFlag(ExceptionHandlingClauseOptions.Finally); if (isFinally) { writer.WriteLine("; End of Finally Handler Body"); } else { writer.WriteLine("; End of Catch Handler Body"); } if (isFinally) { // process Leave jumps var index = 0; var opCodeNope = OpCodePart.CreateNop; var fullyDefinedRef = new FullyDefinedReference( string.Concat("%.finally_jump", exceptionHandlingClause.Offset), llvmWriter.System.System_Int32); llvmWriter.WriteLlvmLoad(opCodeNope, llvmWriter.System.System_Int32, fullyDefinedRef); writer.WriteLine(string.Empty); writer.WriteLine( "switch i32 {1}, label %.finally_exit{0} [", exceptionHandlingClause.Offset, opCodeNope.Result); writer.Indent++; writer.WriteLine("i32 {0}, label %.finally_exit{1}", index++, exceptionHandlingClause.Offset); foreach (var leave in exceptionHandlingClause.FinallyJumps) { writer.WriteLine("i32 {0}, label %{1}", index++, leave); } writer.Indent--; writer.WriteLine("]"); llvmWriter.WriteLabel(writer, string.Concat(".finally_exit", exceptionHandlingClause.Offset)); if (exceptionHandlingClause.EmptyFinallyRethrowRequired) { // rethrow exception in empty finally block var opCodeNop = OpCodePart.CreateNop; llvmWriter.WriteRethrow( opCodeNop, upperLevelExceptionHandlingClause, llvmWriter.tryScopes.Count > 0 ? llvmWriter.tryScopes.Peek().Catches.First() : null); } } var startOfHandlerAddress = exceptionHandlingClause.Offset; var endOfHandlerAddress = exceptionHandlingClause.Offset + exceptionHandlingClause.Length; if (exceptionHandlingClause.RethrowCatchWithCleanUpRequired) { llvmWriter.WriteLabel( writer, string.Format(".catch_with_cleanup_{0}_{1}", startOfHandlerAddress, endOfHandlerAddress)); var opCodeNop = OpCodePart.CreateNop; llvmWriter.WriteLandingPad( opCodeNop, LandingPadOptions.Cleanup, null, new[] { upperLevelExceptionHandlingClause != null ? upperLevelExceptionHandlingClause.Catch : llvmWriter.System.System_Exception }); writer.WriteLine(string.Empty); } else { writer.WriteLine("store i32 0, i32* %.error_typeid"); } writer.WriteLine("call void @__cxa_end_catch()"); if (!exceptionHandlingClause.RethrowCatchWithCleanUpRequired || upperLevelExceptionHandlingClause == null) { var isLeave = opCode.Any(Code.Leave, Code.Leave_S); var nextOp = opCode.Next; if (!isLeave && (nextOp == null || nextOp.JumpDestination == null || !nextOp.JumpDestination.Any() || nextOp.GroupAddressStart != endOfHandlerAddress)) { var noNext = nextOp == null; var isNextCatchBlock = nextOp != null && nextOp.CatchOrFinallyBegin != null; var hasExit = llvmWriter.OpsByAddressStart.Values.Any(op => op.ToCode() == Code.Ret); if (!isNextCatchBlock && !noNext && (isLeave || hasExit)) { writer.WriteLine("br label %.exit{0}", endOfHandlerAddress); llvmWriter.WriteLabel(writer, string.Concat(".exit", endOfHandlerAddress)); writer.WriteLine(string.Empty); } else { writer.WriteLine("unreachable"); } } else { if (isLeave) { writer.WriteLine("br label %.a{0}", opCode.JumpAddress()); } else { writer.WriteLine("br label %.a{0}", nextOp.GroupAddressStart); } } } else { if (!upperLevelExceptionHandlingClause.Flags.HasFlag(ExceptionHandlingClauseOptions.Finally)) { writer.WriteLine("br label %.exception_switch{0}", upperLevelExceptionHandlingClause.Offset); } else { writer.WriteLine("br label %.finally_no_error_entry{0}", upperLevelExceptionHandlingClause.Offset); } } if (isFinally) { writer.WriteLine("; End of Finally"); } else { writer.WriteLine("; End of Catch"); } }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="options"> /// </param> /// <param name="finallyOrFaultClause"> /// </param> /// <param name="catch"> /// </param> /// <param name="filter"> /// </param> /// <param name="exceptionAllocationResultNumber"> /// </param> public static void WriteLandingPad( this LlvmWriter llvmWriter, OpCodePart opCode, LandingPadOptions options, CatchOfFinallyClause finallyOrFaultClause, IType[] @catch = null, int[] filter = null, int?exceptionAllocationResultNumber = null) { var writer = llvmWriter.Output; llvmWriter.WriteLandingPadVariables(); var landingPadResult = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Byte.ToPointerType()); writer.WriteLine( "landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)"); if (options.HasFlag(LandingPadOptions.Cleanup)) { writer.Indent++; writer.WriteLine("cleanup"); writer.Indent--; } if (options.HasFlag(LandingPadOptions.EmptyFilter)) { writer.Indent++; writer.WriteLine("filter [0 x i8*] zeroinitializer"); writer.Indent--; } if (@catch != null && @catch.Any()) { foreach (var catchType in @catch) { writer.Indent++; if (catchType != null) { writer.Write("catch i8* bitcast ("); catchType.WriteRttiPointerClassInfoDeclaration(writer); writer.WriteLine("* @\"{0}\" to i8*)", catchType.GetRttiPointerInfoName()); llvmWriter.typeRttiPointerDeclRequired.Add(catchType); llvmWriter.CheckIfExternalDeclarationIsRequired(catchType); } else { writer.Write("catch i8* null"); } writer.Indent--; } } else if (finallyOrFaultClause != null) { // default catch with rethrowing it writer.Indent++; writer.WriteLine("catch i8* null"); writer.Indent--; finallyOrFaultClause.EmptyFinallyRethrowRequired = true; } var getErrorObjectResultNumber = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Byte.ToPointerType()); writer.WriteLine("extractvalue {1} {0}, 0", landingPadResult, "{ i8*, i32 }"); writer.WriteLine("store i8* {0}, i8** %.error_object", getErrorObjectResultNumber); var getErrorTypeIdResultNumber = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Int32); writer.WriteLine("extractvalue {1} {0}, 1", landingPadResult, "{ i8*, i32 }"); writer.Write("store i32 {0}, i32* %.error_typeid", getErrorTypeIdResultNumber); if (exceptionAllocationResultNumber.HasValue) { writer.WriteLine(string.Empty); writer.Write("call void @__cxa_free_exception(i8* {0})", exceptionAllocationResultNumber.Value); } opCode.Result = landingPadResult; }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="finallyClause"> /// </param> public static void WriteEndFinally(this LlvmWriter llvmWriter, CatchOfFinallyClause finallyClause) { llvmWriter.WriteFinallyVariables(finallyClause); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="finallyClause"> /// </param> public static void WriteFinallyLeave(this LlvmWriter llvmWriter, CatchOfFinallyClause finallyClause) { var writer = llvmWriter.Output; llvmWriter.WriteFinallyVariables(finallyClause); writer.WriteLine( "store i32 {0}, i32* %.finally_jump{1}", finallyClause.FinallyJumps.Count, finallyClause.Offset); writer.WriteLine("br label %.finally_no_error_entry{0}", finallyClause.Offset); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> /// <returns> /// </returns> private static IType WriteThrowInvoke( LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; var errorAllocationResultNumber = llvmWriter.WriteAllocateException(opCode); var exceptionPointerType = opCode.OpCodeOperands[0].Result.Type; writer.Write("invoke void @__cxa_throw(i8* {0}, i8* bitcast (", errorAllocationResultNumber); exceptionPointerType.WriteRttiPointerClassInfoDeclaration(writer); writer.WriteLine("* @\"{0}\" to i8*), i8* null)", exceptionPointerType.GetRttiPointerInfoName()); writer.Indent++; if (exceptionHandlingClause != null) { writer.Write("to label %.unreachable unwind label %.catch{0}", exceptionHandlingClause.Offset); } else { writer.Write("to label %.unreachable unwind label %.unwind_exception"); llvmWriter.needToWriteUnwindException = true; } llvmWriter.WriteDbgLine(opCode); writer.WriteLine(string.Empty); writer.Indent--; llvmWriter.needToWriteUnreachable = true; return exceptionPointerType; }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="exceptionHandlingClause"> /// </param> public static void WriteThrow( this LlvmWriter llvmWriter, OpCodePart opCode, CatchOfFinallyClause exceptionHandlingClause) { var writer = llvmWriter.Output; writer.WriteLine("; Throw"); var exceptionPointerType = exceptionHandlingClause != null ? WriteThrowInvoke(llvmWriter, opCode, exceptionHandlingClause) : WriteThrowCall(llvmWriter, opCode); llvmWriter.typeRttiPointerDeclRequired.Add(exceptionPointerType); llvmWriter.CheckIfExternalDeclarationIsRequired(exceptionPointerType); }
/// <summary> /// </summary> /// <param name="llvmWriter"> /// </param> /// <param name="opCode"> /// </param> /// <param name="options"> /// </param> /// <param name="finallyOrFaultClause"> /// </param> /// <param name="catch"> /// </param> /// <param name="filter"> /// </param> /// <param name="exceptionAllocationResultNumber"> /// </param> public static void WriteLandingPad( this LlvmWriter llvmWriter, OpCodePart opCode, LandingPadOptions options, CatchOfFinallyClause finallyOrFaultClause, IType[] @catch = null, int[] filter = null, int? exceptionAllocationResultNumber = null) { var writer = llvmWriter.Output; llvmWriter.WriteLandingPadVariables(); var landingPadResult = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Byte.ToPointerType()); writer.WriteLine( "landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)"); if (options.HasFlag(LandingPadOptions.Cleanup)) { writer.Indent++; writer.WriteLine("cleanup"); writer.Indent--; } if (options.HasFlag(LandingPadOptions.EmptyFilter)) { writer.Indent++; writer.WriteLine("filter [0 x i8*] zeroinitializer"); writer.Indent--; } if (@catch != null && @catch.Any()) { foreach (var catchType in @catch) { writer.Indent++; if (catchType != null) { writer.Write("catch i8* bitcast ("); catchType.WriteRttiPointerClassInfoDeclaration(writer); writer.WriteLine("* @\"{0}\" to i8*)", catchType.GetRttiPointerInfoName()); llvmWriter.typeRttiPointerDeclRequired.Add(catchType); llvmWriter.CheckIfExternalDeclarationIsRequired(catchType); } else { writer.Write("catch i8* null"); } writer.Indent--; } } else if (finallyOrFaultClause != null) { // default catch with rethrowing it writer.Indent++; writer.WriteLine("catch i8* null"); writer.Indent--; finallyOrFaultClause.EmptyFinallyRethrowRequired = true; } var getErrorObjectResultNumber = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Byte.ToPointerType()); writer.WriteLine("extractvalue {1} {0}, 0", landingPadResult, "{ i8*, i32 }"); writer.WriteLine("store i8* {0}, i8** %.error_object", getErrorObjectResultNumber); var getErrorTypeIdResultNumber = llvmWriter.WriteSetResultNumber( opCode, llvmWriter.System.System_Int32); writer.WriteLine("extractvalue {1} {0}, 1", landingPadResult, "{ i8*, i32 }"); writer.Write("store i32 {0}, i32* %.error_typeid", getErrorTypeIdResultNumber); if (exceptionAllocationResultNumber.HasValue) { writer.WriteLine(string.Empty); writer.Write("call void @__cxa_free_exception(i8* {0})", exceptionAllocationResultNumber.Value); } opCode.Result = landingPadResult; }