Browse Source

Added basic member analysis and Changed method stuff

pull/46/head
Anairkoen Schno 5 years ago
parent
commit
cf33d95ece
1 changed files with 116 additions and 8 deletions
  1. +116
    -8
      IPA.Loader/Config/Stores/GeneratedStore.cs

+ 116
- 8
IPA.Loader/Config/Stores/GeneratedStore.cs View File

@ -108,7 +108,7 @@ namespace IPA.Config.Stores
if (assembly == null) if (assembly == null)
{ {
var name = new AssemblyName("IPA.Config.Generated"); var name = new AssemblyName("IPA.Config.Generated");
assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
} }
return assembly; return assembly;
@ -126,6 +126,14 @@ namespace IPA.Config.Stores
} }
} }
private struct SerializedMemberInfo
{
public string Name;
public MemberInfo Member;
public bool IsVirtual;
public Type Type;
}
private static Func<IGeneratedStore, IConfigStore> MakeCreator(Type type) private static Func<IGeneratedStore, IConfigStore> MakeCreator(Type type)
{ {
var baseCtor = type.GetConstructor(Type.EmptyTypes); // get a default constructor var baseCtor = type.GetConstructor(Type.EmptyTypes); // get a default constructor
@ -141,6 +149,44 @@ namespace IPA.Config.Stores
var GetTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)); var GetTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle));
#region Parse base object structure
var baseChanged = type.GetMethod("Changed", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, Array.Empty<ParameterModifier>());
if (baseChanged != null && !baseChanged.IsVirtual) baseChanged = null; // limit this to just the one thing
var structure = new Dictionary<string, SerializedMemberInfo>();
// TODO: incorporate attributes
// only looks at public properties
foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var smi = new SerializedMemberInfo
{
Name = prop.Name,
Member = prop,
IsVirtual = (prop.GetGetMethod(true)?.IsVirtual ?? false) ||
(prop.GetSetMethod(true)?.IsVirtual ?? false),
Type = prop.PropertyType
};
structure.Add(smi.Name, smi);
}
// only look at public fields
foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public))
{
var smi = new SerializedMemberInfo
{
Name = field.Name,
Member = field,
IsVirtual = false,
Type = field.FieldType
};
structure.Add(smi.Name, smi);
}
#endregion
#region Constructor #region Constructor
// takes its parent // takes its parent
var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IGeneratedStore) }); var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(IGeneratedStore) });
@ -161,26 +207,38 @@ namespace IPA.Config.Stores
il.Emit(OpCodes.Call, GetTypeFromHandle); // effectively typeof(type) il.Emit(OpCodes.Call, GetTypeFromHandle); // effectively typeof(type)
il.Emit(OpCodes.Stfld, typeField); il.Emit(OpCodes.Stfld, typeField);
//il.Emit(OpCodes.Dup); // do this if there are additional initializations that need to be done to this type later
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Dup); il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Newobj, Impl.Ctor); il.Emit(OpCodes.Newobj, Impl.Ctor);
il.Emit(OpCodes.Stfld, implField); il.Emit(OpCodes.Stfld, implField);
// TODO: do additional initializations for List, etc
foreach (var kvp in structure)
EmitMemberFix(il, kvp.Value);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret); il.Emit(OpCodes.Ret);
} }
#endregion #endregion
const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; const MethodAttributes propertyMethodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
const MethodAttributes virtualPropertyMethodAttr = propertyMethodAttr | MethodAttributes.Virtual | MethodAttributes.Final;
#region IGeneratedStore #region IGeneratedStore
typeBuilder.AddInterfaceImplementation(typeof(IGeneratedStore)); typeBuilder.AddInterfaceImplementation(typeof(IGeneratedStore));
var IGeneratedStore_t = typeof(IGeneratedStore);
var IGeneratedStore_GetImpl = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Impl)).GetGetMethod();
var IGeneratedStore_GetType = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Type)).GetGetMethod();
var IGeneratedStore_GetParent = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Parent)).GetGetMethod();
var IGeneratedStore_GetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetGetMethod();
var IGeneratedStore_SetValues = IGeneratedStore_t.GetProperty(nameof(IGeneratedStore.Values)).GetSetMethod();
#region IGeneratedStore.Impl #region IGeneratedStore.Impl
var implProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Impl), PropertyAttributes.None, typeof(Impl), null); var implProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Impl), PropertyAttributes.None, typeof(Impl), null);
var implPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Impl)}", propertyMethodAttr, implProp.PropertyType, Type.EmptyTypes);
var implPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Impl)}", virtualPropertyMethodAttr, implProp.PropertyType, Type.EmptyTypes);
implProp.SetGetMethod(implPropGet); implProp.SetGetMethod(implPropGet);
typeBuilder.DefineMethodOverride(implPropGet, IGeneratedStore_GetImpl);
{ {
var il = implPropGet.GetILGenerator(); var il = implPropGet.GetILGenerator();
@ -192,8 +250,9 @@ namespace IPA.Config.Stores
#endregion #endregion
#region IGeneratedStore.Type #region IGeneratedStore.Type
var typeProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Type), PropertyAttributes.None, typeof(Type), null); var typeProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Type), PropertyAttributes.None, typeof(Type), null);
var typePropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Type)}", propertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes);
var typePropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Type)}", virtualPropertyMethodAttr, typeProp.PropertyType, Type.EmptyTypes);
typeProp.SetGetMethod(typePropGet); typeProp.SetGetMethod(typePropGet);
typeBuilder.DefineMethodOverride(typePropGet, IGeneratedStore_GetType);
{ {
var il = typePropGet.GetILGenerator(); var il = typePropGet.GetILGenerator();
@ -205,8 +264,9 @@ namespace IPA.Config.Stores
#endregion #endregion
#region IGeneratedStore.Parent #region IGeneratedStore.Parent
var parentProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Parent), PropertyAttributes.None, typeof(IGeneratedStore), null); var parentProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Parent), PropertyAttributes.None, typeof(IGeneratedStore), null);
var parentPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Parent)}", propertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes);
var parentPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Parent)}", virtualPropertyMethodAttr, parentProp.PropertyType, Type.EmptyTypes);
parentProp.SetGetMethod(parentPropGet); parentProp.SetGetMethod(parentPropGet);
typeBuilder.DefineMethodOverride(parentPropGet, IGeneratedStore_GetParent);
{ {
var il = parentPropGet.GetILGenerator(); var il = parentPropGet.GetILGenerator();
@ -218,10 +278,12 @@ namespace IPA.Config.Stores
#endregion #endregion
#region IGeneratedStore.Values #region IGeneratedStore.Values
var valuesProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Values), PropertyAttributes.None, typeof(Value), null); var valuesProp = typeBuilder.DefineProperty(nameof(IGeneratedStore.Values), PropertyAttributes.None, typeof(Value), null);
var valuesPropGet = typeBuilder.DefineMethod($"get_{nameof(IGeneratedStore.Values)}", propertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes);
var valuesPropSet = typeBuilder.DefineMethod($"set_{nameof(IGeneratedStore.Values)}", propertyMethodAttr, null, new[] { valuesProp.PropertyType });
var valuesPropGet = typeBuilder.DefineMethod($"<g>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, valuesProp.PropertyType, Type.EmptyTypes);
var valuesPropSet = typeBuilder.DefineMethod($"<s>{nameof(IGeneratedStore.Values)}", virtualPropertyMethodAttr, null, new[] { valuesProp.PropertyType });
valuesProp.SetGetMethod(valuesPropGet); valuesProp.SetGetMethod(valuesPropGet);
typeBuilder.DefineMethodOverride(valuesPropGet, IGeneratedStore_GetValues);
valuesProp.SetSetMethod(valuesPropSet); valuesProp.SetSetMethod(valuesPropSet);
typeBuilder.DefineMethodOverride(valuesPropSet, IGeneratedStore_SetValues);
{ // this is non-locking because the only code that will call this will already own the correct lock { // this is non-locking because the only code that will call this will already own the correct lock
var il = valuesPropGet.GetILGenerator(); var il = valuesPropGet.GetILGenerator();
@ -242,8 +304,54 @@ namespace IPA.Config.Stores
#endregion #endregion
#endregion #endregion
#region Changed
var coreChanged = typeBuilder.DefineMethod(
"<>Changed",
MethodAttributes.Public | MethodAttributes.HideBySig,
null, Type.EmptyTypes);
{
var il = coreChanged.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, Impl.ImplSignalChangedMethod);
il.Emit(OpCodes.Ret); // simply call our impl's SignalChanged method and return
}
if (baseChanged != null) {
var changedMethod = typeBuilder.DefineMethod( // copy to override baseChanged
baseChanged.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig,
null, Type.EmptyTypes);
typeBuilder.DefineMethodOverride(changedMethod, baseChanged);
{
var il = changedMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, baseChanged); // call base
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Tailcall);
il.Emit(OpCodes.Call, coreChanged); // call back to the core change method
il.Emit(OpCodes.Ret);
}
coreChanged = changedMethod; // switch to calling this version instead of just the default
}
#endregion
// TODO: generate overrides for all the virtual properties
return null; return null;
} }
// expects the this param to be on the stack
private static void EmitMemberFix(ILGenerator il, SerializedMemberInfo member)
{
}
} }
} }

Loading…
Cancel
Save