예제 #1
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            switch (instruction.OpCode.Code)
            {
            case Code.Newarr:
                Typ arrayContentType;
                // The array is one-dimensional.
                if (instruction.Operand is TypeReference instructionType)
                {
                    arrayContentType = Typ.FromTypeReference(instructionType);
                }
                // Then the content type of the array is an array (it is multidimensional).
                else if (instruction.Operand is ArrayType instructionArrayType)
                {
                    // Creates a SIL representation of the array content type.
                    arrayContentType = CreateArrayType(
                        Typ.FromTypeReference(instructionArrayType.GetElementType()),
                        instructionArrayType.Rank, state);
                }
                else
                {
                    Log.WriteParserWarning(instruction.Operand, instruction, state);
                    return(false);
                }
                var arrayIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal);
                (var arrayLength, _) = state.Pop();

                var arrayLengthSizeofExp = new SizeofExpression(
                    new Tarray(arrayContentType),
                    SizeofExpression.SizeofExpressionKind.exact,
                    arrayLength);

                var arrayTypeWithPtr = new Tptr(Tptr.PtrKind.Pk_pointer,
                                                new Tarray(arrayContentType));

                var args = new List <Call.CallArg>
                {
                    new Call.CallArg(arrayLengthSizeofExp, arrayTypeWithPtr)
                };

                // Represents memory allocation.
                var callInstr = new Call(returnId: arrayIdentifier,
                                         returnType: arrayTypeWithPtr,
                                         functionExpression: new ConstExpression(
                                             ProcedureName.BuiltIn__new_array),
                                         args: args,
                                         flags: new Call.CallFlags(),
                                         location: state.CurrentLocation);
                var newNode = AddMethodBodyInstructionsToCfg(state, callInstr);
                state.PushExpr(new VarExpression(arrayIdentifier), arrayTypeWithPtr);
                state.PushInstruction(instruction.Next, newNode);
                return(true);

            default:
                return(false);
            }
        }
예제 #2
0
        /// <summary>
        /// Creates a local variable from a given method and variable index; creates the address of
        /// a local variable if the appropriate parameter value is specified.
        /// </summary>
        /// <param name="index">An identifier for a local variable. A compiled local variable loses
        /// its variable name, which is replaced instead by an index.</param>
        /// <param name="method">The method in which the local variable is initialized.</param>
        /// <returns>The local variable expression (or address) and its associated type.</returns>
        protected (LvarExpression, Typ) CreateLocal(int index,
                                                    MethodDefinition method)
        {
            var name = LocalName(index);
            // If the variable is by reference, its corresponding type will have an &, which we do
            // not want.
            var variableType = method.Body.Variables[index].VariableType;

            return(new LvarExpression(new LocalVariable(name, method)),
                   Typ.FromTypeReference(variableType));
        }
예제 #3
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            switch (instruction.OpCode.Code)
            {
            // Object construction in SIL is represented as follows:
            // n${i} = _fun___new (sizeof (ExampleClass))
            // n${i+1} = _fun_ExampleClass.ctor(ni)
            // x = n${i}, where x is the program variable
            case Code.Newobj:
                var constructorMethod   = instruction.Operand as MethodReference;
                var objectTypeReference = constructorMethod.DeclaringType;
                (var memoryAllocationCall, var objectVariable) = CreateMemoryAllocationCall(
                    objectTypeReference, state);
                state.PushExpr(objectVariable, Typ.FromTypeReference(objectTypeReference));

                // Represents constructor call; we discard the return var as it's not needed.
                CreateMethodCall(state,
                                 false,
                                 constructorMethod,
                                 out _,
                                 out _,
                                 out _,
                                 out var constructorCall,
                                 isConstructorCall: true);

                var newNode = new StatementNode(location: state.CurrentLocation,
                                                kind: StatementNode.StatementNodeKind.Call,
                                                proc: state.ProcDesc,
                                                comment: constructorMethod
                                                .GetCompatibleFullName());
                newNode.Instructions.Add(memoryAllocationCall);
                newNode.Instructions.Add(constructorCall);
                RegisterNode(state, newNode);

                // The first copy of this stack item was popped in the invocation of the
                // constructor, so we push another on.
                state.PushExpr(objectVariable, Typ.FromTypeReference(objectTypeReference));

                state.PushInstruction(instruction.Next, newNode);
                // Append the next instruction (which should be stloc, for representing
                // storage of the constructed object into a local variable) to this new node.
                state.AppendToPreviousNode = true;
                return(true);

            default:
                return(false);
            }
        }
예제 #4
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            switch (instruction.OpCode.Code)
            {
            case Code.Ldnull:
                state.PushExpr(
                    new ConstExpression(new IntRepresentation(0, false, true)),
                    Typ.FromTypeReference(state.Method.Module.TypeSystem.Object));
                state.PushInstruction(instruction.Next);
                return(true);

            default:
                return(false);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ProcedureDescription"/> class.
        /// </summary>
        /// <param name="methodDefinition">The <see cref="MethodDefinition"/> from which to create
        /// the description.</param>
        /// <param name="cfg">The CFG with which this procedure description is associated.</param>
        public ProcedureDescription(MethodDefinition methodDefinition, Cfg cfg)
        {
            PdId = NextId;

            var parameters = methodDefinition.Parameters.Select(
                p => new VariableDescription(p.Name, Typ.FromTypeReference(p.ParameterType)));

            if (!methodDefinition.IsStatic)
            {
                parameters = parameters.Prepend(
                    new VariableDescription(Identifier.ThisIdentifier,
                                            Typ.FromTypeReference(
                                                methodDefinition.DeclaringType)));
            }

            var location = Location.FromSequencePoint(
                methodDefinition.DebugInformation.SequencePoints.FirstOrDefault());

            PdAttributes = new ProcedureAttributes()
            {
                Access = methodDefinition.IsPublic ?
                         ProcedureAttributes.ProcedureAccessKind.Public :
                         methodDefinition.IsPrivate ?
                         ProcedureAttributes.ProcedureAccessKind.Private :
                         ProcedureAttributes.ProcedureAccessKind.Default,
                Formals  = parameters.ToList(),
                RetType  = Typ.FromTypeReference(methodDefinition.ReturnType),
                Loc      = location,
                ProcName = new ProcedureName(methodDefinition)
            };

            Nodes     = new List <CfgNode>();
            StartNode = new StartNode(location, this);
            ExitNode  = new ExitNode(Location.FromSequencePoint(methodDefinition
                                                                .DebugInformation
                                                                .SequencePoints
                                                                .FirstOrDefault()),
                                     this);
            ExceptionSinkNode = new StatementNode(location,
                                                  StatementNode.StatementNodeKind.ExceptionsSink,
                                                  proc: this);

            cfg.RegisterNode(StartNode);
            cfg.RegisterNode(ExitNode);
            cfg.RegisterNode(ExceptionSinkNode);
        }
예제 #6
0
        /// <summary>
        /// Creates an entry node for representing exceptional control flow into an exception
        /// handler; in it, the return value is nullified and the unwrap exception function is
        /// applied to it, which causes the exception to be stored in a catch variable.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="handler">The exception handler for which the node is being
        /// created.</param>
        /// <returns>The created entry node, as well as the identifier in which the exception is
        /// stored.</returns>
        private static (CfgNode, Identifier) CreateExceptionEntryNode(ProgramState state,
                                                                      ExceptionHandler handler)
        {
            var handlerStartLocation = GetHandlerStartLocation(state, handler);
            var returnIdentifier     = state.GetIdentifier(Identifier.IdentKind.Normal);
            var returnExpression     = new LvarExpression(
                new LocalVariable(Identifier.ReturnIdentifier, state.Method));
            var returnType = Typ.FromTypeReference(state.Method.ReturnType);

            var getReturnValue = new Load(returnIdentifier,
                                          returnExpression,
                                          returnType,
                                          handlerStartLocation);
            var deactivateException = new Store(returnExpression,
                                                new ConstExpression(
                                                    new IntRepresentation(0, false, true)),
                                                returnType,
                                                handlerStartLocation);

            var exceptionIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal);
            var unwrapReturnValue   = new Call(exceptionIdentifier,
                                               returnType,
                                               new ConstExpression(
                                                   ProcedureName.BuiltIn__unwrap_exception),
                                               new List <Call.CallArg>
            {
                new Call.CallArg(
                    new VarExpression(returnIdentifier),
                    returnType)
            },
                                               new Call.CallFlags(),
                                               handlerStartLocation);

            var node = new StatementNode(handlerStartLocation,
                                         StatementNode.StatementNodeKind.ExceptionHandler,
                                         state.ProcDesc);

            node.Instructions = new List <SilInstruction> {
                getReturnValue,
                deactivateException,
                unwrapReturnValue
            };
            state.Cfg.RegisterNode(node);
            return(node, exceptionIdentifier);
        }
예제 #7
0
        /// <summary>
        /// Creates and returns a <see cref="Call"/> instruction indicating object memory
        /// allocation and the temporary identifier for the new object. Examples of CIL
        /// instructions for which this method is used include initobj and newobj.
        /// </summary>
        /// <param name="newObjectReference">The type to be allocated.</param>
        /// <param name="state">Current program state.</param>
        /// <returns>Instruction representing the memory allocation, as well as the identifier for
        /// the new object.</returns>
        protected static (Call, VarExpression) CreateMemoryAllocationCall(
            TypeReference newObjectReference, ProgramState state)
        {
            var type = Typ.FromTypeReference(newObjectReference);
            var newObjectIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal);
            var callFlags           = new Call.CallFlags(isVirtual: false,
                                                         noReturn: false,
                                                         isObjCBlock: false);
            var args = new List <Call.CallArg>
            {
                new Call.CallArg(new SizeofExpression(type.StripPointer(), "exact"), type)
            };

            return(new Call(newObjectIdentifier,
                            type,
                            new ConstExpression(ProcedureName.BuiltIn__new),
                            args,
                            callFlags,
                            state.CurrentLocation),
                   new VarExpression(newObjectIdentifier));
        }
예제 #8
0
        /// <summary>
        /// Creates a node for returning an exceptional value; does not register the node in the
        /// CFG.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="returnValue">The exceptional value to be returned.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        protected static CfgNode CreateExceptionReturnNode(ProgramState state,
                                                           Expression returnValue,
                                                           Location location)
        {
            var retType = state.Method.ReturnType.GetElementType();
            var retNode = new StatementNode(location,
                                            StatementNode.StatementNodeKind.ReturnStmt,
                                            state.ProcDesc);
            var returnVariable = new LvarExpression(new LocalVariable(Identifier.ReturnIdentifier,
                                                                      state.Method));
            var retInstr = new Store(returnVariable,
                                     new ExnExpression(returnValue),
                                     Typ.FromTypeReference(retType),
                                     location);

            retNode.Instructions.Add(retInstr);
            retNode.Successors = new List <CfgNode> {
                state.ProcDesc.ExitNode
            };
            return(retNode);
        }
예제 #9
0
        /// <summary>
        /// Creates a method call returned via out parameter.
        /// </summary>
        /// <param name="state">Current program state.</param>
        /// <param name="isVirtual">True if method call is virtual, false otherwise.</param>
        /// <param name="calledMethod">The method being called.</param>
        /// <param name="returnType">The return type of the method being called.</param>
        /// <param name="returnVariable">Identifies the variable returned by the method.</param>
        /// <param name="callArgs">The method arguments.</param>
        /// <param name="methodCall">The Call SIL instruction.</param>
        /// <param name="isConstructorCall"><c>true</c> if the call is for a constructor,
        /// <c>false</c> otherwise.</param>
        protected static void CreateMethodCall(ProgramState state,
                                               bool isVirtual,
                                               MethodReference calledMethod,
                                               out TypeReference returnType,
                                               out Identifier returnVariable,
                                               out List <Call.CallArg> callArgs,
                                               out Call methodCall,
                                               bool isConstructorCall = false)
        {
            callArgs   = new List <Call.CallArg>();
            returnType = calledMethod.ReturnType;
            var paramCount = calledMethod.Parameters.Count;

            if (calledMethod.HasThis)
            {
                paramCount++;
            }
            if (isConstructorCall)
            {
                // In this case, the "this" argument of the constructor is located at the top of
                // the stack; we remove it and place it at the front of the argument list.
                (var thisExpr, var thisType) = state.Pop();
                callArgs.Add(new Call.CallArg(thisExpr, thisType));
                paramCount--;
            }
            var funcExp = new ConstExpression(new ProcedureName(calledMethod));

            callArgs.AddRange(state.PopMany(paramCount)
                              .Select(p => new Call.CallArg(p.Item1, p.Item2))
                              .ToList());
            var callFlags = new Call.CallFlags(isVirtual, false, false);

            returnVariable = state.GetIdentifier(Identifier.IdentKind.Normal);
            methodCall     = new Call(returnId: returnVariable,
                                      returnType: Typ.FromTypeReference(returnType),
                                      functionExpression: funcExp,
                                      args: callArgs,
                                      flags: callFlags,
                                      location: state.CurrentLocation);
        }
예제 #10
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            switch (instruction.OpCode.Code)
            {
            case Code.Ret:
                var retType = state.Method.ReturnType.GetElementType();
                if (retType == state.Method.Module.TypeSystem.Void)
                {
                    state.PreviousNode.Successors.Add(state.ProcDesc.ExitNode);
                }
                else
                {
                    (var returnValue, _) = state.Pop();
                    Expression returnVariable = new LvarExpression(
                        new LocalVariable(Identifier.ReturnIdentifier,
                                          state.Method));
                    var retInstr = new Store(lvalue: returnVariable,
                                             rvalue: returnValue,
                                             type: Typ.FromTypeReference(retType),
                                             location: state.CurrentLocation);
                    var retNode = new StatementNode(state.CurrentLocation,
                                                    StatementNode.StatementNodeKind.ReturnStmt,
                                                    state.ProcDesc);
                    retNode.Instructions.Add(retInstr);
                    retNode.Successors = new List <CfgNode> {
                        state.ProcDesc.ExitNode
                    };
                    RegisterNode(state, retNode);
                }
                return(true);

            default:
                return(false);
            }
        }
예제 #11
0
        /// <summary>
        /// Creates the argument variable.
        /// </summary>
        /// <param name="index">The argument's index.</param>
        /// <param name="method">The method with which the argument is associated.</param>
        /// <returns>Expression representing the argument and its type.</returns>
        protected (LvarExpression, Typ) CreateArg(int index,
                                                  MethodDefinition method)
        {
            TypeReference type;
            var           name = ArgumentName(index, method);

            if (method.HasThis)
            {
                if (index == 0)
                {
                    type = method.DeclaringType;
                }
                else
                {
                    type = method.Parameters[index - 1].ParameterType;
                }
            }
            else
            {
                type = method.Parameters[index].ParameterType;
            }
            return(new LvarExpression(new LocalVariable(name, method)),
                   Typ.FromTypeReference(type));
        }
예제 #12
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            bool isVirtual;

            switch (instruction.OpCode.Code)
            {
            case Code.Call:
                isVirtual = false;
                break;

            case Code.Callvirt:
                isVirtual = true;
                break;

            default:
                return(false);
            }

            var instrs = new List <SilInstruction>();

            var calledMethod = instruction.Operand as MethodReference;

            if (calledMethod.GetCompatibleFullName()
                .Contains("System.Void System.Threading.Monitor::Enter"))
            {
                state.ProcDesc.PdAttributes.IsCSharpSynchronizedMethod = true;
                instrs.Add(CreateLockedAttributeCall(true, calledMethod.Parameters.Count, state));
            }
            else if (calledMethod.GetCompatibleFullName()
                     .Contains("System.Void System.Threading.Monitor::Exit"))
            {
                instrs.Add(CreateLockedAttributeCall(false, calledMethod.Parameters.Count, state));
            }
            else
            {
                CreateMethodCall(state,
                                 isVirtual,
                                 calledMethod,
                                 out var retTypeRef,
                                 out var retId,
                                 out var callArgs,
                                 out var callInstr);

                instrs.Add(callInstr);

                // Deref on the object calling in the case of instance method, for null
                // validation on it by Infer. Object "this" is the first argument in the argument list
                // for instance methods.
                if (calledMethod.HasThis && calledMethod.Name != Identifier.ConstructorIdentifier)
                {
                    var thisArg = callArgs.First();
                    if (thisArg.Expression is VarExpression varExpression &&
                        !varExpression.FromThis)
                    {
                        instrs.Insert(0, CreateDereference(varExpression, thisArg.Type, state));
                    }
                }

                var returnType = Typ.FromTypeReference(retTypeRef);
                if (!(returnType is Tvoid))
                {
                    state.PushExpr(new VarExpression(retId), returnType);
                }
            }

            var callNode = new StatementNode(location: state.CurrentLocation,
                                             kind: StatementNode.StatementNodeKind.Call,
                                             proc: state.ProcDesc,
                                             comment: calledMethod.GetCompatibleFullName());

            callNode.Instructions.AddRange(instrs);
            RegisterNode(state, callNode);

            state.PushInstruction(instruction.Next, callNode);
            state.AppendToPreviousNode = true;
            return(true);
        }
예제 #13
0
        protected override bool ParseCilInstructionInternal(Instruction instruction,
                                                            ProgramState state)
        {
            switch (instruction.OpCode.Code)
            {
            case Code.Ret:
                Store retInstr;
                var   retType = state.Method.ReturnType.GetElementType();
                var   retNode = new StatementNode(state.CurrentLocation,
                                                  StatementNode.StatementNodeKind.ReturnStmt,
                                                  state.ProcDesc);
                if (retType == state.Method.Module.TypeSystem.Void)
                {
                    state.PreviousNode.Successors.Add(state.ProcDesc.ExitNode);
                }
                else
                {
                    (var returnValue, _) = state.Pop();
                    Expression returnVariable = new LvarExpression(
                        new LocalVariable(Identifier.ReturnIdentifier,
                                          state.Method));

                    if (returnValue is BinopExpression)
                    {
                        // We see that for the auto-generated method op_Inequality in records,
                        // an equality expression is pushed directly onto the stack and
                        // returned. However, return of an expression is not valid in the SIL --
                        // we must inline a variable store and load of the value prior to
                        // subsequently returning it.
                        var inlineReturn     = new LocalVariable("inlineReturn", state.Method);
                        var inlineIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal);

                        var storeInlineReturn = new Store(new LvarExpression(inlineReturn),
                                                          returnValue,
                                                          Typ.FromTypeReference(retType),
                                                          state.CurrentLocation);
                        AddMethodBodyInstructionsToCfg(state, storeInlineReturn);

                        var loadInlineReturn = new Load(inlineIdentifier,
                                                        new LvarExpression(inlineReturn),
                                                        Typ.FromTypeReference(retType),
                                                        state.CurrentLocation);
                        AddMethodBodyInstructionsToCfg(state, loadInlineReturn);

                        retInstr = new Store(returnVariable,
                                             new VarExpression(inlineIdentifier),
                                             Typ.FromTypeReference(retType),
                                             state.CurrentLocation);
                    }
                    else
                    {
                        retInstr = new Store(returnVariable,
                                             returnValue,
                                             Typ.FromTypeReference(retType),
                                             state.CurrentLocation);
                    }
                    retNode.Instructions.Add(retInstr);
                    retNode.Successors = new List <CfgNode> {
                        state.ProcDesc.ExitNode
                    };
                    RegisterNode(state, retNode);
                }
                return(true);

            default:
                return(false);
            }
        }
예제 #14
0
        private TypeEntry RegisterCilType(TypeDefinition type, TypeEnvironment typeEnvironment)
        {
            var typeFullName = type.GetCompatibleFullName();

            if (typeEnvironment.ContainsType(typeFullName))
            {
                return(typeEnvironment[typeFullName]);
            }

            // Gets all the classes from which the input class inherits.
            var baseClasses        = type.Interfaces.Select(i => i.InterfaceType).Append(type.BaseType);
            var baseInstanceFields = new List <FieldIdentifier>();
            var baseStaticFields   = new List <FieldIdentifier>();
            var baseSupers         = new List <string>();
            var baseTypes          = new List <string>();

            // Aggregates the instance and static fields, the super
            foreach (var baseClass in baseClasses)
            {
                if (baseClass != null)
                {
                    try
                    {
                        var resolvedBaseClass = baseClass.Resolve();
                        if (resolvedBaseClass != null)
                        {
                            var baseTypeEntry = RegisterCilType(resolvedBaseClass, typeEnvironment);

                            baseInstanceFields.AddRange(baseTypeEntry.TypeStruct.InstanceFields);
                            baseStaticFields.AddRange(baseTypeEntry.TypeStruct.StaticFields);
                            baseSupers.AddRange(baseTypeEntry.TypeStruct.Supers.Select(s => s.Name));
                            baseTypes.Add(baseClass.GetCompatibleFullName());
                        }
                    }
                    catch
                    {
                        continue;
                    }
                }
            }

            var allFields = type.Fields.Select(
                f => (f.IsStatic,
                      Field: new FieldIdentifier(f.GetCompatibleFullName(),
                                                 Typ.FromTypeReference(f.FieldType))));

            var instanceFields = allFields
                                 .Where(f => !f.IsStatic)
                                 .Select(f => f.Field)
                                 .Concat(baseInstanceFields);
            var staticFields = allFields
                               .Where(f => f.IsStatic)
                               .Select(f => f.Field)
                               .Concat(baseStaticFields);
            var procNames = type.Methods.Select(m => new ProcedureName(m));

            var typeStruct = new Struct(instanceFields,
                                        staticFields,
                                        baseSupers.Concat(baseTypes),
                                        procNames);

            var typeEntry = new TypeEntry
            {
                TypeName   = TypeName.FromTypeReference(type),
                TypeStruct = typeStruct,
            };

            typeEnvironment[typeFullName] = typeEntry;
            return(typeEntry);
        }
예제 #15
0
        protected static (CfgNode, CfgNode) CreateExceptionTypeCheckBranchNodes(
            ProgramState state, ExceptionHandler handler, Identifier exceptionIdentifier)
        {
            var handlerStartLocation = GetHandlerStartLocation(state, handler);
            var exceptionExpression  = new VarExpression(exceptionIdentifier);
            var isInstIdentifier     = state.GetIdentifier(Identifier.IdentKind.Normal);
            var isInstArgs           = new List <Call.CallArg>
            {
                new Call.CallArg(exceptionExpression,
                                 Typ.FromTypeReference(handler.CatchType)),
                new Call.CallArg(
                    new SizeofExpression(
                        Typ.FromTypeReferenceNoPointer(handler.CatchType),
                        SizeofExpression.SizeofExpressionKind.exact),
                    new Tvoid())
            };
            // We don't mark the function output as an isinst output, as there is no load or store
            // of it.
            var isInstCall = new Call(isInstIdentifier,
                                      new Tint(Tint.IntKind.IBool),
                                      new ConstExpression(ProcedureName.BuiltIn__instanceof),
                                      isInstArgs,
                                      new Call.CallFlags(),
                                      handlerStartLocation);

            var isInstOutputExpression = new VarExpression(isInstIdentifier);
            var pruneTrueInstruction   = new Prune(isInstOutputExpression,
                                                   true,
                                                   Prune.IfKind.Ik_switch,
                                                   handlerStartLocation);

            var pruneFalseInstruction = new Prune(new UnopExpression(UnopExpression.UnopKind.LNot,
                                                                     isInstOutputExpression,
                                                                     null),
                                                  false,
                                                  Prune.IfKind.Ik_switch,
                                                  handlerStartLocation);

            var setCatchVarInstruction = new Store(GetHandlerCatchVar(state, handler),
                                                   exceptionExpression,
                                                   Typ.FromTypeReference(state.Method.ReturnType),
                                                   handlerStartLocation);

            var pruneTrueNode = new PruneNode(handlerStartLocation,
                                              true,
                                              PruneNode.PruneNodeKind.ExceptionHandler,
                                              Prune.IfKind.Ik_switch,
                                              state.ProcDesc);

            var pruneFalseNode = new PruneNode(handlerStartLocation,
                                               false,
                                               PruneNode.PruneNodeKind.ExceptionHandler,
                                               Prune.IfKind.Ik_switch,
                                               state.ProcDesc);


            pruneTrueNode.Instructions.AddRange(new List <SilInstruction>
            {
                isInstCall, pruneTrueInstruction, setCatchVarInstruction
            });

            pruneFalseNode.Instructions.AddRange(new List <SilInstruction>
            {
                isInstCall, pruneFalseInstruction
            });
            pruneTrueNode.BlockEndOffset = state.MethodExceptionHandlers
                                           .GetBlockEndOffsetFromOffset(
                state.CurrentInstruction.Offset);
            pruneFalseNode.BlockEndOffset = state.MethodExceptionHandlers
                                            .GetBlockEndOffsetFromOffset(
                state.CurrentInstruction.Offset);
            state.Cfg.RegisterNode(pruneTrueNode);
            state.Cfg.RegisterNode(pruneFalseNode);
            return(pruneTrueNode, pruneFalseNode);
        }
예제 #16
0
        protected static void CreateCatchHandlerEntryBlock(ProgramState state,
                                                           ExceptionHandlerNode handlerNode,
                                                           CfgNode handlerEntryPredecessor,
                                                           Identifier exceptionIdentifier)
        {
            (var trueBranch, var falseBranch) = CreateExceptionTypeCheckBranchNodes(
                state, handlerNode.ExceptionHandler, exceptionIdentifier);
            handlerEntryPredecessor.Successors.Add(trueBranch);
            handlerEntryPredecessor.Successors.Add(falseBranch);

            if (!state.ExceptionHandlerToCatchVarNode.ContainsKey(handlerNode.ExceptionHandler))
            {
                state.ExceptionHandlerToCatchVarNode[handlerNode.ExceptionHandler] =
                    CreateLoadCatchVarNode(state, handlerNode.ExceptionHandler);
                // The CIL specification dictates that the exception object is on top of
                // the stack when the catch handler is entered; the first instruction of
                // the catch handler will handle the object pushed onto the stack.
                state.PushExpr(new VarExpression(exceptionIdentifier),
                               new Tptr(Tptr.PtrKind.Pk_pointer,
                                        new Tstruct("System.Object")));
                state.PushInstruction(
                    handlerNode.ExceptionHandler.HandlerStart,
                    state.ExceptionHandlerToCatchVarNode[handlerNode.ExceptionHandler].node);
            }
            (var loadCatchVarNode, _) = GetHandlerCatchVarNode(
                state, handlerNode.ExceptionHandler);
            trueBranch.Successors.Add(loadCatchVarNode);

            if (handlerNode.NextCatchBlock != null)
            {
                // Continues translation with catch handler's first instruction from
                // the handler's catch variable load node.
                CreateCatchHandlerEntryBlock(state,
                                             handlerNode.NextCatchBlock,
                                             falseBranch,
                                             exceptionIdentifier);
            }
            // Last catch handler of set; need to route control flow through the false
            // exception type-matching node.
            else
            {
                if (handlerNode.FinallyBlock != null)
                {
                    var finallyBranchNode = CreateFinallyExceptionBranchNode(
                        state, handlerNode.ExceptionHandler);
                    falseBranch.Successors
                    .Add(finallyBranchNode);
                    (var finallyLoadCatchVar, _) = GetHandlerCatchVarNode(
                        state, handlerNode.FinallyBlock);
                    finallyBranchNode.Successors.Add(finallyLoadCatchVar);
                }
                else
                {
                    var returnVariable = new LvarExpression(
                        new LocalVariable(Identifier.ReturnIdentifier, state.Method));
                    var retType  = state.Method.ReturnType.GetElementType();
                    var retInstr = new Store(
                        returnVariable,
                        new ExnExpression(new VarExpression(exceptionIdentifier)),
                        Typ.FromTypeReference(retType),
                        GetHandlerStartLocation(state,
                                                handlerNode.ExceptionHandler));
                    falseBranch.Instructions
                    .Add(retInstr);
                    falseBranch.Successors
                    .Add(state.ProcDesc.ExceptionSinkNode);
                }
            }
        }