Esempio n. 1
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var fallthroughBlock = context.FallThroughBlock;

            var op1 = importer.PopExpression();

            var targets   = instruction.Operand as Instruction[];
            var jumpTable = new List <string>(targets?.Length ?? 0);

            if (targets != null)
            {
                foreach (var target in targets)
                {
                    var targetBlock = importer.BasicBlocks[(int)target.Offset];
                    jumpTable.Add(targetBlock.Label);
                    importer.ImportFallThrough(targetBlock);
                }
            }

            var switchNode = new SwitchEntry(op1, jumpTable);

            importer.ImportAppendTree(switchNode);

            // TODO: Can this ever be null?
            if (fallthroughBlock != null)
            {
                importer.ImportFallThrough(fallthroughBlock);
            }

            context.StopImporting = true;
        }
Esempio n. 2
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var fieldDef = instruction.OperandAs <FieldDef>();

            var value = importer.PopExpression();
            var addr  = importer.PopExpression();

            var kind = fieldDef.FieldType.GetStackValueKind();

            if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ValueType && value.Kind != StackValueKind.NativeInt)
            {
                throw new NotSupportedException($"Storing to field of type {value.Kind} not supported");
            }

            // Ensure fields have all offsets calculated
            if (fieldDef.FieldOffset == null)
            {
                fieldDef.DeclaringType.ToTypeSig().GetExactSize();
            }

            // TODO: Can this be removed
            var fieldSize   = fieldDef.FieldType.GetExactSize();
            var fieldOffset = fieldDef.FieldOffset ?? 0;

            importer.ImportAppendTree(new StoreIndEntry(addr, value, WellKnownType.Int32, fieldOffset, fieldSize));
        }
Esempio n. 3
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var retNode = new ReturnEntry();

            if (context.Method.HasReturnType)
            {
                var returnType = context.Method.ReturnType;

                var value = importer.PopExpression();

                if (returnType.IsStruct())
                {
                    // Record return buffer argument index
                    // so that code gen can generate code to
                    // copy struct on top of stack to the
                    // return buffer.
                    retNode.ReturnBufferArgIndex = context.Method.HasThis ? 1 : 0;
                    retNode.ReturnTypeExactSize  = returnType.GetExactSize();
                }
                else if (value.Kind != StackValueKind.Int32)
                {
                    throw new NotSupportedException($"Unsupported Return type {value.Kind}");
                }

                retNode.Return = value;
            }
            importer.ImportAppendTree(retNode);
            context.StopImporting = true;
        }
Esempio n. 4
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op2 = importer.PopExpression();

            if (op2.Kind != StackValueKind.Int32)
            {
                throw new NotSupportedException("Boolean comparisons only supported using int as underlying type");
            }
            StackEntry op1;
            Operation  op = Operation.Eq;

            switch (instruction.OpCode.Code)
            {
            case Code.Cgt: op = Operation.Gt; break;

            case Code.Cgt_Un: op = Operation.Gt; break;

            case Code.Clt: op = Operation.Lt; break;

            case Code.Clt_Un: op = Operation.Lt; break;
            }
            op1 = importer.PopExpression();
            if (op2.Kind != StackValueKind.Int32)
            {
                throw new NotSupportedException("Boolean comparisons only supported using int as underlying type");
            }
            op1 = new BinaryOperator(op, isComparison: true, op1, op2, StackValueKind.Int32);
            importer.PushExpression(op1);
        }
Esempio n. 5
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op1 = importer.PopExpression();
            var op2 = op1.Duplicate();

            importer.PushExpression(op1);
            importer.PushExpression(op2);
        }
Esempio n. 6
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var type = GetWellKnownType(instruction.OpCode.Code);
            var addr = importer.PopExpression();
            // TODO: Can this be optimised for I1 & I2??
            var node = new IndirectEntry(addr, StackValueKind.Int32, null); // type.GetWellKnownTypeSize());

            importer.PushExpression(node);
        }
Esempio n. 7
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            int index         = GetIndex(instruction);
            var localNumber   = importer.ParameterCount + index;
            var localVariable = importer.LocalVariableTable[localNumber];
            var node          = new LocalVariableEntry(localNumber, localVariable.Kind, localVariable.ExactSize);

            importer.PushExpression(node);
        }
Esempio n. 8
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var index  = GetIndex(instruction);
            var lclNum = MapIlArgNum(index, importer.ReturnBufferArgIndex);

            var argument = importer.LocalVariableTable[lclNum];
            var node     = new LocalVariableEntry(lclNum, argument.Kind, argument.ExactSize);

            importer.PushExpression(node);
        }
Esempio n. 9
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op1 = importer.PopExpression();

            // Need to spill result removed from stack to a temp that will never be used
            var lclNum = importer.GrabTemp(op1.Kind, op1.ExactSize);
            var node   = new StoreLocalVariableEntry(lclNum, false, op1);

            // ctor has no return type so just append the tree
            importer.ImportAppendTree(node);
        }
Esempio n. 10
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var value = importer.PopExpression();

            if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ObjRef)
            {
                throw new NotSupportedException("Storing to argument other than short, int32 or object refs not supported yet");
            }
            var node = new StoreLocalVariableEntry((instruction.OperandAs <Parameter>()).Index, true, value);

            importer.ImportAppendTree(node);
        }
Esempio n. 11
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            int index = GetIndex(instruction);

            var value = importer.PopExpression();

            if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ObjRef && value.Kind != StackValueKind.ValueType && value.Kind != StackValueKind.NativeInt)
            {
                throw new NotSupportedException("Storing variables other than short, int32 ,object refs, or valuetypes not supported yet");
            }
            var localNumber = importer.ParameterCount + index;
            var node        = new StoreLocalVariableEntry(localNumber, false, value);

            importer.ImportAppendTree(node, true);
        }
Esempio n. 12
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var value = importer.PopExpression();
            var addr  = importer.PopExpression();

            if (value.Kind != StackValueKind.Int32)
            {
                throw new NotSupportedException();
            }

            // TODO: Can this be optimised to copy less data if Stind_I1, Stind_I2???
            WellKnownType type      = WellKnownType.Int32;
            int           exactSize = type.GetWellKnownTypeSize();

            importer.ImportAppendTree(new StoreIndEntry(addr, value, type, fieldOffset: 0, exactSize));
        }
Esempio n. 13
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var fieldDefOrRef = instruction.Operand as IField;
            var fieldDef      = fieldDefOrRef.ResolveFieldDef();

            // Ensure fields have all offsets calculated
            if (fieldDef.FieldOffset == null)
            {
                fieldDef.DeclaringType.ToTypeSig().GetExactSize();
            }

            var fieldOffset = fieldDef.FieldOffset ?? 0;

            var obj = importer.PopExpression();

            if (obj.Kind == StackValueKind.ValueType)
            {
                if (obj is LocalVariableEntry)
                {
                    obj = new LocalVariableAddressEntry((obj.As <LocalVariableEntry>()).LocalNumber);
                }
                else if (obj is IndirectEntry)
                {
                    // If the object is itself an IndirectEntry e.g. resulting from a Ldfld
                    // then we should merge the Ldfld's together

                    // e.g. Ldfld SimpleVector::N
                    //      Ldfld Nested::Length
                    // will get converted into a single IndirectEntry node with the field offset
                    // being the combination of the field offsets for N and Length

                    var previousIndirect = obj.As <IndirectEntry>();
                    fieldOffset = previousIndirect.Offset + fieldOffset;
                    obj         = previousIndirect.Op1;
                }
            }

            if (obj.Kind != StackValueKind.ObjRef && obj.Kind != StackValueKind.ByRef && obj.Kind != StackValueKind.NativeInt)
            {
                throw new NotImplementedException($"LoadFieldImporter does not support {obj.Kind}");
            }

            var kind = fieldDef.FieldType.GetStackValueKind();
            var node = new IndirectEntry(obj, kind, fieldDef.FieldType.GetExactSize(), fieldOffset);

            importer.PushExpression(node);
        }
Esempio n. 14
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var fieldDefOrRef = instruction.Operand as IField;
            var fieldDef      = fieldDefOrRef.ResolveFieldDef();

            var obj = importer.PopExpression();


            if (obj.Kind != StackValueKind.ObjRef && obj.Kind != StackValueKind.ByRef)
            {
                throw new NotImplementedException($"LoadFieldImporter does not support {obj.Kind}");
            }

            var node = new FieldAddressEntry(fieldDef.Name, obj, fieldDef?.FieldOffset ?? 0);

            importer.PushExpression(node);
        }
Esempio n. 15
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op2 = importer.PopExpression();
            var op1 = importer.PopExpression();

            // If one of the values is a native int then cast the other to be native int too
            if (op1.Kind == StackValueKind.NativeInt && op2.Kind == StackValueKind.Int32)
            {
                op2 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op2, op1.Kind);
            }
            else if (op1.Kind == StackValueKind.Int32 && op2.Kind == StackValueKind.NativeInt)
            {
                op1 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op1, op2.Kind);
            }

            // StackValueKind is carefully ordered to make this work
            StackValueKind kind;

            kind = op1.Kind > op2.Kind ? op1.Kind : op2.Kind;

            if (kind != StackValueKind.Int32 && kind != StackValueKind.NativeInt)
            {
                throw new NotSupportedException($"Binary operation on type {kind} not supported");
            }

            Operation binaryOp;

            switch (instruction.OpCode.Code)
            {
            case Code.Mul_Ovf_Un:
                // For now this maps to standard multiplication as we have no exception support
                binaryOp = Operation.Mul;
                break;

            default:
                binaryOp = Operation.Add + (instruction.OpCode.Code - Code.Add);
                break;
            }

            var binaryExpr = new BinaryOperator(binaryOp, isComparison: false, op1, op2, kind);

            importer.PushExpression(binaryExpr);
        }
Esempio n. 16
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var methodDefOrRef = instruction.Operand as IMethodDefOrRef;
            var methodToCall   = methodDefOrRef.ResolveMethodDefThrow();

            var declType = methodToCall.DeclaringType;

            var objType = declType.ToTypeSig();
            var objKind = objType.GetStackValueKind();
            var objSize = objType.GetExactSize();

            if (declType.IsValueType)
            {
                // Allocate memory on the stack for the value type as a temp local variable
                var lclNum        = importer.GrabTemp(objKind, objSize);
                var newObjThisPtr = new LocalVariableAddressEntry(lclNum);

                // Call the valuetype constructor
                CallImporter.ImportCall(instruction, context, importer, newObjThisPtr);

                var node = new LocalVariableEntry(lclNum, objKind, objSize);
                importer.PushExpression(node);
            }
            else
            {
                // Allocate memory for object
                var op1 = new AllocObjEntry((int)declType.ClassSize, objKind);

                // Store allocated memory address into a temp local variable
                var lclNum = importer.GrabTemp(objKind, objSize);
                var asg    = new StoreLocalVariableEntry(lclNum, false, op1);
                importer.ImportAppendTree(asg);

                // Call the constructor
                var newObjThisPtr = new LocalVariableEntry(lclNum, objKind, objSize);
                CallImporter.ImportCall(instruction, context, importer, newObjThisPtr);

                // Push a local variable entry corresponding to the object here
                var node = new LocalVariableEntry(lclNum, objKind, objSize);
                importer.PushExpression(node);
            }
        }
Esempio n. 17
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op2 = importer.PopExpression();
            var op1 = importer.PopExpression(); // operand to be shifted

            if (op1.Kind != StackValueKind.Int32 && op1.Kind != StackValueKind.NativeInt)
            {
                throw new NotSupportedException($"Shift operation on type {op1.Kind} not supported");
            }

            if (op2.Kind != StackValueKind.Int32 && op2.Kind != StackValueKind.NativeInt)
            {
                throw new NotSupportedException($"Shift operation with amount of type {op2.Kind} not supported");
            }

            var shiftOp    = Operation.Lsh + (instruction.OpCode.Code - Code.Shl);
            var binaryExpr = new BinaryOperator(shiftOp, isComparison: false, op1, op2, op1.Kind);

            importer.PushExpression(binaryExpr);
        }
Esempio n. 18
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var op2 = importer.PopExpression().As <Int32ConstantEntry>();

            if (op2.Kind != StackValueKind.Int32)
            {
                throw new NotSupportedException("Localloc requires int size");
            }

            var allocSize = op2.Value;

            // Ensure we don't allocate less than each stack entry size
            allocSize = RoundUp(allocSize, 4);

            // TODO: Is Unknown the right kind to use??
            var lclNum = importer.GrabTemp(StackValueKind.Unknown, allocSize);

            var op1 = new LocalVariableAddressEntry(lclNum);

            importer.PushExpression(op1);
        }
Esempio n. 19
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            WellKnownType wellKnownType;

            switch (instruction.OpCode.Code)
            {
            case Code.Conv_I4: wellKnownType = WellKnownType.Int32; break;

            case Code.Conv_U4: wellKnownType = WellKnownType.UInt32; break;

            case Code.Conv_I2: wellKnownType = WellKnownType.Int16; break;

            case Code.Conv_U2: wellKnownType = WellKnownType.UInt16; break;

            case Code.Conv_I1: wellKnownType = WellKnownType.SByte; break;

            case Code.Conv_U1: wellKnownType = WellKnownType.Byte; break;

            case Code.Conv_U: wellKnownType = WellKnownType.UIntPtr; break;

            case Code.Conv_I: wellKnownType = WellKnownType.IntPtr; break;

            default: throw new NotImplementedException($"Conversion type not supported for opcode {instruction.OpCode.Code}");
            }

            var op1 = importer.PopExpression();

            // Work out if a cast is required
            if ((op1.Kind == StackValueKind.Int32 && wellKnownType == Common.TypeSystem.WellKnownType.UInt16) ||
                (op1.Kind == StackValueKind.Int32 && wellKnownType == Common.TypeSystem.WellKnownType.Int16) ||
                (op1.Kind == StackValueKind.Int32 && wellKnownType == WellKnownType.Byte) ||
                (op1.Kind == StackValueKind.Int32 && wellKnownType == WellKnownType.SByte))
            {
                op1 = new CastEntry(wellKnownType, op1, op1.Kind);
            }

            importer.PushExpression(op1);
        }
Esempio n. 20
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     importer.PushExpression(new LocalVariableAddressEntry(importer.ParameterCount + (instruction.OperandAs <Local>()).Index));
 }
Esempio n. 21
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     // TODO: Need to implement this
     importer.PopExpression();
 }
Esempio n. 22
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     importer.PushExpression(new Int32ConstantEntry(checked ((int)GetValue(instruction))));
 }
Esempio n. 23
0
        private static bool ImportIntrinsicCall(MethodDef methodToCall, IList <StackEntry> arguments, IILImporterProxy importer)
        {
            // Not yet implemented methods with non void return type
            if (methodToCall.HasReturnType)
            {
                throw new NotSupportedException();
            }

            // Map method name to string that code generator will understand
            var targetMethodName = "";

            switch (methodToCall.Name)
            {
            // TODO: Suspect this won't stay as an intrinsic but at least we have the mechanism for instrincs
            case "Write":
                if (IsTypeName(methodToCall, "System", "Console"))
                {
                    var argtype = methodToCall.Parameters[0].Type;
                    targetMethodName = argtype.FullName switch
                    {
                        "System.String" => "WriteString",
                        "System.Int32" => "WriteInt32",
                        "System.UInt32" => "WriteUInt32",
                        "System.Char" => "WriteChar",
                        _ => throw new NotSupportedException(),
                    };
                }
                break;

            default:
                return(false);
            }

            var callNode = new IntrinsicEntry(targetMethodName, arguments, StackValueKind.Unknown);

            importer.ImportAppendTree(callNode);

            return(true);
        }
Esempio n. 24
0
        public static void ImportCall(Instruction instruction, ImportContext context, IILImporterProxy importer, StackEntry?newObjThis = null)
        {
            var methodDefOrRef = instruction.Operand as IMethodDefOrRef;
            var methodToCall   = methodDefOrRef.ResolveMethodDefThrow();

            var arguments     = new List <StackEntry>();
            var firstArgIndex = newObjThis != null ? 1 : 0;

            for (var i = firstArgIndex; i < methodToCall.Parameters.Count; i++)
            {
                var argument = importer.PopExpression();
                arguments.Add(argument);
            }
            // Add the this pointer if required, e.g. if part of newobj
            if (newObjThis != null)
            {
                arguments.Add(newObjThis);
            }
            arguments.Reverse();

            // Intrinsic calls
            if (methodToCall.IsIntrinsic())
            {
                if (!ImportIntrinsicCall(methodToCall, arguments, importer))
                {
                    throw new NotSupportedException("Unknown intrinsic");
                }
                return;
            }

            string targetMethod;

            if (methodToCall.IsPinvokeImpl)
            {
                targetMethod = methodToCall.ImplMap.Name;
            }
            else
            {
                targetMethod = context.NameMangler.GetMangledMethodName(methodToCall);
            }

            int returnBufferArgIndex = 0;
            var returnType           = methodToCall.ReturnType;

            if (methodToCall.HasReturnType)
            {
                if (returnType.IsStruct())
                {
                    returnBufferArgIndex = FixupCallStructReturn(returnType, arguments, importer, methodToCall.HasThis);
                }
            }

            int?returnTypeSize = methodToCall.HasReturnType ? returnType.GetExactSize() : null;

            var callNode = new CallEntry(targetMethod, arguments, returnType.GetStackValueKind(), returnTypeSize);

            if (!methodToCall.HasReturnType)
            {
                importer.ImportAppendTree(callNode);
            }
            else
            {
                if (returnType.IsStruct())
                {
                    importer.ImportAppendTree(callNode);

                    // Load return buffer to stack
                    var loadTemp = new LocalVariableEntry(returnBufferArgIndex, returnType.GetStackValueKind(), returnType.GetExactSize());
                    importer.PushExpression(loadTemp);
                }
                else
                {
                    importer.PushExpression(callNode);
                }
            }
        }
Esempio n. 25
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     importer.PushExpression(new StringConstantEntry(instruction.OperandAs <string>()));
 }
Esempio n. 26
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var unaryOp = Operation.Neg + (instruction.OpCode.Code - Code.Neg);

            importer.PushExpression(new UnaryOperator(unaryOp, importer.PopExpression()));
        }
Esempio n. 27
0
        public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
        {
            var code = instruction.OpCode.Code;

            switch (code)
            {
            case Code.Br_S:
            case Code.Blt_S:
            case Code.Bgt_S:
            case Code.Ble_S:
            case Code.Bge_S:
            case Code.Beq_S:
            case Code.Bne_Un_S:
            case Code.Brfalse_S:
            case Code.Brtrue_S:
                code += (Code.Br - Code.Br_S);
                break;
            }
            var target = instruction.OperandAs <Instruction>();

            var targetBlock      = importer.BasicBlocks[(int)target.Offset];
            var fallthroughBlock = (code != Code.Br) ? context.FallThroughBlock : null;

            if (code != Code.Br)
            {
                var op2 = importer.PopExpression();
                if (op2.Kind != StackValueKind.Int32 && op2.Kind != StackValueKind.NativeInt)
                {
                    throw new NotSupportedException("Boolean comparisons only supported using int and nativeint as underlying type");
                }

                StackEntry op1;
                Operation  op;
                if (code != Code.Brfalse && code != Code.Brtrue)
                {
                    op1 = importer.PopExpression();
                    op  = Operation.Eq + (code - Code.Beq);

                    // If one of the values is a native int then cast the other to be native int too
                    if (op1.Kind == StackValueKind.NativeInt && op2.Kind == StackValueKind.Int32)
                    {
                        op2 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op2, op1.Kind);
                    }
                    else if (op1.Kind == StackValueKind.Int32 && op2.Kind == StackValueKind.NativeInt)
                    {
                        op1 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op1, op2.Kind);
                    }
                }
                else
                {
                    op1 = new Int32ConstantEntry(0);
                    op  = (code == Code.Brfalse) ? Operation.Eq : Operation.Ne;
                }
                op1 = new BinaryOperator(op, isComparison: true, op1, op2, op1.Kind);
                importer.ImportAppendTree(new JumpTrueEntry(targetBlock.Label, op1));
            }
            else
            {
                importer.ImportAppendTree(new JumpEntry(targetBlock.Label));
            }

            // Fall through handling
            importer.ImportFallThrough(targetBlock);

            if (fallthroughBlock != null)
            {
                importer.ImportFallThrough(fallthroughBlock);
            }

            context.StopImporting = true;
        }
Esempio n. 28
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     ImportCall(instruction, context, importer);
 }
Esempio n. 29
0
        static private int FixupCallStructReturn(TypeSig returnType, List <StackEntry> arguments, IILImporterProxy importer, bool hasThis)
        {
            // Create temp
            var lclNum          = importer.GrabTemp(returnType.GetStackValueKind(), returnType.GetExactSize());
            var returnBufferPtr = new LocalVariableAddressEntry(lclNum);

            // Ensure return buffer parameter goes after the this parameter if present
            var returnBufferArgPos = hasThis ? 1 : 0;

            arguments.Insert(returnBufferArgPos, returnBufferPtr);

            return(lclNum);
        }
Esempio n. 30
0
 public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer)
 {
     // Nothing to do
 }