private static Action <ILGenerator> GenerateNestedFunc2(Type stateType, MethodInfo methodInfo) { var className = $"TupacAmaru.Yacep.DynamicAssembly.Functions.Function{NameCounter.GetCurrentCount()}"; var typeBuilder = dynamicModule.DefineType(className, TypeAttributes.Public | TypeAttributes.Sealed); var target = typeBuilder.DefineField("_target", stateType, FieldAttributes.Private | FieldAttributes.InitOnly); var ctor = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.HasThis, new[] { stateType }); var ctorIl = ctor.GetILGenerator(); ctorIl.Emit(OpCodes.Ldarg_0); ctorIl.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); ctorIl.Emit(OpCodes.Ldarg_0); ctorIl.Emit(OpCodes.Ldarg_1); ctorIl.Emit(OpCodes.Stfld, target); ctorIl.Emit(OpCodes.Ret); var methodName = $"FuncProxy{NameCounter.GetCurrentCount()}"; var proxyMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.Standard, typeof(object), new[] { typeof(object[]) }); var proxyMethodIl = proxyMethod.GetILGenerator(); var parameters = methodInfo.GetParameters(); var num = parameters.Length; proxyMethodIl.Emit(OpCodes.Ldarg_0); proxyMethodIl.Emit(OpCodes.Ldfld, target); for (var i = 0; i < num; i++) { var parameterInfo = parameters[i]; var parameterType = parameterInfo.ParameterType; proxyMethodIl.Emit(OpCodes.Ldarg_1); proxyMethodIl.Emit(OpCodes.Ldc_I4_S, i); proxyMethodIl.Emit(OpCodes.Ldelem_Ref); proxyMethodIl.Emit(parameterType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, parameterType); } proxyMethodIl.Emit(OpCodes.Callvirt, methodInfo); if (methodInfo.ReturnType == typeof(void)) { proxyMethodIl.Emit(OpCodes.Ldnull); } else if (methodInfo.ReturnType.IsValueType) { proxyMethodIl.Emit(OpCodes.Box, methodInfo.ReturnType); } proxyMethodIl.Emit(OpCodes.Ret); var type = typeBuilder.CreateTypeInfo().AsType(); var ctorInfo = type.GetConstructor(new[] { stateType }); var proxyMethodInfo = type.GetMethod(methodName); return(il => { il.Emit(OpCodes.Newobj, ctorInfo); il.Emit(OpCodes.Ldftn, proxyMethodInfo); il.Emit(OpCodes.Newobj, Delegates.NewObjectArrayArgumentFunc); }); }
private static FieldBuilder GetOrAddValue <V>(TypeBuilder typeBuilder, Conjunction <V> conjunction, string symbol, Type fieldType, V value) { if (conjunction.TryGetValue(symbol, out var definedValue)) { return(definedValue); } var field = typeBuilder.DefineField($"_f{NameCounter.GetCurrentCount()}", fieldType, FieldAttributes.Private | FieldAttributes.InitOnly); conjunction.Add(symbol, field, value); return(field); }
public IEvaluator <TState> Compile <TState>(EvaluableExpression expression) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var className = $"TupacAmaru.Yacep.DynamicAssembly.Workers.Worker{NameCounter.GetCurrentCount()}"; var typeBuilder = dynamicModule.DefineType(className, TypeAttributes.Public | TypeAttributes.Sealed); var compileContext = new CompileContext(typeBuilder); var methodName = "Execute"; GenerateExecuteMethod <TState>(expression, typeBuilder, methodName, compileContext); GenerateConstructor(compileContext); var workerType = typeBuilder.CreateTypeInfo().AsType(); return(CreateEvaluator <TState>(workerType, workerType.GetMethod(methodName), compileContext)); }
private static EvaluableExpression TryGenerateObjectMemberIL(Type stateType, ObjectMemberExpression objectMemberExpression, ILGenerator iLGenerator, CompileContext compileContext) { var unresolvedExpression = objectMemberExpression; var stack = new Stack <(string memberName, object indexerValue)>(); while (true) { var target = unresolvedExpression.Object; if (target is IdentifierExpression maybeIdentifier) { if (unresolvedExpression.IsIndexer) { if (unresolvedExpression.Member is ConstantExpression constantExpression) { stack.Push(("", constantExpression.Value)); stack.Push((maybeIdentifier.Name, null)); break; } if (unresolvedExpression.Member is LiteralExpression literalExpression && literalExpression.LiteralValue.Value != null) { stack.Push(("", literalExpression.LiteralValue.Value)); stack.Push((maybeIdentifier.Name, null)); break; } } else { var identifierExpression = (IdentifierExpression)unresolvedExpression.Member; stack.Push((identifierExpression.Name, null)); stack.Push((maybeIdentifier.Name, null)); break; } stack.Clear(); return(objectMemberExpression); } var member = unresolvedExpression.Member; if (unresolvedExpression.IsIndexer) { switch (member) { case ConstantExpression constantExpression: stack.Push(("", constantExpression.Value)); break; case LiteralExpression literalExpression when literalExpression.LiteralValue.Value != null: stack.Push(("", literalExpression.LiteralValue.Value)); break; default: stack.Clear(); return(objectMemberExpression); } } else { var identifierExpression = (IdentifierExpression)unresolvedExpression.Member; stack.Push((identifierExpression.Name, null)); } if (target is ObjectMemberExpression objectMember) { unresolvedExpression = objectMember; } else { stack.Clear(); return(objectMemberExpression); } } var currentType = stateType; var first = stack.Peek(); if (string.Equals("this", first.memberName, StringComparison.Ordinal)) { stack.Pop(); } var readers = new List <Action <CompileContext, ILGenerator> > { (c, il) => il.Emit(OpCodes.Ldarg_1) }; while (stack.Count > 0) { var(memberName, indexerValue) = stack.Pop(); if (indexerValue != null) { var indexerType = indexerValue.GetType(); var method = currentType.GetMethod("Get", new[] { indexerType }) ?? currentType.GetMethod("get_Item", new[] { indexerType }); if (method != null) { currentType = method.ReturnType; readers.Add((context, il) => { var valueName = $"_v{NameCounter.GetCurrentCount()}"; GenerateValue(il, indexerValue, context, valueName, false); il.Emit(OpCodes.Callvirt, method); }); continue; } if (indexerValue is string stringValue) { memberName = stringValue; } else { return(objectMemberExpression); } } if (!string.IsNullOrWhiteSpace(memberName)) { var propertyInfo = currentType.GetProperty(memberName); if (propertyInfo != null && propertyInfo.CanRead) { var getter = propertyInfo.GetGetMethod(); if (getter != null) { currentType = propertyInfo.PropertyType; readers.Add((context, il) => il.Emit(OpCodes.Callvirt, getter)); continue; } } var fieldInfo = currentType.GetField(memberName); if (fieldInfo != null) { currentType = fieldInfo.FieldType; readers.Add((context, il) => il.Emit(OpCodes.Ldfld, fieldInfo)); continue; } var method = currentType.GetMethod("get_Item", new[] { typeof(string) }) ?? currentType.GetMethod("Get", new[] { typeof(string) }) ?? currentType.GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary <,>) && x.GetGenericArguments()[0] == typeof(string))?.GetMethod("get_Item"); if (method != null) { currentType = method.ReturnType; readers.Add((context, il) => { il.Emit(OpCodes.Ldstr, memberName); il.Emit(OpCodes.Callvirt, method); }); continue; } var methodInfo = currentType.GetMethod(memberName); if (methodInfo != null) { var type = currentType; readers.Add((context, il) => GenerateNestedFunc2(type, methodInfo)(il)); currentType = typeof(Func <object[], object>); continue; } } return(objectMemberExpression); } foreach (var reader in readers) { reader(compileContext, iLGenerator); } if (currentType.IsValueType) { iLGenerator.Emit(OpCodes.Box, currentType); } return(null); }