Esempio n. 1
0
        public void TransformIL(IEnumerable <TypeDefinition> types)
        {
            foreach (var t in types.Where(x => !x.IsInterface && !x.IsAbstract))
            {
                var finalizer = t.Methods.SingleOrDefault(x => x.Name.EndsWith("Finalize"));

                if (finalizer == null)
                {
                    continue;
                }

                var proc = finalizer.Body.GetILProcessor();
                finalizer.Body.MaxStackSize = Math.Max(finalizer.Body.MaxStackSize, 2);


                var ret = finalizer.Body.Instructions.LastOrDefault();
                if (ret != null)
                {
                    finalizer.Body.Instructions.Remove(ret);
                }

                foreach (var field in t.Fields.Where(
                             x => !x.IsStatic && !x.FieldType.IsValueType))
                {
                    proc.Emit(OpCodes.Ldarg_0);
                    proc.Emit(OpCodes.Ldnull);
                    proc.Emit(OpCodes.Stfld, field);
                }

                foreach (var field in t.Fields.Where(x => x.FieldType.IsValueType && ValueTypeHelper.NeedRefCounting(x.FieldType.Resolve())))
                {
                    proc.Emit(OpCodes.Ldarg_0);
                    proc.Emit(OpCodes.Ldflda, field);
                    proc.Emit(OpCodes.Call, field.FieldType.Resolve().Methods.Single(x => x.Name.EndsWith("RemoveRef")));
                }

                // call base finalizer
                if (!t.IsValueType && t.BaseType != null && t.BaseType.Name != "EObject")
                {
                    var baseFinalizer = t.BaseType.Resolve().Methods.SingleOrDefault(x => x.Name.EndsWith("Finalize"));
                    if (baseFinalizer != null)
                    {
                        proc.Emit(OpCodes.Ldarg_0);
                        proc.Emit(OpCodes.Call, baseFinalizer);
                    }
                }

                proc.Emit(OpCodes.Ret);
                IlHelper.UpdateIlOffsets(finalizer.Body);
            }
        }
        public void TransformIL(IEnumerable <TypeDefinition> types)
        {
            var resolver = new ReferenceResolver(types);


            foreach (var t in types)
            {
                if (t.IsValueType)
                {
                    // add initobj method
                    var nm = new MethodDefinition(t.Name + "_initobj", MethodAttributes.Static, t.Module.ImportReference((typeof(void))));
                    nm.Parameters.Add(new ParameterDefinition("_this", ParameterAttributes.None, new PointerType(t)));
                    var code = "memset(_this, 0, sizeof(*_this));";
                    EmitSource.SourceImplementation(nm, code);
                    t.Methods.Add(nm);


                    if (ValueTypeHelper.NeedRefCounting(t))
                    {
                        foreach (var methodName in new string[] { "AddRef", "RemoveRef" })
                        {
                            // add ref adjustment methods
                            nm = new MethodDefinition(t.Name + "_" + methodName, MethodAttributes.Static, t.Module.ImportReference((typeof(void))));
                            nm.Parameters.Add(new ParameterDefinition("_vt", ParameterAttributes.None, new PointerType(t)));
                            t.Methods.Add(nm);

                            var procs = nm.Body.GetILProcessor();

                            foreach (var field in t.Fields.Where(x => !x.FieldType.IsValueType))
                            {
                                var refMethod = types.Single(x => x.Name == "EObject").Methods.Single(x => x.Name.EndsWith("EObject_" + methodName));                                 //
                                procs.Emit(OpCodes.Ldarg_0);
                                procs.Emit(OpCodes.Ldfld, field);
                                procs.Emit(OpCodes.Call, refMethod);
                            }
                            procs.Emit(OpCodes.Ret);
                        }
                    }


                    var finalizer = t.Methods.Single(x => x.Name == t.Name + "_Finalize");
                    //if (!ValueTypeHelper.NeedRefCounting(t)) {
                    t.Methods.Remove(finalizer);
                }
            }



            foreach (var t in types)
            {
                foreach (var m in t.Methods)
                {
                    // C only knows pointers but no references. Replace with pointers.
                    foreach (var p in m.Parameters)
                    {
                        if (p.ParameterType is ByReferenceType rt)
                        {
                            p.ParameterType = new PointerType(rt.ElementType);
                        }
                    }

                    if (!m.HasBody)
                    {
                        continue;
                    }

                    var newBody = new List <Instruction>();
                    var ilp     = m.Body.GetILProcessor();
                    // replace default with new
                    for (int idx = 0; idx < m.Body.Instructions.Count(); idx++)
                    {
                        var inst = m.Body.Instructions[idx];
                        newBody.Add(inst);

                        if (inst.OpCode == OpCodes.Initobj)
                        {
                            var initType = inst.Operand as TypeDefinition;
                            Debug.Assert(initType.IsValueType, initType.Name + " should be a Value Type");

                            // adjust ref counting before memset
                            // todo: skip this when struct is unused.
                            if (ValueTypeHelper.NeedRefCounting(initType))
                            {
                                ilp.InsertBefore(inst, ilp.Create(OpCodes.Dup));
                                ilp.InsertBefore(inst, ilp.Create(OpCodes.Call, initType.Methods.Single(x => x.Name.EndsWith("RemoveRef"))));
                            }

                            if (initType.IsPrimitive)
                            {
                                ilp.InsertBefore(inst, Instruction.Create(OpCodes.Ldc_I4, 0));
                                ilp.Replace(inst, Instruction.Create(OpCodes.Stobj, initType));
                            }
                            else
                            {
                                var initMethod = initType.Methods.Single(x => x.Name.EndsWith("_initobj"));
                                ilp.Replace(inst, Instruction.Create(OpCodes.Call, initMethod));
                            }
                        }


                        // try to use pointers instead of references
                        if (inst.OpCode == OpCodes.Ldflda)
                        {
                            var field = (inst.Operand as FieldDefinition);
                            ilp.InsertAfter(inst, ilp.Create(OpCodes.Conv_I));
                            idx++;
                        }
                    }
                    //m.Body.Instructions = newBody;
                    IlHelper.UpdateIlOffsets(m.Body);

                    // initalizing should be done in LocalVariableInitializaionOptimization
                    //continue;

                    foreach (var v in m.Body.Variables)
                    {
                        // remove ref for valuetypes going out of scope.
                        if (false)                          // currently nor needed, done in ref counting
                        {
                            if (v.VariableType.Resolve().IsValueType&& ValueTypeHelper.NeedRefCounting(v.VariableType.Resolve()))
                            {
                                // Afaik, only one return in functions
                                var ret = ilp.Body.Instructions.Single(x => x.OpCode == OpCodes.Ret);

                                if (ret.Operand != v)
                                {
                                    ilp.InsertBefore(ret, ilp.Create(OpCodes.Ldloca, v));
                                    ilp.InsertBefore(ret, ilp.Create(OpCodes.Call, v.VariableType.Resolve().Methods.Single(x => x.Name.EndsWith("RemoveRef"))));
                                }
                            }
                        }
                    }
                }
            }
        }