Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
 /// <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 ");
     }
 }
Beispiel #4
0
 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);
 }
Beispiel #5
0
 /// <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 ");
     }
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        /// <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);
        }
Beispiel #10
0
        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);
        }