예제 #1
0
        public void VisitInstructionExpression(CilInstructionExpression expression)
        {
            if (expression.Instructions.Count == 1 &&
                IsArrayMemberAccess(expression.Instructions[0], out var method))
            {
                var arrayExpr = expression.Arguments[0];

                if (arrayExpr.ExpressionType is SzArrayTypeSignature arrayType)
                {
                    if (IsArrayGetLength(method))
                    {
                        ReplaceWithLdlen(expression, arrayType);
                    }
                    else if (IsArrayGetValue(method))
                    {
                        ReplaceWithLdelem(expression, arrayType);
                    }
                    else if (IsArraySetValue(method))
                    {
                        ReplaceWithStelem(expression, arrayType);
                    }
                    else if (IsArrayAddress(method))
                    {
                        ReplaceWithLdelema(expression, arrayType);
                    }
                }
            }

            foreach (var argument in expression.Arguments.ToArray())
            {
                argument.AcceptVisitor(this);
            }
        }
예제 #2
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var annotation = (LdftnAnnotation)expression.Annotation;

            ICallableMemberReference method;

            if (!annotation.IsIntraLinked)
            {
                method = annotation.Method;
            }
            else
            {
                method = context.ExportResolver.ResolveMethod(annotation.Function.EntrypointAddress);
                if (method == null)
                {
                    throw new RecompilerException(
                              $"Could not resolve function_{annotation.Function.EntrypointAddress:X4} to a physical method.");
                }
            }

            var result = new CilInstructionExpression(CilOpCodes.Ldftn, method)
            {
                ExpressionType = context.TargetImage.TypeSystem.IntPtr
            };

            return(result);
        }
예제 #3
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var annotation = (LdftnAnnotation)expression.Annotation;

            IMethodDescriptor method;

            if (!annotation.IsIntraLinked)
            {
                method = annotation.Method;
            }
            else
            {
                method = context.ExportResolver.ResolveMethod(annotation.Function.EntrypointAddress);
                if (method == null)
                {
                    throw new RecompilerException(
                              $"Could not resolve function_{annotation.Function.EntrypointAddress:X4} to a physical method.");
                }
            }

            var result = new CilInstructionExpression(CilOpCodes.Ldftn, method)
            {
                ExpressionType = context.TargetModule.CorLibTypeFactory.IntPtr
            };

            if (annotation.IsVirtual)
            {
                var callingObject = (CilExpression)expression.Arguments[expression.Arguments.Count - 1]
                                    .AcceptVisitor(context.Recompiler);
                result.Instructions[0].OpCode = CilOpCodes.Ldvirtftn;
                result.Arguments.Add(callingObject);
            }

            return(result);
        }
예제 #4
0
        public virtual bool VisitInstructionExpression(CilInstructionExpression expression)
        {
            bool changed = false;

            foreach (var argument in expression.Arguments.ToArray())
            {
                changed |= argument.AcceptVisitor(this);
            }
            return(changed);
        }
예제 #5
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var metadata = (FieldAnnotation)expression.Annotation;

            // Enter generic context for member.
            context.EnterMember(metadata.Field);

            var  fieldDef = metadata.Field.Resolve();
            bool hasThis  = !fieldDef?.IsStatic ?? metadata.Field.Signature.HasThis;

            // Select opcode and expression type.
            var       expressionType = metadata.Field.Signature.FieldType;
            CilOpCode opCode;

            if (metadata.IsAddress)
            {
                expressionType = new ByReferenceTypeSignature(expressionType);
                opCode         = hasThis ? CilOpCodes.Ldflda : CilOpCodes.Ldsflda;
            }
            else
            {
                opCode = hasThis ? CilOpCodes.Ldfld : CilOpCodes.Ldsfld;
            }

            // Construct CIL expression.
            var result = new CilInstructionExpression(opCode, metadata.Field)
            {
                ExpressionType = expressionType.InstantiateGenericTypes(context.GenericContext)
            };

            if (hasThis)
            {
                // Recompile object expression if field is an instance field.
                var objectExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 1]
                                       .AcceptVisitor(context.Recompiler);

                var objectType = metadata.Field.DeclaringType
                                 .ToTypeSignature()
                                 .InstantiateGenericTypes(context.GenericContext);

                if (metadata.IsAddress)
                {
                    objectType = new ByReferenceTypeSignature(objectType);
                }

                objectExpression.ExpectedType = objectType;
                result.Arguments.Add(objectExpression);
            }

            // Leave generic context.
            context.ExitMember();

            return(result);
        }
예제 #6
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var annotation = (ThrowAnnotation)expression.Annotation;

            var argument = (CilExpression)expression.Arguments[2].AcceptVisitor(context.Recompiler);

            argument.ExpectedType = context.ReferenceImporter.ImportType(typeof(Exception));

            var result = new CilInstructionExpression(annotation.IsRethrow ? CilOpCodes.Rethrow :  CilOpCodes.Throw,
                                                      null,
                                                      argument);

            return(result);
        }
예제 #7
0
        private void ReplaceWithLdlen(CilInstructionExpression expression, SzArrayTypeSignature arrayType)
        {
            var arrayExpr = expression.Arguments[0];

            arrayExpr.ExpectedType = arrayType;

            var arrayLengthExpr = new CilInstructionExpression(CilOpCodes.Ldlen, null,
                                                               (CilExpression)arrayExpr.Remove())
            {
                ExpressionType = _context.TargetModule.CorLibTypeFactory.Int32
            };

            expression.ReplaceWith(arrayLengthExpr);
        }
예제 #8
0
        public override bool VisitInstructionExpression(CilInstructionExpression expression)
        {
            if (expression.Instructions.Count == 1 &&
                expression.Instructions[0].OpCode.Code == CilCode.Unbox_Any &&
                IsBoxExpression(expression.Arguments[0], out var argument, out var boxedType) &&
                expression.Instructions[0].Operand is ITypeDefOrRef type &&
                type.FullName == boxedType.FullName)
            {
                argument.ExpectedType = expression.ExpectedType;
                expression.ReplaceWith(argument.Remove());
            }

            return(base.VisitInstructionExpression(expression));
        }
예제 #9
0
        private void ReplaceWithLdlen(CilInstructionExpression expression, SzArrayTypeSignature arrayType)
        {
            var arrayExpr = expression.Arguments[0];

            arrayExpr.ExpectedType = arrayType;

            var arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Ldlen, null,
                                                             (CilExpression)arrayExpr.Remove())
            {
                ExpressionType = arrayType.BaseType
            };

            expression.ReplaceWith(arrayLoadExpr);
        }
예제 #10
0
        public virtual CilExpression Translate(RecompilerContext context, ILInstructionExpression expression)
        {
            if (!SupportedOpCodes.Contains(expression.OpCode.Code))
            {
                throw new NotSupportedException();
            }

            var result = new CilInstructionExpression();

            // Copy instructions
            foreach (var instruction in NewInstructions)
            {
                result.Instructions.Add(new CilInstruction(0, instruction.OpCode, instruction.Operand));
            }

            // Create arguments
            for (var i = 0; i < expression.Arguments.Count; i++)
            {
                // Convert argument.
                var argument    = expression.Arguments[i];
                var cilArgument = (CilExpression)argument.AcceptVisitor(context.Recompiler);

                // Check type.
                cilArgument.ExpectedType = expression.OpCode.StackBehaviourPop
                                           .GetArgumentType(i)
                                           .ToMetadataType(context.TargetImage);

                // Convert if necessary, and add to argument list.
                result.Arguments.Add(cilArgument);
            }

            // Determine expression type from opcode.
            if (expression.OpCode.StackBehaviourPush != ILStackBehaviour.None)
            {
                result.ExpressionType = expression.OpCode.StackBehaviourPush
                                        .GetResultType()
                                        .ToMetadataType(context.TargetImage);
            }

            result.ShouldEmitFlagsUpdate = expression.IsFlagDataSource;
            if (expression.IsFlagDataSource)
            {
                result.AffectedFlags       = expression.OpCode.AffectedFlags;
                result.InvertedFlagsUpdate = InvertedFlagsUpdate;
            }

            return(result);
        }
예제 #11
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var metadata  = (FieldAnnotation)expression.Annotation;
            var fieldType = metadata.Field.Signature.FieldType;

            // Enter generic context.
            context.EnterMember(metadata.Field);

            var  fieldDef = metadata.Field.Resolve();
            bool hasThis  = !fieldDef?.IsStatic ?? metadata.Field.Signature.HasThis;

            // Construct CIL expression.
            var result = new CilInstructionExpression(hasThis ? CilOpCodes.Stfld : CilOpCodes.Stsfld, metadata.Field);

            if (hasThis)
            {
                // Recompile object expression if field is an instance field.
                var objectExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 2]
                                       .AcceptVisitor(context.Recompiler);

                var objectType = metadata.Field.DeclaringType
                                 .ToTypeSignature()
                                 .InstantiateGenericTypes(context.GenericContext);

                // Struct members can only be accessed when the object is passed on by reference.
                if (metadata.Field.DeclaringType.IsValueType)
                {
                    objectType = new ByReferenceTypeSignature(objectType);
                }

                objectExpression.ExpectedType = objectType;
                result.Arguments.Add(objectExpression);
            }

            // Recompile value.
            var valueExpression = (CilExpression)expression.Arguments[expression.Arguments.Count - 1]
                                  .AcceptVisitor(context.Recompiler);

            valueExpression.ExpectedType = fieldType.InstantiateGenericTypes(context.GenericContext);
            result.Arguments.Add(valueExpression);

            // Exit generic context.
            context.ExitMember();

            return(result);
        }
예제 #12
0
        public IList <CilInstruction> VisitInstructionExpression(CilInstructionExpression expression)
        {
            var result = new List <CilInstruction>();

            // Sanity check for expression validity.
            ValidateExpression(expression);

            // Decide whether to emit FL updates or not.
            if (expression.ShouldEmitFlagsUpdate)
            {
                var first = expression.Arguments[0];

                switch (expression.Arguments.Count)
                {
                case 1:
                    result.AddRange(_context.BuildFlagAffectingExpression32(
                                        first.AcceptVisitor(this),
                                        expression.Instructions,
                                        _context.Constants.GetFlagMask(expression.AffectedFlags),
                                        expression.ExpressionType != null));
                    break;

                case 2:
                    var second = expression.Arguments[1];

                    result.AddRange(_context.BuildFlagAffectingExpression32(
                                        first.AcceptVisitor(this),
                                        second.AcceptVisitor(this),
                                        expression.Instructions,
                                        _context.Constants.GetFlagMask(expression.AffectedFlags),
                                        expression.InvertedFlagsUpdate,
                                        expression.ExpressionType != null));
                    break;
                }
            }
            else
            {
                foreach (var argument in expression.Arguments)
                {
                    result.AddRange(argument.AcceptVisitor(this));
                }
                result.AddRange(expression.Instructions);
            }

            return(result);
        }
예제 #13
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var annotation = (TypeAnnotation)expression.Annotation;

            var argument = (CilExpression)expression.Arguments[expression.Arguments.Count - 1]
                           .AcceptVisitor(context.Recompiler);

            argument.ExpectedType = new ByReferenceTypeSignature(
                context.ReferenceImporter.ImportTypeSignature(annotation.Type.ToTypeSignature()));

            var result = new CilInstructionExpression(CilOpCodes.Initobj, annotation.Type, argument)
            {
                ExpressionType = null
            };

            return(result);
        }
예제 #14
0
        public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression)
        {
            var callMetadata = (CallAnnotation)expression.Annotation;

            // Convert entrypoint address to physical method def.
            var method    = context.ExportResolver.ResolveMethod(callMetadata.Function.EntrypointAddress);
            var methodSig = ((MethodSignature)method.Signature);

            // Create call instruction.
            CilExpression result = new CilInstructionExpression(CilOpCodes.Call, method,
                                                                context.RecompileCallArguments(method, expression.Arguments.Skip(1).ToArray(), VMECallOpCode.CALL))
            {
                ExpressionType = methodSig.ReturnType
            };

            // Make sure the resulting object is converted to an unsigned integer if necessary.
            return(result);
        }
예제 #15
0
        private void ReplaceWithLdelema(CilInstructionExpression expression, SzArrayTypeSignature arrayType)
        {
            var arrayExpr = expression.Arguments[0];
            var indexExpr = expression.Arguments[1];

            arrayExpr.ExpectedType = arrayType;
            var elementTypeRef = _context.ReferenceImporter
                                 .ImportType(arrayType.BaseType.ToTypeDefOrRef());

            var arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Ldelema, elementTypeRef,
                                                             (CilExpression)arrayExpr.Remove(),
                                                             (CilExpression)indexExpr.Remove())
            {
                ExpressionType = new ByReferenceTypeSignature(arrayType.BaseType)
            };

            expression.ReplaceWith(arrayLoadExpr);
        }
예제 #16
0
        private void ValidateExpression(CilInstructionExpression expression)
        {
            int stackSize = expression.Arguments.Count;

            foreach (var instruction in expression.Instructions)
            {
                stackSize += instruction.GetStackPopCount(_context.MethodBody);
                if (stackSize < 0)
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Insufficient arguments are pushed onto the stack'{expression.AcceptVisitor(_formatter)}'."));
                }

                stackSize += instruction.GetStackPushCount(_context.MethodBody);

                ValidateInstruction(expression, instruction);
            }
        }
        private static unsafe bool TryOptimizeLdcI(CilInstructionExpression expression)
        {
            if (expression.Instructions.Count != 1 || expression.ExpectedType == null)
            {
                return(false);
            }

            var instruction = expression.Instructions[0];

            if (instruction.IsLdcI4())
            {
                int i4Value = instruction.GetLdcI4Constant();
                if (!expression.ExpectedType.IsValueType)
                {
                    if (i4Value == 0)
                    {
                        // If ldc.i4.0 and expected type is a ref type, the ldc.i4.0 pushes null. We can therefore
                        // optimize to ldnull.
                        ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldnull));
                        return(true);
                    }
                }
                else if (expression.ExpectedType.IsTypeOf("System", "Single"))
                {
                    // KoiVM pushes floats using the pushi_dword instruction. Convert to ldc.r4 if a float is expected
                    // but an ldc.i4 instruction is pushing the value.
                    float actualValue = *(float *)&i4Value;
                    ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldc_R4, actualValue));
                    return(true);
                }
            }
            else if (instruction.OpCode.Code == CilCode.Ldc_I8 && expression.ExpectedType.IsTypeOf("System", "Double"))
            {
                // KoiVM pushes doubles using the pushi_qword instruction. Convert to ldc.r8 if a double is expected
                // but an ldc.i8 instruction is pushing the value.
                long   i8Value     = (long)instruction.Operand;
                double actualValue = *(double *)&i8Value;
                ReplaceWithSingleInstruction(expression, new CilInstruction(CilOpCodes.Ldc_R8, actualValue));
                return(true);
            }

            return(false);
        }
        public override bool VisitInstructionExpression(CilInstructionExpression expression)
        {
            // KoiVM emits pushi_dword or pushi_qwords not only for pushing integers, but also for pushing null or
            // floating point numbers as well.
            if (TryOptimizeLdcI(expression))
            {
                return(true);
            }

            // Insert conversions in all arguments.
            bool changed = base.VisitInstructionExpression(expression);

            // Ensure type safety for all processed arguments.
            foreach (var argument in expression.Arguments.ToArray())
            {
                changed = EnsureTypeSafety(argument);
            }

            return(changed);
        }
        public override bool VisitInstructionExpression(CilInstructionExpression expression)
        {
            if (expression.Instructions.Count == 1 &&
                expression.Instructions[0].IsLdcI4 &&
                expression.Instructions[0].GetLdcValue() == 0 &&
                expression.ExpectedType != null &&
                !expression.ExpectedType.IsValueType)
            {
                expression.Instructions.Clear();
                expression.Instructions.Add(CilInstruction.Create(CilOpCodes.Ldnull));
                expression.ExpressionType = expression.ExpectedType;
                return(true);
            }

            bool changed = base.VisitInstructionExpression(expression);

            foreach (var argument in expression.Arguments.ToArray())
            {
                changed = EnsureTypeSafety(argument);
            }

            return(changed);
        }
예제 #20
0
        private void ReplaceWithLdelem(CilInstructionExpression expression, SzArrayTypeSignature arrayType)
        {
            var arrayExpr = expression.Arguments[0];
            var indexExpr = expression.Arguments[1];

            arrayExpr.ExpectedType = arrayType;
            var elementTypeRef = _context.ReferenceImporter
                                 .ImportType(arrayType.BaseType.ToTypeDefOrRef());

            // Select appropriate opcode.
            CilOpCode opCode;
            object    operand = null;

            switch (arrayType.BaseType.ElementType)
            {
            case ElementType.I1:
                opCode = CilOpCodes.Ldelem_I1;
                break;

            case ElementType.U1:
                opCode = CilOpCodes.Ldelem_U1;
                break;

            case ElementType.I2:
                opCode = CilOpCodes.Ldelem_I2;
                break;

            case ElementType.Char:
            case ElementType.U2:
                opCode = CilOpCodes.Ldelem_U2;
                break;

            case ElementType.Boolean:
            case ElementType.I4:
                opCode = CilOpCodes.Ldelem_I4;
                break;

            case ElementType.U4:
                opCode = CilOpCodes.Ldelem_U4;
                break;

            case ElementType.I8:
            case ElementType.U8:
                opCode = CilOpCodes.Ldelem_I8;
                break;

            case ElementType.R4:
                opCode = CilOpCodes.Ldelem_R4;
                break;

            case ElementType.R8:
                opCode = CilOpCodes.Ldelem_R8;
                break;

            case ElementType.I:
            case ElementType.U:
                opCode = CilOpCodes.Ldelem_I;
                break;

            case ElementType.ValueType:
                opCode  = CilOpCodes.Ldelem;
                operand = elementTypeRef;
                break;

            default:
                opCode = CilOpCodes.Ldelem_Ref;
                break;
            }

            // Create the ldelem expression
            var arrayLoadExpr = new CilInstructionExpression(opCode, operand,
                                                             (CilExpression)arrayExpr.Remove(),
                                                             (CilExpression)indexExpr.Remove())
            {
                ExpressionType = arrayType.BaseType
            };

            if (arrayType.BaseType.IsValueType)
            {
                // Array.GetValue boxes value typed values.
                arrayLoadExpr = new CilInstructionExpression(CilOpCodes.Box, elementTypeRef, arrayLoadExpr)
                {
                    ExpectedType   = expression.ExpectedType,
                    ExpressionType = expression.ExpressionType
                };
            }

            expression.ReplaceWith(arrayLoadExpr);
        }
예제 #21
0
        private void ValidateInstruction(CilInstructionExpression expression, CilInstruction instruction)
        {
            switch (instruction.OpCode.OperandType)
            {
            case CilOperandType.ShortInlineBrTarget:
            case CilOperandType.InlineBrTarget:
                if (!(instruction.Operand is CilInstruction))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a branch target operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineMethod:
            case CilOperandType.InlineField:
            case CilOperandType.InlineType:
            case CilOperandType.InlineTok:
                if (!(instruction.Operand is IMemberReference))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a member reference operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineSig:
                if (!(instruction.Operand is StandAloneSignature))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a signature operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineI:
                if (!(instruction.Operand is int))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected an int32 operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineI8:
                if (!(instruction.Operand is long))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected an int64 operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineNone:
                if (instruction.Operand != null)
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Unexpected operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineR:
                if (!(instruction.Operand is double))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a float64 operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.ShortInlineI:
                if (!(instruction.Operand is sbyte))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected an int8 operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.ShortInlineR:
                if (!(instruction.Operand is float))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a float32 operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineString:
                if (!(instruction.Operand is string))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a string operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineSwitch:
                if (!(instruction.Operand is IList <CilInstruction>))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a switch table operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.ShortInlineVar:
            case CilOperandType.InlineVar:
                if (!(instruction.Operand is VariableSignature))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a variable operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            case CilOperandType.InlineArgument:
            case CilOperandType.ShortInlineArgument:
                if (!(instruction.Operand is ParameterSignature))
                {
                    throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                            $"Expected a parameter operand in '{expression.AcceptVisitor(_formatter)}'."));
                }

                break;

            default:
                throw new CilCodeGeneratorException(InvalidAstMessage, new ArgumentException(
                                                        $"Unexpected opcode in '{expression.AcceptVisitor(_formatter)}'."));
            }
        }
예제 #22
0
        private void ReplaceWithStelem(CilInstructionExpression expression, SzArrayTypeSignature arrayType)
        {
            var arrayExpr = expression.Arguments[0];
            var valueExpr = expression.Arguments[1];
            var indexExpr = expression.Arguments[2];

            arrayExpr.ExpectedType = arrayType;

            // Select appropriate opcode.
            CilOpCode opCode;
            object    operand = null;

            switch (arrayType.BaseType.ElementType)
            {
            case ElementType.I1:
            case ElementType.U1:
                opCode = CilOpCodes.Stelem_I1;
                break;

            case ElementType.Char:
            case ElementType.I2:
            case ElementType.U2:
                opCode = CilOpCodes.Stelem_I2;
                break;

            case ElementType.Boolean:
            case ElementType.I4:
            case ElementType.U4:
                opCode = CilOpCodes.Stelem_I4;
                break;

            case ElementType.I8:
            case ElementType.U8:
                opCode = CilOpCodes.Stelem_I8;
                break;

            case ElementType.R4:
                opCode = CilOpCodes.Stelem_R4;
                break;

            case ElementType.R8:
                opCode = CilOpCodes.Stelem_R8;
                break;

            case ElementType.I:
            case ElementType.U:
                opCode = CilOpCodes.Stelem_I;
                break;

            case ElementType.ValueType:
                opCode  = CilOpCodes.Stelem;
                operand = _context.ReferenceImporter
                          .ImportType(arrayType.BaseType.ToTypeDefOrRef());
                break;

            default:
                opCode = CilOpCodes.Stelem_Ref;
                break;
            }

            valueExpr.ExpectedType = arrayType.BaseType;

            var arrayStoreExpr = new CilInstructionExpression(opCode, operand,
                                                              (CilExpression)arrayExpr.Remove(),
                                                              (CilExpression)indexExpr.Remove(),
                                                              (CilExpression)valueExpr.Remove());

            expression.ReplaceWith(arrayStoreExpr);
        }
예제 #23
0
        private static CilExpression CompileRegisterPush(RecompilerContext context, ILInstructionExpression expression)
        {
            var cilExpression = (CilExpression)expression.Arguments[0].AcceptVisitor(context.Recompiler);

            var resultType = expression.OpCode.StackBehaviourPush.GetResultType();

            if (cilExpression is CilUnboxToVmExpression)
            {
                // HACK: Unbox expressions unbox the value from the stack, but also convert it to their unsigned
                //       variant and box it again into an object. We need to unpack it again, however, we do not
                //       know the actual type of the value inside the box, as this is determined at runtime.
                //
                //       For now, we just make use of the Convert class provided by .NET, which works but would rather
                //       see a true "native" CIL conversion instead.

                MethodBase convertMethod;
                switch (resultType)
                {
                case VMType.Byte:
                    convertMethod = typeof(Convert).GetMethod("ToByte", new[] { typeof(object) });
                    break;

                case VMType.Word:
                    convertMethod = typeof(Convert).GetMethod("ToUInt16", new[] { typeof(object) });
                    break;

                case VMType.Dword:
                    convertMethod = typeof(Convert).GetMethod("ToUInt32", new[] { typeof(object) });
                    break;

                case VMType.Qword:
                    convertMethod = typeof(Convert).GetMethod("ToUInt64", new[] { typeof(object) });
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                cilExpression.ExpectedType = context.TargetImage.TypeSystem.Object;
                cilExpression = new CilInstructionExpression(
                    CilOpCodes.Call,
                    context.ReferenceImporter.ImportMethod(convertMethod),
                    cilExpression);
            }

            if (resultType == VMType.Object)
            {
                if (cilExpression.ExpressionType.IsValueType)
                {
                    if (cilExpression is CilInstructionExpression instructionExpression &&
                        instructionExpression.Instructions.Count == 1 &&
                        instructionExpression.Instructions[0].IsLdcI4 &&
                        instructionExpression.Instructions[0].GetLdcValue() == 0)
                    {
                        cilExpression = new CilInstructionExpression(CilOpCodes.Ldnull);
                    }
                    else
                    {
                        // If expression returns a value type, we have to box it to an object.
                        cilExpression = new CilInstructionExpression(CilOpCodes.Box,
                                                                     context.ReferenceImporter.ImportType(cilExpression.ExpressionType.ToTypeDefOrRef()),
                                                                     cilExpression);
                    }
                }
                else
                {
                    // Use the reference type of the expression instead of System.Object.
                    cilExpression.ExpressionType = cilExpression.ExpressionType;
                }
            }
예제 #24
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var ecall     = (ECallAnnotation)expression.Annotation;
            var methodSig = ecall.Method.Signature;

            // Select calling instruction, return type and call prefix.
            CilInstruction prefix = null;
            TypeSignature  resultType;
            CilOpCode      opcode;
            object         operand = ecall.Method;

            switch (ecall.OpCode)
            {
            case VMECallOpCode.CALL:
                opcode     = CilOpCodes.Call;
                resultType = methodSig.ReturnType;
                break;

            case VMECallOpCode.CALLVIRT:
                opcode     = CilOpCodes.Callvirt;
                resultType = methodSig.ReturnType;
                break;

            case VMECallOpCode.NEWOBJ:
                opcode     = CilOpCodes.Newobj;
                resultType = ecall.Method.DeclaringType.ToTypeSignature();

                // KoiVM translates "newarr ElementType" instructions to "newobj ElementType[]::.ctor(int32)".
                // Revert this operation if necessary:
                if (resultType is SzArrayTypeSignature arrayType)
                {
                    opcode  = CilOpCodes.Newarr;
                    operand = context.ReferenceImporter.ImportType(arrayType.BaseType.ToTypeDefOrRef());
                }

                break;

            case VMECallOpCode.CALLVIRT_CONSTRAINED:
                prefix     = new CilInstruction(CilOpCodes.Constrained, ecall.ConstrainedType);
                opcode     = CilOpCodes.Callvirt;
                resultType = methodSig.ReturnType;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // Enter generic context of method.
            context.EnterMember(ecall.Method);

            // Collect arguments.
            var arguments = expression.Arguments
                            .Skip(ecall.IsConstrained ? 3 : 2)
                            .ToArray();

            // Build call expression.
            var result = new CilInstructionExpression(opcode, operand,
                                                      context.RecompileCallArguments(ecall.Method, arguments, ecall.OpCode, ecall.ConstrainedType))
            {
                ExpressionType = resultType.InstantiateGenericTypes(context.GenericContext)
            };

            // Add prefix when necessary.
            if (prefix != null)
            {
                result.Instructions.Insert(0, prefix);
            }

            // Leave generic context.
            context.ExitMember();

            return(result);
        }
예제 #25
0
 public string VisitInstructionExpression(CilInstructionExpression expression)
 {
     return(string.Join(" - ", expression.Instructions.Select(i => i.Operand == null
         ? _formatter.FormatOpCode(i.OpCode)
         : $"{_formatter.FormatOpCode(i.OpCode)} {_formatter.FormatOperand(i.OpCode.OperandType, i.Operand)}")));
 }
예제 #26
0
        public CilExpression Translate(RecompilerContext context, ILVCallExpression expression)
        {
            var ecall     = (ECallAnnotation)expression.Annotation;
            var methodSig = (MethodSignature)ecall.Method.Signature;

            // Select calling instruction, return type and call prefix.
            CilInstruction prefix = null;
            TypeSignature  resultType;
            CilOpCode      opcode;

            switch (ecall.OpCode)
            {
            case VMECallOpCode.CALL:
                opcode     = CilOpCodes.Call;
                resultType = methodSig.ReturnType;
                break;

            case VMECallOpCode.CALLVIRT:
                opcode     = CilOpCodes.Callvirt;
                resultType = methodSig.ReturnType;
                break;

            case VMECallOpCode.NEWOBJ:
                opcode     = CilOpCodes.Newobj;
                resultType = ecall.Method.DeclaringType.ToTypeSignature();
                break;

            case VMECallOpCode.CALLVIRT_CONSTRAINED:
                prefix     = CilInstruction.Create(CilOpCodes.Constrained, ecall.ConstrainedType);
                opcode     = CilOpCodes.Callvirt;
                resultType = methodSig.ReturnType;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // Enter generic context of method.
            context.EnterMember(ecall.Method);

            // Collect arguments.
            var arguments = expression.Arguments
                            .Skip(ecall.IsConstrained ? 3 : 2)
                            .ToArray();

            // Build call expression.
            var result = new CilInstructionExpression(opcode, ecall.Method,
                                                      context.RecompileCallArguments(ecall.Method, arguments, ecall.OpCode == VMECallOpCode.NEWOBJ))
            {
                ExpressionType = resultType.InstantiateGenericTypes(context.GenericContext)
            };

            // Add prefix when necessary.
            if (prefix != null)
            {
                result.Arguments[0].ExpectedType = ecall.ConstrainedType;
                result.Instructions.Insert(0, prefix);
            }

            // Leave generic context.
            context.ExitMember();

            return(result);
        }
        public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression)
        {
            var arguments = expression.Arguments
                            .Select(a => (CilExpression)a.AcceptVisitor(context.Recompiler))
                            .ToArray();

            CilOpCode opCode;

            switch (expression.OpCode.Code)
            {
            case ILCode.__EQUALS_OBJECT:
                opCode = CilOpCodes.Ceq;
                break;

            case ILCode.__EQUALS_R32:
            case ILCode.__EQUALS_R64:
            case ILCode.__EQUALS_DWORD:
            case ILCode.__EQUALS_QWORD:
                opCode = CilOpCodes.Ceq;
                break;

            case ILCode.__GT_R32:
            case ILCode.__GT_R64:
                opCode = CilOpCodes.Cgt;
                break;

            case ILCode.__GT_DWORD:
            case ILCode.__GT_QWORD:
                opCode = CilOpCodes.Cgt_Un;
                break;

            case ILCode.__LT_R32:
            case ILCode.__LT_R64:
                opCode = CilOpCodes.Clt;
                break;

            case ILCode.__LT_DWORD:
            case ILCode.__LT_QWORD:
                opCode = CilOpCodes.Clt_Un;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(expression));
            }

            var argumentType = expression.OpCode.StackBehaviourPop.GetArgumentType(0)
                               .ToMetadataType(context.TargetModule)
                               .ToTypeSignature();

            var result = new CilInstructionExpression(opCode)
            {
                ExpressionType = context.TargetModule.CorLibTypeFactory.Boolean
            };

            foreach (var argument in arguments)
            {
                argument.ExpectedType = argumentType;
                result.Arguments.Add(argument);
            }

            return(result);
        }
 private static void ReplaceWithSingleInstruction(CilInstructionExpression expression, CilInstruction newInstruction)
 {
     expression.Instructions.Clear();
     expression.Instructions.Add(newInstruction);
     expression.ExpressionType = expression.ExpectedType;
 }