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")))); } } } } } } }