protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { var fieldReference = instruction.Operand as FieldReference; // An object expression for an instance field and a class expression for a static // field. Expression fieldParentExpression; // The expression to set the field to. Expression expressionToStore; switch (instruction.OpCode.Code) { case Code.Stfld: (expressionToStore, _) = state.Pop(); (fieldParentExpression, _) = state.Pop(); break; case Code.Stsfld: (expressionToStore, _) = state.Pop(); fieldParentExpression = new LvarExpression( new GlobalVariable(fieldReference.DeclaringType.GetCompatibleFullName())); break; default: return(false); } var fieldStore = new Store(CreateFieldExpression(fieldParentExpression, fieldReference), expressionToStore, Typ.FromTypeReferenceNoPointer(fieldReference.DeclaringType), state.CurrentLocation); var node = AddMethodBodyInstructionsToCfg(state, fieldStore); state.PushInstruction(instruction.Next, node); return(true); }
/// TODO: Need to add is_csharp to Pvar.ml to parse CatchVar accordingly. /// <summary> /// Helper method for creating a component of the entry block to exception-handling blocks, /// in which the thrown exception stored in the CatchVar is handled. /// </summary> /// <param name="state">The program state.</param> /// <param name="handler">The exception handler for which the node is being /// created.</param> /// <returns>The node in which the caught exception variable is loaded, as well as the /// synthetic exception variable created, if the handler is finally.</returns> private static (CfgNode, LvarExpression) CreateLoadCatchVarNode(ProgramState state, ExceptionHandler handler) { LvarExpression syntheticExceptionVariable = null; var handlerStartLocation = GetHandlerStartLocation(state, handler); var exceptionIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var exceptionType = new Tptr(Tptr.PtrKind.Pk_pointer, new Tstruct("System.Object")); var catchVarLoad = new Load(exceptionIdentifier, GetHandlerCatchVar(state, handler), exceptionType, handlerStartLocation); var node = new StatementNode(location: handlerStartLocation, kind: StatementNode.StatementNodeKind.MethodBody, proc: state.ProcDesc); node.Instructions.Add(catchVarLoad); switch (handler.HandlerType) { case ExceptionHandlerType.Catch: state.AppendToPreviousNode = true; break; case ExceptionHandlerType.Finally: // In this case, the exception catch variable is stored into a synthetic // variable we create here. syntheticExceptionVariable = new LvarExpression(new LocalVariable(state.GetSyntheticVariableName(), state.Method)); var storeIntoSyntheticVariable = new Store( syntheticExceptionVariable, new VarExpression(exceptionIdentifier), exceptionType, handlerStartLocation); node.Instructions.Add(storeIntoSyntheticVariable); (var entryNode, _) = GetHandlerEntryNode(state, handler); var finallyBranchNode = CreateFinallyExceptionBranchNode(state, handler); entryNode.Successors.Add(finallyBranchNode); finallyBranchNode.Successors.Add(node); node.ExceptionNodes.Add(entryNode); state.FinallyExceptionalTranslation = true; state.PushInstruction(handler.HandlerStart, node); state.FinallyExceptionalTranslation = false; break; default: return(null, null); } state.Cfg.RegisterNode(node); return(node, syntheticExceptionVariable); }
/// <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); }
/// <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); }
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); } }
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); } }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { var field = instruction.Operand as FieldReference; // An object expression for an instance field and a class expression for a static // field. Expression fieldOwnerExpression; Typ fieldType; switch (instruction.OpCode.Code) { case Code.Ldfld: case Code.Ldflda: (var objectExpression, var objectExpressionType) = state.Pop(); // Handles the case in which the address of the owning object is on the stack. if (objectExpressionType is Address address) { // The value at the address is the parent expression, matching how the // field is initialized. var addressValueIdentifier = state.GetIdentifier( Identifier.IdentKind.Normal); state.PreviousNode.Instructions.Add( new Load(addressValueIdentifier, address.Value, Typ.FromTypeReferenceNoPointer(field.DeclaringType), state.CurrentLocation)); fieldOwnerExpression = new VarExpression(addressValueIdentifier); } // The expression represents the object itself. else { fieldOwnerExpression = objectExpression; } break; case Code.Ldsfld: case Code.Ldsflda: fieldOwnerExpression = new LvarExpression( new GlobalVariable(field.DeclaringType.GetCompatibleFullName())); break; default: return(false); } // An identifier to store the field expression. var fieldIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); fieldType = Typ.FromTypeReferenceNoPointer(field.FieldType); var fieldExpression = CreateFieldExpression(fieldOwnerExpression, field); if (instruction.OpCode.Code == Code.Ldfld || instruction.OpCode.Code == Code.Ldsfld) { state.PreviousNode.Instructions.Add(new Load(fieldIdentifier, fieldExpression, Typ.FromTypeReferenceNoPointer( field.DeclaringType), state.CurrentLocation)); state.AppendToPreviousNode = true; state.PushExpr(new VarExpression(fieldIdentifier), fieldType); } // Instruction is either Ldflda or Ldsflda. else { var fieldAddressVariableType = new Address(Tptr.PtrKind.Pk_pointer, Typ.FromTypeReferenceNoPointer( field.FieldType), fieldExpression, referenceKind: Address.ReferenceKind.Field); state.PushExpr(fieldExpression, fieldAddressVariableType); } state.PushInstruction(instruction.Next); return(true); }
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); } } }