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); } }
/// 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 a <see cref="CfgNode"/> containing instructions for memory allocation as well /// as constructor invocation. /// </summary> /// <param name="type">The SIL type to be allocate memory for.</param> /// <param name="state">Current program state.</param> /// <returns>Node with the object allocation instructions, as well as the variable which /// represents the new object.</returns> protected static (CfgNode, VarExpression) CreateObjectAllocationNode(Tptr type, ProgramState state) { var typeName = type.StripPointer().ToString(); var newObjectIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var newObjectVariable = new VarExpression(newObjectIdentifier); var callFlags = new Call.CallFlags(isVirtual: false, noReturn: false, isObjCBlock: false); var objectAllocationCall = new Call(newObjectIdentifier, type, new ConstExpression(ProcedureName.BuiltIn__new), new List <Call.CallArg> { new Call.CallArg( new SizeofExpression( type.StripPointer(), SizeofExpression.SizeofExpressionKind.exact), type) }, callFlags, state.CurrentLocation); var objectConstructorCall = new Call(state.GetIdentifier(Identifier.IdentKind.Normal), new Tvoid(), new ConstExpression(new ProcedureName(".ctor", new List <string>(), typeName, "System.Void", false)), new List <Call.CallArg> { new Call.CallArg(newObjectVariable, type) }, callFlags, state.CurrentLocation); var node = new StatementNode(state.CurrentLocation, StatementNode.StatementNodeKind.Call, state.ProcDesc, comment: $"System.Void {typeName}::.ctor()"); node.Instructions.Add(objectAllocationCall); node.Instructions.Add(objectConstructorCall); return(node, newObjectVariable); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { switch (instruction.OpCode.Code) { case Code.Ldtoken: var token = instruction.Operand; string runtimeHandleTypeString; if (token is TypeReference) { runtimeHandleTypeString = "System.RuntimeTypeHandle"; } else if (token is FieldReference) { runtimeHandleTypeString = "System.RuntimeFieldHandle"; } else if (token is MethodReference) { runtimeHandleTypeString = "System.RuntimeMethodHandle"; } else { Log.WriteWarning($"Unexpected instruction operand {instruction.Operand}"); return(false); } var runtimeHandleType = new Tptr(Tptr.PtrKind.Pk_pointer, new Tstruct(runtimeHandleTypeString)); // In keeping with how we handle structs when translating Initobj, we // initialize an object in the SIL to represent the value type. (var node, var runtimeHandleVariable) = CreateObjectAllocationNode( runtimeHandleType, state); RegisterNode(state, node); state.PushExpr(runtimeHandleVariable, runtimeHandleType); state.PushInstruction(instruction.Next, node); state.AppendToPreviousNode = true; return(true); default: return(false); } }
/// <summary> /// Creates a SIL array representation. Generates a SIL Tptr of Tarray around the input /// underlying type, with layers equal to the given <paramref name="dimensionCount"/>. /// </summary> /// <param name="arrayUnderlyingType">The type of the array's underlying elements (i.e. at /// the base dimension of the array). This typ must be encapsulated by a Tptr.</param> /// <param name="dimensionCount">Number of dimensions of the array. This must be greater /// than 0.</param> /// <param name="state">The program state.</param> /// <returns>SIL Tptr of Tarray for each dimension.</returns> /// <remarks>An example two-dimensional output with <paramref name="arrayUnderlyingType"/> /// object* would look like [[object*]*]*.</remarks> private Typ CreateArrayType(Typ arrayUnderlyingType, int dimensionCount, ProgramState state) { if (dimensionCount <= 0) { throw new ArgumentException( state.GetStateDebugInformation(dimensionCount)); } if (!(arrayUnderlyingType is Tptr)) { throw new ArgumentException( state.GetStateDebugInformation(arrayUnderlyingType)); } var nextDimType = arrayUnderlyingType; for (var i = 0; i < dimensionCount; i++) { nextDimType = new Tptr(Tptr.PtrKind.Pk_pointer, new Tarray(nextDimType)); } return(nextDimType); }
protected static CfgNode CreateFinallyExceptionExitNode(ProgramState state, ExceptionHandler handler) { (_, var syntheticExceptionVariable) = GetHandlerCatchVarNode(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, syntheticExceptionVariable, exceptionType, GetHandlerEndLocation(state, handler)); var exceptionReturnNode = CreateExceptionReturnNode( state, new VarExpression(exceptionIdentifier), GetHandlerEndLocation(state, handler)); exceptionReturnNode.Instructions.Insert(0, catchVarLoad); state.Cfg.RegisterNode(exceptionReturnNode); state.PreviousNode.Successors.Add(exceptionReturnNode); return(exceptionReturnNode); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { Tptr arrayTypeWithPtr; Tarray arrayTypeNoPtr; switch (instruction.OpCode.Code) { case Code.Ldelem_Any: case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: (var arrayIndex, _) = state.Pop(); (var array, var type) = state.Pop(); if (!(array is VarExpression arrayVar) || !(type.StripPointer() is Tarray)) { Log.WriteParserWarning(array, instruction, state); return(false); } // Type is either Tarray or a Tptr with a Tarray type underlying it. if (type is Tarray) { arrayTypeWithPtr = new Tptr(Tptr.PtrKind.Pk_pointer, type); arrayTypeNoPtr = (Tarray)type; } else if (type is Tptr) { arrayTypeWithPtr = (Tptr)type; arrayTypeNoPtr = (Tarray)type.StripPointer(); } else { Log.WriteParserWarning(type, instruction, state); return(false); } var derefArray = CreateDereference(arrayVar, arrayTypeWithPtr, state); var tempIdentifier = state.GetIdentifier(Identifier.IdentKind.Normal); var arrayIndexLoad = new Load(identifierAssignedTo: tempIdentifier, lvalue: new LindexExpression( array, arrayIndex), type: arrayTypeNoPtr.ContentType, location: state.CurrentLocation); var newNode = AddMethodBodyInstructionsToCfg(state, derefArray, arrayIndexLoad); state.PushExpr(new VarExpression(tempIdentifier), arrayTypeNoPtr.ContentType); state.AppendToPreviousNode = true; state.PushInstruction(instruction.Next, newNode); return(true); } return(false); }
protected override bool ParseCilInstructionInternal(Instruction instruction, ProgramState state) { ConstExpression constExp = null; Typ type = null; switch (instruction.OpCode.Code) { case Code.Ldc_I4_M1: (constExp, type) = MakeInt(-1); break; case Code.Ldc_I4: (constExp, type) = MakeInt((int)instruction.Operand); break; case Code.Ldc_I4_S: (constExp, type) = MakeInt((sbyte)instruction.Operand); break; case Code.Ldc_I4_0: (constExp, type) = MakeInt(0); break; case Code.Ldc_I4_1: (constExp, type) = MakeInt(1); break; case Code.Ldc_I4_2: (constExp, type) = MakeInt(2); break; case Code.Ldc_I4_3: (constExp, type) = MakeInt(3); break; case Code.Ldc_I4_4: (constExp, type) = MakeInt(4); break; case Code.Ldc_I4_5: (constExp, type) = MakeInt(5); break; case Code.Ldc_I4_6: (constExp, type) = MakeInt(6); break; case Code.Ldc_I4_7: (constExp, type) = MakeInt(7); break; case Code.Ldc_I4_8: (constExp, type) = MakeInt(8); break; case Code.Ldc_I8: (constExp, _) = MakeInt((long)instruction.Operand); type = new Tint(Tint.IntKind.ILongLong); break; case Code.Ldc_R4: constExp = new ConstExpression((float)instruction.Operand); type = new Tfloat(Tfloat.FloatKind.FFloat); break; case Code.Ldc_R8: constExp = new ConstExpression((double)instruction.Operand); type = new Tfloat(Tfloat.FloatKind.FDouble); break; case Code.Ldstr: constExp = new ConstExpression((string)instruction.Operand); type = new Tptr(Tptr.PtrKind.Pk_pointer, new Tstruct("System.String")); break; default: return(false); } state.PushExpr(constExp, type); state.PushInstruction(instruction.Next); return(true); }