public AtomGetterMethodWeaver(AtomWeaverV2 weaver, PropertyDefinition property, FieldReference atomField, AtomOptions options) { _atomField = atomField; _options = options; _property = property; _atomDebugName = weaver._generateDebugNames ? $"{property.DeclaringType.FullName}::{property.Name}" : null; _resultVariable = new VariableDefinition(property.PropertyType); _nullCheckEndInstruction = Instruction.Create(OpCodes.Nop); _directEvalEndInstruction = Instruction.Create(OpCodes.Nop); _loadResultInstruction = Instruction.Create(OpCodes.Ldloc, _resultVariable); var propertyType = property.PropertyType; _atomCreateMethod = Helpers.MakeGenericMethod(weaver._atomCreateMethod, propertyType); _atomPullCtorMethod = Helpers.MakeHostInstanceGeneric(weaver._atomPullCtorMethod, propertyType); _tryEnterMethod = Helpers.MakeHostInstanceGeneric(weaver._atomDirectEvalMethod, propertyType); _atomGetMethod = Helpers.MakeHostInstanceGeneric(weaver._atomGetValueMethod, propertyType); var body = property.GetMethod.Body; body.InitLocals = true; body.Variables.Add(_resultVariable); }
public AtomSetterMethodWeaver(AtomWeaverV2 weaver, PropertyDefinition property, FieldReference atomField) { _atomField = atomField; _property = property; _nullCheckEndInstruction = Instruction.Create(OpCodes.Nop); _preReturnInstruction = Instruction.Create(OpCodes.Nop); var propertyType = property.PropertyType; _compAndInvalidateMethod = Helpers.MakeHostInstanceGeneric(weaver._atomCompAndInvalidateMethod, propertyType); }
private void ReplacePropertyCall(PropertyDefinition prop, FieldReference field, MethodReference pullMethod, MethodReference pushMethod) { var type = prop.PropertyType; if (prop.GetMethod != null) { prop.GetMethod.Body = new MethodBody(prop.GetMethod); prop.GetMethod.Body.Variables.Add(new VariableDefinition(_atomTypeGeneric)); var ilProcessor = prop.GetMethod.Body.GetILProcessor(); var typedAtomGet = Helpers.MakeHostInstanceGeneric(_atomGetValue, type); GenerateAtom(ilProcessor, type, field, pullMethod, pushMethod, proc => { Instruction first; proc.Append(first = proc.Create(OpCodes.Callvirt, typedAtomGet)); return(first); }); } if (prop.SetMethod != null) { prop.SetMethod.Body = new MethodBody(prop.SetMethod); prop.SetMethod.Body.Variables.Add(new VariableDefinition(_atomTypeGeneric)); var ilProcessor = prop.SetMethod.Body.GetILProcessor(); var typedAtomSet = Helpers.MakeHostInstanceGeneric(_atomSetValue, type); GenerateAtom(ilProcessor, type, field, pullMethod, pushMethod, proc => { Instruction first; proc.Append(first = proc.Create(OpCodes.Ldarg_1)); proc.Append(proc.Create(OpCodes.Callvirt, typedAtomSet)); return(first); }); } }
private void GenerateAtom(ILProcessor proc, TypeReference type, FieldReference field, MethodReference pullMethod, MethodReference pushMethod, Func <ILProcessor, Instruction> generate) { Instruction br; //load class instance onto stack proc.Append(proc.Create(OpCodes.Ldarg_0)); // pop class instance and push field value proc.Append(proc.Create(OpCodes.Ldfld, field)); // duplicate field value proc.Append(br = proc.Create(OpCodes.Dup)); { // pop field value and jump if atom not null //worker.Append(worker.Create(OpCodes.Brtrue_S, label)); //will be inserted later // pop field value (now stack is empty) proc.Append(proc.Create(OpCodes.Pop)); //load class instance proc.Append(proc.Create(OpCodes.Ldarg_0)); //create pull delegate or null if (pullMethod != null) { proc.Append(proc.Create(OpCodes.Ldarg_0)); proc.Append(proc.Create(OpCodes.Ldftn, pullMethod)); proc.Append(proc.Create(OpCodes.Newobj, Helpers.MakeHostInstanceGeneric(_atomPullCtor, type))); } else { proc.Append(proc.Create(OpCodes.Ldnull)); } //create push delegate or null if (pushMethod != null) { proc.Append(proc.Create(OpCodes.Ldarg_0)); proc.Append(proc.Create(OpCodes.Ldftn, pushMethod)); proc.Append(proc.Create(OpCodes.Newobj, Helpers.MakeHostInstanceGeneric(_atomPushCtor, type))); } else { proc.Append(proc.Create(OpCodes.Ldnull)); } proc.Append(proc.Create(OpCodes.Ldc_I4_0)); //keepAlive = false proc.Append(proc.Create(OpCodes.Ldc_I4_0)); //requireReaction = false proc.Append(proc.Create(OpCodes.Ldnull)); //onActive = null proc.Append(proc.Create(OpCodes.Ldnull)); //onInactive = null proc.Append(proc.Create(OpCodes.Ldnull)); //comparer = null //invoke Atom.Computed(pull, push, keepAlive, requiredReaction, onActive, onInactive, comparer) proc.Append(proc.Create(OpCodes.Call, Helpers.MakeGenericMethod(_atomFactoryComputed, type))); // duplicate created Atom proc.Append(proc.Create(OpCodes.Dup)); //pop created atom and save it to local variable proc.Append(proc.Create(OpCodes.Stloc_0)); //pop atom and save it to class field (now stack is empty) proc.Append(proc.Create(OpCodes.Stfld, field)); //load atom onto stack proc.Append(proc.Create(OpCodes.Ldloc_0)); } //use atom var brTarget = generate(proc); proc.InsertAfter(br, proc.Create(OpCodes.Brtrue_S, brTarget)); // return proc.Append(proc.Create(OpCodes.Ret)); }