Ejemplo n.º 1
0
        public void ReferenceTypeAttributes()
        {
            // Grab all references from TypeSystem.
            var ts       = corlib.Definition.MainModule.TypeSystem;
            var refTypes = new[]
            {
                ts.Object, ts.String
            };
            var valTypes = new[]
            {
                ts.Char, ts.Boolean,
                ts.IntPtr, ts.UIntPtr,
                ts.SByte, ts.Int16, ts.Int32, ts.Int64,
                ts.Byte, ts.UInt16, ts.UInt32, ts.UInt64,
                ts.Single, ts.Double
            };

            foreach (var item in refTypes)
            {
                Assert.IsTrue(corlib.Resolve(item).IsReferenceType());
            }
            foreach (var item in valTypes)
            {
                Assert.IsFalse(corlib.Resolve(item).IsReferenceType());
            }
        }
Ejemplo n.º 2
0
        public void ResolveStringEmpty()
        {
            var ts            = corlib.Definition.MainModule.TypeSystem;
            var emptyFieldRef = ts.String.Resolve().Fields.Single(f => f.Name == "Empty");

            var emptyField = corlib.Resolve(emptyFieldRef);

            Assert.IsNotNull(emptyField);
            Assert.AreEqual(emptyField.Name.ToString(), emptyFieldRef.Name);
            Assert.IsTrue(emptyField.IsStatic);
            Assert.AreEqual(emptyField.FieldType.FullName.ToString(), StringBoxName);
        }
Ejemplo n.º 3
0
        private static Task <AssemblyContentDescription> CreateContentDescriptionAsync(ClrAssembly assembly)
        {
            var typeSystem = assembly.Resolver.TypeEnvironment;
            var pipeline   = new Optimization[]
            {
                new ConstantPropagation(),
                MemoryAccessElimination.Instance,
                DeadValueElimination.Instance,
                new JumpThreading(true),
                SwitchSimplification.Instance,
                DuplicateReturns.Instance,
                TailRecursionElimination.Instance,
                BlockFusion.Instance
            };

            var optimizer = new OnDemandOptimizer(
                pipeline,
                method => GetInitialMethodBody(method, typeSystem));

            return(AssemblyContentDescription.CreateTransitiveAsync(
                       assembly.FullName,
                       assembly.Attributes,
                       assembly.Resolve(assembly.Definition.EntryPoint),
                       optimizer));
        }
Ejemplo n.º 4
0
        public void ResolveTypeSystem()
        {
            // Grab all references from TypeSystem.
            var ts   = Corlib.Definition.MainModule.TypeSystem;
            var refs = new[]
            {
                ts.Object, ts.String, ts.Void, ts.Char, ts.Boolean,
                ts.IntPtr, ts.UIntPtr,
                ts.SByte, ts.Int16, ts.Int32, ts.Int64,
                ts.Byte, ts.UInt16, ts.UInt32, ts.UInt64,
                ts.Single, ts.Double
            };

            // Resolve all references in TypeSystem.
            foreach (var item in refs)
            {
                Assert.IsNotNull(Corlib.Resolve(item));
            }
        }
Ejemplo n.º 5
0
        public void RoundtripCheckedConversions()
        {
            var typeSys = corlib.Definition.MainModule.TypeSystem;
            Func <TypeReference, bool> isSigned = type => corlib.Resolve(type).GetIntegerSpecOrNull().IsSigned;
            Func <TypeReference, int>  getSize  = type => corlib.Resolve(type).GetIntegerSpecOrNull().Size;
            var checkedOps = new Dictionary <TypeReference, Tuple <Mono.Cecil.Cil.OpCode, Mono.Cecil.Cil.OpCode> >()
            {
                { typeSys.Byte, Tuple.Create(OpCodes.Conv_Ovf_U1, OpCodes.Conv_Ovf_U1_Un) },
                { typeSys.SByte, Tuple.Create(OpCodes.Conv_Ovf_I1, OpCodes.Conv_Ovf_I1_Un) },
                { typeSys.Int16, Tuple.Create(OpCodes.Conv_Ovf_I2, OpCodes.Conv_Ovf_I2_Un) },
                { typeSys.UInt16, Tuple.Create(OpCodes.Conv_Ovf_U2, OpCodes.Conv_Ovf_U2_Un) },
                { typeSys.Int32, Tuple.Create(OpCodes.Conv_Ovf_I4, OpCodes.Conv_Ovf_I4_Un) },
                { typeSys.UInt32, Tuple.Create(OpCodes.Conv_Ovf_U4, OpCodes.Conv_Ovf_U4_Un) },
                { typeSys.Int64, Tuple.Create(OpCodes.Conv_Ovf_I8, OpCodes.Conv_Ovf_I8_Un) },
                { typeSys.UInt64, Tuple.Create(OpCodes.Conv_Ovf_U8, OpCodes.Conv_Ovf_U8_Un) }
            };

            foreach (var sourceType in checkedOps.Keys)
            {
                foreach (var targetType in checkedOps.Keys)
                {
                    var signedAndUnsignedOp = checkedOps[targetType];
                    var op           = isSigned(sourceType) ? signedAndUnsignedOp.Item1 : signedAndUnsignedOp.Item2;
                    var requiresConv = !InstructionSimplification.CanAlwaysConvert(
                        corlib.Resolve(sourceType),
                        corlib.Resolve(targetType));
                    RoundtripStaticMethodBody(
                        targetType,
                        new[] { sourceType },
                        EmptyArray <TypeReference> .Value,
                        ilProc =>
                    {
                        ilProc.Emit(OpCodes.Ldarg_0);
                        ilProc.Emit(op);
                        ilProc.Emit(OpCodes.Ret);
                    },
                        ilProc =>
                    {
                        ilProc.Emit(OpCodes.Ldarg_0);
                        if (requiresConv)
                        {
                            ilProc.Emit(op);
                        }
                        else if (getSize(targetType) > 32 && getSize(sourceType) <= 32)
                        {
                            if (isSigned(sourceType))
                            {
                                ilProc.Emit(OpCodes.Conv_I8);
                            }
                            else
                            {
                                ilProc.Emit(OpCodes.Conv_U8);
                            }
                        }
                        ilProc.Emit(OpCodes.Ret);
                    });
                }
            }
        }
Ejemplo n.º 6
0
        private static void OptimizeMethod(
            Mono.Cecil.MethodDefinition methodDefinition,
            ClrAssembly parentAssembly,
            Func <ClrMethodDefinition, MethodBody> optimizeBody)
        {
            if (methodDefinition.HasBody)
            {
                var flameMethod = (ClrMethodDefinition)parentAssembly.Resolve(methodDefinition);
                var irBody      = flameMethod.Body;

                var errors = irBody.Validate();
                if (errors.Count > 0)
                {
                    var sourceIr = FormatIr(irBody);
                    log.Log(
                        new LogEntry(
                            Severity.Warning,
                            "invalid IR",
                            Quotation.QuoteEvenInBold(
                                "the Flame IR produced by the CIL analyzer for ",
                                flameMethod.FullName.ToString(),
                                " is erroneous; skipping it."),

                            CreateRemark(
                                "errors in IR:",
                                new BulletedList(errors.Select(x => new Text(x)).ToArray())),

                            CreateRemark(
                                "generated Flame IR:",
                                new Paragraph(new WrapBox(sourceIr, 0, -sourceIr.Length)))));
                    return;
                }

                var optBody = optimizeBody(flameMethod);
                var emitter = new ClrMethodBodyEmitter(
                    methodDefinition,
                    optBody,
                    parentAssembly.Resolver.TypeEnvironment);
                var newCilBody = emitter.Compile();
                methodDefinition.Body = newCilBody;
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Writes a CIL method body, analyzes it as Flame IR,
        /// emits that as CIL and checks that the outcome matches
        /// what we'd expect.
        /// </summary>
        /// <param name="returnType">
        /// The return type of the method body.
        /// </param>
        /// <param name="parameterTypes">
        /// The parameter types of the method body.
        /// </param>
        /// <param name="localTypes">
        /// The local variable types of the method body.
        /// </param>
        /// <param name="emitBody">
        /// A function that writes the method body.
        /// </param>
        /// <param name="oracle">
        /// A printed version of the expected method body.
        /// </param>
        private void RoundtripStaticMethodBody(
            TypeReference returnType,
            IReadOnlyList <TypeReference> parameterTypes,
            IReadOnlyList <TypeReference> localTypes,
            Action <Mono.Cecil.Cil.ILProcessor> emitBody,
            string oracle)
        {
            // Define a method.
            var methodDef = CreateStaticMethodDef(returnType, parameterTypes);

            // Emit the source CIL.
            var cilBody = new Mono.Cecil.Cil.MethodBody(methodDef);

            foreach (var localType in localTypes)
            {
                cilBody.Variables.Add(new Mono.Cecil.Cil.VariableDefinition(localType));
            }

            emitBody(cilBody.GetILProcessor());
            cilBody.Optimize();

            // Analyze it as Flame IR.
            var irBody = ClrMethodBodyAnalyzer.Analyze(
                cilBody,
                new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(returnType))),
                default(Parameter),
                parameterTypes
                .Select((type, i) => new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(type)), "param_" + i))
                .ToArray(),
                corlib);

            // Register analyses.
            irBody = new global::Flame.Compiler.MethodBody(
                irBody.ReturnParameter,
                irBody.ThisParameter,
                irBody.Parameters,
                irBody.Implementation
                .WithAnalysis(LazyBlockReachabilityAnalysis.Instance)
                .WithAnalysis(NullabilityAnalysis.Instance)
                .WithAnalysis(new EffectfulInstructionAnalysis())
                .WithAnalysis(PredecessorAnalysis.Instance)
                .WithAnalysis(RelatedValueAnalysis.Instance)
                .WithAnalysis(LivenessAnalysis.Instance)
                .WithAnalysis(InterferenceGraphAnalysis.Instance)
                .WithAnalysis(ValueUseAnalysis.Instance)
                .WithAnalysis(ConservativeInstructionOrderingAnalysis.Instance));

            // Optimize the IR a tiny bit.
            irBody = irBody.WithImplementation(
                irBody.Implementation.Transform(
                    AllocaToRegister.Instance,
                    CopyPropagation.Instance,
                    new ConstantPropagation(),
                    SwitchSimplification.Instance,
                    DeadValueElimination.Instance,
                    new JumpThreading(true),
                    DeadBlockElimination.Instance,
                    new SwitchLowering(corlib.Resolver.TypeEnvironment),
                    CopyPropagation.Instance,
                    DeadValueElimination.Instance,
                    new JumpThreading(false)));

            // Turn Flame IR back into CIL.
            var emitter    = new ClrMethodBodyEmitter(methodDef, irBody, corlib.Resolver.TypeEnvironment);
            var newCilBody = emitter.Compile();

            // Check that the resulting CIL matches the expected CIL.
            var actual = FormatMethodBody(newCilBody);

            actual = actual.Trim().Replace("\r", "");
            oracle = oracle.Trim().Replace("\r", "");
            if (actual != oracle)
            {
                var encoder     = new EncoderState();
                var encodedImpl = encoder.Encode(irBody.Implementation);

                var actualIr = Les2LanguageService.Value.Print(
                    encodedImpl,
                    options: new LNodePrinterOptions
                {
                    IndentString = new string(' ', 4)
                });

                log.Log(
                    new LogEntry(
                        Severity.Message,
                        "emitted CIL-oracle mismatch",
                        "round-tripped CIL does not match the oracle. CIL emit output:",
                        new Paragraph(new WrapBox(actual, 0, -actual.Length)),
                        DecorationSpan.MakeBold("remark: Flame IR:"),
                        new Paragraph(new WrapBox(actualIr, 0, -actualIr.Length))));
            }
            Assert.AreEqual(oracle, actual);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Writes a CIL method body, analyzes it as Flame IR
        /// and checks that the result is what we'd expect.
        /// </summary>
        /// <param name="returnType">
        /// The return type of the method body.
        /// </param>
        /// <param name="parameterTypes">
        /// The parameter types of the method body.
        /// </param>
        /// <param name="emitBody">
        /// A function that writes the method body.
        /// </param>
        /// <param name="oracle">
        /// The expected Flame IR flow graph, as LESv2.
        /// </param>
        private void AnalyzeStaticMethodBody(
            TypeReference returnType,
            IReadOnlyList <TypeReference> parameterTypes,
            IReadOnlyList <TypeReference> localTypes,
            Action <Mono.Cecil.Cil.ILProcessor> emitBody,
            string oracle)
        {
            var methodDef = new MethodDefinition(
                "f",
                MethodAttributes.Public | MethodAttributes.Static,
                returnType);

            foreach (var type in parameterTypes)
            {
                methodDef.Parameters.Add(new ParameterDefinition(type));
                int index = methodDef.Parameters.Count - 1;
                methodDef.Parameters[index].Name = "param_" + index;
            }

            var cilBody = new Mono.Cecil.Cil.MethodBody(methodDef);

            foreach (var localType in localTypes)
            {
                cilBody.Variables.Add(new Mono.Cecil.Cil.VariableDefinition(localType));
            }

            emitBody(cilBody.GetILProcessor());

            var irBody = ClrMethodBodyAnalyzer.Analyze(
                cilBody,
                new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(returnType))),
                default(Parameter),
                parameterTypes
                .Select((type, i) => new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(type)), "param_" + i))
                .ToArray(),
                corlib);

            var encoder     = new EncoderState();
            var encodedImpl = encoder.Encode(irBody.Implementation);

            var actual = Les2LanguageService.Value.Print(
                encodedImpl,
                options: new LNodePrinterOptions
            {
                IndentString = new string(' ', 4)
            });

            if (actual.Trim() != oracle.Trim())
            {
                log.Log(
                    new LogEntry(
                        Severity.Message,
                        "CIL analysis-oracle mismatch",
                        "analyzed CIL does not match the oracle. CIL analysis output:"));
                // TODO: ugly hack to work around wrapping.
                Console.Error.WriteLine(actual.Trim());
            }

            Assert.AreEqual(
                actual.Trim(),
                oracle.Trim());
        }