예제 #1
0
        public static Instruction[] GetReadValue(ModuleDefinition module, TypeReference type, ILProcessor il, ParameterDefinition reader, ParameterDefinition options, ParameterDefinition value, VariableDefinition resolverVariable)
        {
            type = module.ImportReference(type);

            List <Instruction> ins = new List <Instruction>();

            bool isStandard = IsStandardReadType(type);

            ins.Add(ILHelper.Ldarg(il, value));

            if (!isStandard)
            {
                if (resolverVariable == null)
                {
                    throw new ArgumentNullException(nameof(resolverVariable), "If you don't provide a getResolver call, you'll need to provide a resolver variable.");
                }

                ins.AddRange(ILHelper.Ldloc(resolverVariable));
                ins.Add(Instruction.Create(OpCodes.Call, module.ImportReference(module.ImportReference(typeof(FormatterResolverExtensions).GetMethod("GetFormatterWithVerify")).MakeGenericMethod(type))));
            }
            else
            {
                ins.Add(ILHelper.Ldarg(il, reader));
            }

            MethodReference readMethod;

            if (type.Is <byte>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadByte));
            }
            else if (type.Is <sbyte>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadSByte));
            }
            else if (type.Is <short>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadInt16));
            }
            else if (type.Is <ushort>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadUInt16));
            }
            else if (type.Is <int>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadInt32));
            }
            else if (type.Is <uint>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadUInt32));
            }
            else if (type.Is <long>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadInt64));
            }
            else if (type.Is <ulong>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadUInt64));
            }
            else if (type.Is <string>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadString));
            }
            else if (type.Is <char>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadChar));
            }
            else if (type.Is <bool>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadBoolean));
            }
            else if (type.Is <float>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadSingle));
            }
            else if (type.Is <double>())
            {
                readMethod = module.GetMethod(typeof(MessagePackReader), nameof(MessagePackReader.ReadDouble));
            }
            else
            {
                ins.Add(ILHelper.Ldarg(il, reader));
                ins.Add(ILHelper.Ldarg(il, options));
                readMethod = module.ImportReference(typeof(IMessagePackFormatter <>).GetMethod("Deserialize")).MakeHostInstanceGeneric(module.ImportReference(typeof(IMessagePackFormatter <>)).MakeGenericInstanceType(type));
            }

            ins.Add(Instruction.Create(isStandard ? OpCodes.Call : OpCodes.Callvirt, readMethod));

            Instruction finish;

            if (type.Is <sbyte>() || type.Is <byte>())
            {
                finish = Instruction.Create(OpCodes.Stind_I1);
            }
            else if (type.Is <short>() || type.Is <ushort>())
            {
                finish = Instruction.Create(OpCodes.Stind_I2);
            }
            else if (type.Is <int>() || type.Is <uint>())
            {
                finish = Instruction.Create(OpCodes.Stind_I4);
            }
            else if (type.Is <long>() || type.Is <ulong>())
            {
                finish = Instruction.Create(OpCodes.Stind_I8);
            }
            else if (type.Is <float>())
            {
                finish = Instruction.Create(OpCodes.Stind_R4);
            }
            else if (type.Is <double>())
            {
                finish = Instruction.Create(OpCodes.Stind_R8);
            }
            else if (type.IsValueType)
            {
                finish = Instruction.Create(OpCodes.Stobj, type);
            }
            else
            {
                finish = Instruction.Create(OpCodes.Stind_Ref);
            }

            ins.Add(finish);

            return(ins.ToArray());
        }
예제 #2
0
        public static Instruction[] GetKeyCheck(MethodDefinition method,
                                                VariableDefinition key,
                                                VariableDefinition stringKey,
                                                VariableDefinition keyLength,
                                                FieldDefinition field,
                                                MethodDefinition fieldSpan,
                                                out Instruction lengthLast,
                                                out Instruction checkLast,
                                                out bool isAdvanced)
        {
            Span <byte> binary = utf8.GetBytes(field.Name).AsSpan();

            switch (binary.Length)
            {
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
                isAdvanced = false;
                return(ByteKeyNameCheck(out lengthLast, out checkLast));

            default:
                isAdvanced = true;
                return(SequenceEqualsCheck(binary.Length, out lengthLast, out checkLast));
            }

            Instruction[] ByteKeyNameCheck(out Instruction length, out Instruction check)
            {
                ulong id = GetKeyName(field.Name);

                List <Instruction> i = new List <Instruction>();

                i.AddRange(ILHelper.Ldloc(keyLength));

                length = ILHelper.Int(field.Name.Length);
                i.Add(length);

                i.AddRange(ILHelper.Ldloc(key));
                i.Add(ILHelper.ULong(id));

                if (id < int.MaxValue)
                {
                    i.Add(Instruction.Create(OpCodes.Conv_I8));
                }

                check = i[i.Count - 1];

                return(i.ToArray());
            }

            Instruction[] SequenceEqualsCheck(int binaryLength, out Instruction length, out Instruction last)
            {
                VariableDefinition v = method.AddLocalVariable(method.Module.ImportReference(typeof(ReadOnlySpan <byte>)));

                MethodReference seqEqual = null;

                MethodInfo[] methods = typeof(MemoryExtensions).GetMethods();
                for (int j = 0; j < methods.Length; j++)
                {
                    if (methods[j].Name == "SequenceEqual")
                    {
                        ParameterInfo[] para = methods[j].GetParameters();
                        if (para.Length == 2 && IsSameType(para[0].ParameterType, typeof(ReadOnlySpan <>)) && IsSameType(para[1].ParameterType, typeof(ReadOnlySpan <>)))
                        {
                            seqEqual = method.Module.ImportReference(methods[j]).MakeGenericMethod(method.Module.GetTypeReference <byte>());
                            break;
                        }
                    }
                }

                if (seqEqual == null)
                {
                    throw new NullReferenceException("Couldn't find the sequence equals method.");
                }

                List <Instruction> i = new List <Instruction>();

                i.AddRange(ILHelper.Ldloc(keyLength));

                length = ILHelper.Int(field.Name.Length);
                i.Add(length);

                i.AddRange(ILHelper.Ldloc(stringKey));
                i.Add(Instruction.Create(OpCodes.Call, fieldSpan));
                i.AddRange(ILHelper.Stloc(v));
                i.AddRange(ILHelper.Ldloc(v, true));
                i.Add(ILHelper.Int(GetHeaderLength(binaryLength)));
                i.Add(Instruction.Create(OpCodes.Call, method.Module.ImportReference(typeof(ReadOnlySpan <byte>).GetMethod("Slice", new[] { typeof(int) }))));
                i.Add(Instruction.Create(OpCodes.Call, seqEqual));

                last = i[i.Count - 1];

                return(i.ToArray());

                bool IsSameType(Type typeA, Type typeB)
                {
                    return($"{typeA.Namespace}.{typeA.Name}" == typeB.FullName);
                }
            }
        }