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()); }
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); } } }