Пример #1
0
        private static void Cast(ILGenerator il, CacheMethod method, int locals)
        {
            if (method.AsyncType == null)
            {
                return;
            }

            var returnType = (method.RawType ?? method.ValueType) == typeof(void) ? typeof(ValueTask) : typeof(ValueTask <>).MakeGenericType(method.RawType ?? method.ValueType);

            if (returnType == method.Method.ReturnType && !(method.Method.ReturnType == typeof(ValueTask) && method.RawType != null))
            {
                return;
            }

            if (method.Method.ReturnType == typeof(ValueTask))
            {
                il.Emit(OpCodes.Call, ConvertMethod.MakeGenericMethod(method.RawType));
            }
            else
            {
                il.DeclareLocal(returnType);

                Stloc(il, locals);

                il.Emit(OpCodes.Ldloca_S, locals);

                il.Emit(OpCodes.Call, returnType.GetMethod(nameof(ValueTask.AsTask)));
            }
        }
Пример #2
0
        private static void BuildSet(CacheMethod method, ILGenerator il, int defaultTtl)
        {
            Ldarg(il, method.Value + 1);

            var locals = 0;

            if (LdTtl(method, il, locals, defaultTtl))
            {
                locals++;
            }

            if (method.When > 0)
            {
                Ldarg(il, method.When + 1);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4_0);
            }

            if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
            {
                locals++;
            }

            BuildCacheMethod(method, locals, il,
                             nameof(CacheHelper.Set), nameof(CacheHelper.SetAsync),
                             method.Method.GetParameters()[0].ParameterType,
                             method.Method.GetParameters()[method.Value].ParameterType);
        }
Пример #3
0
        private static void BuildGet(CacheMethod method, ILGenerator il, int defaultTtl)
        {
            var keyType = method.Method.GetParameters()[0].ParameterType;

            if (method.Method.IsAbstract && method.Value < 1)
            {
                var locals = 0;
                if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
                {
                    locals++;
                }

                BuildCacheMethod(method, locals, il, nameof(CacheHelper.Get), nameof(CacheHelper.GetAsync), keyType, method.ValueType !);
            }
            else
            {
                BuildFunc(method, il, keyType, method.ValueType !);

                var locals = 0;
                if (LdTtl(method, il, locals, defaultTtl))
                {
                    locals++;
                }
                if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
                {
                    locals++;
                }

                BuildCacheMethod(method, locals, il, nameof(CacheHelper.GetOrSet), nameof(CacheHelper.GetOrSetAsync), keyType, method.ValueType !);
            }
        }
Пример #4
0
        private void BuildGet(CacheMethod method, ILGenerator il, int defaultTtl)
        {
            var keyType = method.Method.GetParameters()[0].ParameterType;

#if BuildTask
            if (method.Method.Resolve().IsAbstract&& method.Value < 1)
#else
            if (method.Method.IsAbstract && method.Value < 1)
#endif
            {
                var locals = 0;
                if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
                {
                    locals++;
                }

                BuildCacheMethod(method, locals, il, nameof(CacheHelper.Get), keyType, method.WarpedValue ? method.ValueType.GetGenericArguments()[0] : method.ValueType);
            }
            else
            {
                BuildFunc(method, il, keyType, method.ValueType);

                var locals = 0;
                if (LdTtl(method, il, locals, defaultTtl))
                {
                    locals++;
                }
                if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
                {
                    locals++;
                }

                BuildCacheMethod(method, locals, il, nameof(CacheHelper.GetOrSet), keyType, method.WarpedValue ? method.ValueType.GetGenericArguments()[0] : method.ValueType);
            }
        }
Пример #5
0
        private static void BuildRemove(CacheMethod method, ILGenerator il)
        {
            var locals = 0;

            if (InitValue <CancellationToken>(method.CancellationToken, il, locals))
            {
                locals++;
            }

            BuildCacheMethod(method, locals, il, nameof(CacheHelper.Remove), nameof(CacheHelper.RemoveAsync), method.Method.GetParameters()[0].ParameterType);
        }
Пример #6
0
        private static void BuildCacheMethod(CacheMethod method, int locals, ILGenerator il,
                                             string syncMethod, string asyncMethod, params Type[] typeArguments)
        {
            if (method.AsyncType == null)
            {
                il.Emit(OpCodes.Callvirt, CacheHelperMethods[syncMethod].MakeGenericMethod(typeArguments));

                if (method.Method.ReturnType == typeof(void))
                {
                    il.Emit(OpCodes.Pop);
                }
            }
            else
            {
                il.Emit(OpCodes.Callvirt, CacheHelperMethods[asyncMethod].MakeGenericMethod(typeArguments));

                Cast(il, method, locals);
            }
        }
Пример #7
0
        private static void BuildCacheMethod(CacheMethod method, int locals, ILGenerator il,
                                             string methodName, params Type[] typeArguments)
        {
            if (method.WarpedValue)
            {
                methodName += "2";
            }

            if (method.AsyncType == null)
            {
                il.Emit(OpCodes.Callvirt, CacheHelperMethods[methodName].MakeGenericMethod(typeArguments));

                if (method.Method.ReturnType == typeof(void))
                {
                    il.Emit(OpCodes.Pop);
                }
            }
            else
            {
                il.Emit(OpCodes.Callvirt, CacheHelperMethods[methodName + "Async"].MakeGenericMethod(typeArguments));

                Cast(il, method, locals);
            }
        }
Пример #8
0
        private static bool LdTtl(CacheMethod method, ILGenerator il, int locals, int defaultTtl)
        {
            if (method.Ttl < 1)
            {
                if (defaultTtl < 1)
                {
                    return(InitValue <TimeSpan>(method.Ttl, il, locals));
                }

                il.Emit(OpCodes.Ldc_R8, (double)defaultTtl);
            }
            else
            {
                var type    = method.Method.GetParameters()[method.Ttl].ParameterType;
                var rawType = Nullable.GetUnderlyingType(type);

                if (rawType == null)
                {
                    Ldarg(il, method.Ttl + 1);
                }
                else
                {
                    il.Emit(OpCodes.Ldarga_S, method.Ttl + 1);
                }

                if (type == typeof(DateTime) ||
                    type == typeof(DateTimeOffset))
                {
                    il.Emit(OpCodes.Call, type.GetProperty(nameof(DateTime.Now)).GetMethod);
                    il.Emit(OpCodes.Call, type.GetMethod("op_Subtraction", new[] { type, type }));

                    return(false);
                }

                if (rawType == typeof(DateTime) ||
                    rawType == typeof(DateTimeOffset))
                {
                    var falseLabel = il.DefineLabel();
                    var endLabel   = il.DefineLabel();

                    il.Emit(OpCodes.Call, type.GetProperty(nameof(Nullable <TimeSpan> .HasValue)).GetMethod);
                    il.Emit(OpCodes.Brfalse_S, falseLabel);

                    il.Emit(OpCodes.Ldarga_S, method.Ttl + 1);
                    il.Emit(OpCodes.Call, type.GetProperty(nameof(Nullable <TimeSpan> .Value)).GetMethod);

                    il.Emit(OpCodes.Call, rawType.GetProperty(nameof(DateTime.Now)).GetMethod);
                    il.Emit(OpCodes.Call, rawType.GetMethod("op_Subtraction", new[] { rawType, rawType }));
                    il.Emit(OpCodes.Br_S, endLabel);

                    il.MarkLabel(falseLabel);
                    il.DeclareLocal(typeof(TimeSpan));
                    il.Emit(OpCodes.Ldloca_S, locals);
                    il.Emit(OpCodes.Initobj, typeof(TimeSpan));
                    Ldloc(il, locals);
                    il.MarkLabel(endLabel);

                    return(true);
                }

                if (rawType != null)
                {
                    il.Emit(OpCodes.Call,
                            type.GetMethod(nameof(Nullable <TimeSpan> .GetValueOrDefault),
#if NET45
                                           new Type[0]));
                }
#else
                                           Array.Empty <Type>()));
#endif
                if ((rawType ?? type) == typeof(TimeSpan))
                {
                    return(false);
                }

                if ((rawType ?? type) != typeof(double))
                {
                    if ((rawType ?? type) == typeof(uint) ||
                        (rawType ?? type) == typeof(ulong))
                    {
                        il.Emit(OpCodes.Conv_R_Un);
                    }
                    else if ((rawType ?? type) == typeof(decimal))
                    {
                        il.Emit(OpCodes.Call, typeof(decimal).GetMethods(BindingFlags.Public | BindingFlags.Static)
                                .First(m => m.Name == "op_Explicit" &&
                                       m.ReturnType == typeof(double)));
                    }

                    il.Emit(OpCodes.Conv_R8);
                }
            }

            il.Emit(OpCodes.Call, typeof(TimeSpan).GetMethod(nameof(TimeSpan.FromSeconds)));

            return(false);
        }
Пример #9
0
        private static void BuildFunc(CacheMethod method, ILGenerator il, Type keyType, Type valueType)
        {
            Type funcType;

            if (method.Method.IsAbstract)
            {
                Ldarg(il, method.Value + 1);

                funcType = method.Method.GetParameters()[method.Value].ParameterType;
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldftn, method.Method);

                var result = method.Method.GetParameters().Select(p => p.ParameterType).Union(new[] { valueType }).ToArray();
                funcType = result.Length switch
                {
                    1 => typeof(Func <>).MakeGenericType(result),
                    2 => typeof(Func <,>).MakeGenericType(result),
                    3 => typeof(Func <, ,>).MakeGenericType(result),
                    4 => typeof(Func <, , ,>).MakeGenericType(result),
                    _ => throw CacheTypeResolver.ParameterException(method.Method.DeclaringType, method.Method)
                };

                il.Emit(OpCodes.Newobj, funcType.GetConstructors()[0]);
            }

            var args = funcType.GetGenericArguments();

            Type?arg1 = null, arg2 = null, arg3 = null, returnArg = null;

            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? typeof(object) : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? typeof(object) : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? typeof(object) : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType, method.Method);
            }

            if (args[args.Length - 1].IsGenericType)
            {
                var type = args[args.Length - 1].GetGenericTypeDefinition();

                if (type == typeof(Task <>) || type == typeof(ValueTask <>))
                {
                    returnArg = type;
                }
            }

            if (arg1 != typeof(object) || arg2 != typeof(TimeSpan) || arg3 != typeof(CancellationToken) || method.AsyncType != null && returnArg != typeof(ValueTask <>))
            {
                il.Emit(OpCodes.Call, (method.AsyncType == null
                        ? FuncHelper.GetWrapMethod(arg1, arg2, arg3, returnArg)
                        : FuncHelper.GetWrapAsyncMethod(arg1, arg2, arg3, returnArg))
                        .MakeGenericMethod(keyType, method.ValueType));
            }
        }
Пример #10
0
        private void BuildFunc(CacheMethod method, ILGenerator il, Type keyType, Type valueType)
        {
#if BuildTask
            GenericInstanceType funcType;
            if (method.Method.Resolve().IsAbstract)
#else
            Type funcType;
            if (method.Method.IsAbstract)
#endif
            {
                Ldarg(il, method.Value + 1);
#if BuildTask
                funcType = (GenericInstanceType)method.Method.GetParameters()[method.Value].ParameterType;
#else
                funcType = method.Method.GetParameters()[method.Value].ParameterType;
#endif
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldftn, method.Method);

                var result = method.Method.GetParameters().Select(p => p.ParameterType).Union(new[] { valueType }).ToArray();
                funcType = result.Length switch
                {
#if BuildTask
                    1 => new GenericInstanceType(ImportType(typeof(Func <>))),
                    2 => new GenericInstanceType(ImportType(typeof(Func <,>))),
                    3 => new GenericInstanceType(ImportType(typeof(Func <, ,>))),
                    4 => new GenericInstanceType(ImportType(typeof(Func <, , ,>))),
#else
                    1 => typeof(Func <>).MakeGenericType(result),
                    2 => typeof(Func <,>).MakeGenericType(result),
                    3 => typeof(Func <, ,>).MakeGenericType(result),
                    4 => typeof(Func <, , ,>).MakeGenericType(result),
#endif
                    _ => throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method)
                };
#if BuildTask
                foreach (var p in result)
                {
                    funcType.GenericArguments.Add(p);
                }

                il.Emit(OpCodes.Newobj, Module.ImportReference(funcType.Resolve().GetConstructors().First()).CopyTo(funcType));
#else
                il.Emit(OpCodes.Newobj, funcType.GetConstructors()[0]);
#endif
            }

            var args = funcType.GetGenericArguments();

            Type?arg1 = null, arg2 = null, arg3 = null, returnArg = null;
#if BuildTask
            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? TypeSystem.Object : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? TypeSystem.Object : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? TypeSystem.Object : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method);
            }

            if (args[args.Length - 1].IsGenericInstance)
            {
                var type = args[args.Length - 1].GetElementType();

                if (type.IsType(typeof(Task <>)) || type.IsType(typeof(ValueTask <>)))
                {
                    returnArg = type;
                }
            }

            if (arg1 != null && arg1.IsType <object>() &&
                arg2 != null && arg2.IsType <TimeSpan>() &&
                arg3 != null && arg3.IsType <CancellationToken>() &&
                (method.AsyncType == null || returnArg != null && returnArg.IsType(typeof(ValueTask <>))))
            {
                return;
            }

            var fat = _helper.FuncAdapterType.MakeGenericInstanceType(keyType, method.ValueType);

            il.Emit(OpCodes.Newobj, new MethodInfo(".ctor", TypeSystem.Void, fat)
            {
                Parameters = { new ParameterBuilder(TypeSystem.Object) }, HasThis = true
            });
            il.Emit(OpCodes.Ldftn, Module.ImportReference(_helper.GetWrapMethod(method.AsyncType == null, arg1, arg2, arg3, returnArg)).CopyTo(fat));
            il.Emit(OpCodes.Newobj, Module.ImportReference(typeof(Func <, , ,>).GetConstructors()[0]).CopyTo(ImportType(typeof(Func <, , ,>)).MakeGenericInstanceType(keyType.GetElementType(), ImportType <TimeSpan>(), ImportType <CancellationToken>(), method.AsyncType == null ? method.ValueType : ImportType(typeof(ValueTask <>)).MakeGenericInstanceType(method.ValueType.GetElementType()))));
#else
            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? typeof(object) : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? typeof(object) : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? typeof(object) : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method);
            }

            if (args[args.Length - 1].IsGenericType)
            {
                var type = args[args.Length - 1].GetGenericTypeDefinition();

                if (type == typeof(Task <>) || type == typeof(ValueTask <>))
                {
                    returnArg = type;
                }
            }

            if (arg1 == typeof(object) && arg2 == typeof(TimeSpan) && arg3 == typeof(CancellationToken) &&
                (method.AsyncType == null || returnArg == typeof(ValueTask <>)))
            {
                return;
            }

            var fat = _helper.FuncAdapterType.MakeGenericType(keyType, method.ValueType);

            il.Emit(OpCodes.Newobj, fat.GetConstructors()[0]);
            il.Emit(OpCodes.Ldftn, fat.GetMethod(_helper.GetWrapMethod(method.AsyncType == null, arg1, arg2, arg3, returnArg).Name) !);
            il.Emit(OpCodes.Newobj, typeof(Func <, , ,>).MakeGenericType(keyType, typeof(TimeSpan), typeof(CancellationToken), method.AsyncType == null ? method.ValueType : typeof(ValueTask <>).MakeGenericType(method.ValueType)).GetConstructors()[0]);
#endif
        }