1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435 |
- #if FEAT_COMPILER
- //#define DEBUG_COMPILE
- using System;
- using System.Threading;
- using ProtoBuf.Meta;
- using ProtoBuf.Serializers;
- using System.Reflection;
- using System.Reflection.Emit;
- namespace ProtoBuf.Compiler
- {
- internal readonly struct CodeLabel
- {
- public readonly Label Value;
- public readonly int Index;
- public CodeLabel(Label value, int index)
- {
- this.Value = value;
- this.Index = index;
- }
- }
- internal sealed class CompilerContext
- {
- public TypeModel Model => model;
- readonly DynamicMethod method;
- static int next;
- internal CodeLabel DefineLabel()
- {
- CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++);
- return result;
- }
- #if DEBUG_COMPILE
- static readonly string traceCompilePath;
- static CompilerContext()
- {
- traceCompilePath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(),
- "TraceCompile.txt");
- Console.WriteLine("DEBUG_COMPILE enabled; writing to " + traceCompilePath);
- }
- #endif
- [System.Diagnostics.Conditional("DEBUG_COMPILE")]
- private void TraceCompile(string value)
- {
- #if DEBUG_COMPILE
- if (!string.IsNullOrWhiteSpace(value))
- {
- using (System.IO.StreamWriter sw = System.IO.File.AppendText(traceCompilePath))
- {
- sw.WriteLine(value);
- }
- }
- #endif
- }
- internal void MarkLabel(CodeLabel label)
- {
- il.MarkLabel(label.Value);
- TraceCompile("#: " + label.Index);
- }
- public static ProtoSerializer BuildSerializer(IProtoSerializer head, TypeModel model)
- {
- Type type = head.ExpectedType;
- try
- {
- CompilerContext ctx = new CompilerContext(type, true, true, model, typeof(object));
- ctx.LoadValue(ctx.InputValue);
- ctx.CastFromObject(type);
- ctx.WriteNullCheckedTail(type, head, null);
- ctx.Emit(OpCodes.Ret);
- return (ProtoSerializer)ctx.method.CreateDelegate(
- typeof(ProtoSerializer));
- }
- catch (Exception ex)
- {
- string name = type.FullName;
- if (string.IsNullOrEmpty(name)) name = type.Name;
- throw new InvalidOperationException("It was not possible to prepare a serializer for: " + name, ex);
- }
- }
- /*public static ProtoCallback BuildCallback(IProtoTypeSerializer head)
- {
- Type type = head.ExpectedType;
- CompilerContext ctx = new CompilerContext(type, true, true);
- using (Local typedVal = new Local(ctx, type))
- {
- ctx.LoadValue(Local.InputValue);
- ctx.CastFromObject(type);
- ctx.StoreValue(typedVal);
- CodeLabel[] jumpTable = new CodeLabel[4];
- for(int i = 0 ; i < jumpTable.Length ; i++) {
- jumpTable[i] = ctx.DefineLabel();
- }
- ctx.LoadReaderWriter();
- ctx.Switch(jumpTable);
- ctx.Return();
- for(int i = 0 ; i < jumpTable.Length ; i++) {
- ctx.MarkLabel(jumpTable[i]);
- if (head.HasCallbacks((TypeModel.CallbackType)i))
- {
- head.EmitCallback(ctx, typedVal, (TypeModel.CallbackType)i);
- }
- ctx.Return();
- }
- }
-
- ctx.Emit(OpCodes.Ret);
- return (ProtoCallback)ctx.method.CreateDelegate(
- typeof(ProtoCallback));
- }*/
- public static ProtoDeserializer BuildDeserializer(IProtoSerializer head, TypeModel model)
- {
- Type type = head.ExpectedType;
- CompilerContext ctx = new CompilerContext(type, false, true, model, typeof(object));
- using (Local typedVal = new Local(ctx, type))
- {
- if (!Helpers.IsValueType(type))
- {
- ctx.LoadValue(ctx.InputValue);
- ctx.CastFromObject(type);
- ctx.StoreValue(typedVal);
- }
- else
- {
- ctx.LoadValue(ctx.InputValue);
- CodeLabel notNull = ctx.DefineLabel(), endNull = ctx.DefineLabel();
- ctx.BranchIfTrue(notNull, true);
- ctx.LoadAddress(typedVal, type);
- ctx.EmitCtor(type);
- ctx.Branch(endNull, true);
- ctx.MarkLabel(notNull);
- ctx.LoadValue(ctx.InputValue);
- ctx.CastFromObject(type);
- ctx.StoreValue(typedVal);
- ctx.MarkLabel(endNull);
- }
- head.EmitRead(ctx, typedVal);
- if (head.ReturnsValue)
- {
- ctx.StoreValue(typedVal);
- }
- ctx.LoadValue(typedVal);
- ctx.CastToObject(type);
- }
- ctx.Emit(OpCodes.Ret);
- return (ProtoDeserializer)ctx.method.CreateDelegate(
- typeof(ProtoDeserializer));
- }
- internal void Return()
- {
- Emit(OpCodes.Ret);
- }
- static bool IsObject(Type type)
- {
- return type == typeof(object);
- }
- internal void CastToObject(Type type)
- {
- if (IsObject(type))
- { }
- else if (Helpers.IsValueType(type))
- {
- il.Emit(OpCodes.Box, type);
- TraceCompile(OpCodes.Box + ": " + type);
- }
- else
- {
- il.Emit(OpCodes.Castclass, MapType(typeof(object)));
- TraceCompile(OpCodes.Castclass + ": " + type);
- }
- }
- internal void CastFromObject(Type type)
- {
- if (IsObject(type))
- { }
- else if (Helpers.IsValueType(type))
- {
- switch (MetadataVersion)
- {
- case ILVersion.Net1:
- il.Emit(OpCodes.Unbox, type);
- il.Emit(OpCodes.Ldobj, type);
- TraceCompile(OpCodes.Unbox + ": " + type);
- TraceCompile(OpCodes.Ldobj + ": " + type);
- break;
- default:
- il.Emit(OpCodes.Unbox_Any, type);
- TraceCompile(OpCodes.Unbox_Any + ": " + type);
- break;
- }
- }
- else
- {
- il.Emit(OpCodes.Castclass, type);
- TraceCompile(OpCodes.Castclass + ": " + type);
- }
- }
- private readonly bool isStatic;
- private readonly RuntimeTypeModel.SerializerPair[] methodPairs;
- internal MethodBuilder GetDedicatedMethod(int metaKey, bool read)
- {
- if (methodPairs == null) return null;
- // but if we *do* have pairs, we demand that we find a match...
- for (int i = 0; i < methodPairs.Length; i++)
- {
- if (methodPairs[i].MetaKey == metaKey) { return read ? methodPairs[i].Deserialize : methodPairs[i].Serialize; }
- }
- throw new ArgumentException("Meta-key not found", "metaKey");
- }
- internal int MapMetaKeyToCompiledKey(int metaKey)
- {
- if (metaKey < 0 || methodPairs == null) return metaKey; // all meta, or a dummy/wildcard key
- for (int i = 0; i < methodPairs.Length; i++)
- {
- if (methodPairs[i].MetaKey == metaKey) return i;
- }
- throw new ArgumentException("Key could not be mapped: " + metaKey.ToString(), "metaKey");
- }
- private readonly bool isWriter;
- private readonly bool nonPublic;
- internal bool NonPublic { get { return nonPublic; } }
- private readonly Local inputValue;
- public Local InputValue { get { return inputValue; } }
- private readonly string assemblyName;
- internal CompilerContext(ILGenerator il, bool isStatic, bool isWriter, RuntimeTypeModel.SerializerPair[] methodPairs, TypeModel model, ILVersion metadataVersion, string assemblyName, Type inputType, string traceName)
- {
- if (string.IsNullOrEmpty(assemblyName)) throw new ArgumentNullException(nameof(assemblyName));
- this.assemblyName = assemblyName;
- this.isStatic = isStatic;
- this.methodPairs = methodPairs ?? throw new ArgumentNullException(nameof(methodPairs));
- this.il = il ?? throw new ArgumentNullException(nameof(il));
- // nonPublic = false; <== implicit
- this.isWriter = isWriter;
- this.model = model ?? throw new ArgumentNullException(nameof(model));
- this.metadataVersion = metadataVersion;
- if (inputType != null) this.inputValue = new Local(null, inputType);
- TraceCompile(">> " + traceName);
- }
- private CompilerContext(Type associatedType, bool isWriter, bool isStatic, TypeModel model, Type inputType)
- {
- metadataVersion = ILVersion.Net2;
- this.isStatic = isStatic;
- this.isWriter = isWriter;
- this.model = model ?? throw new ArgumentNullException(nameof(model));
- nonPublic = true;
- Type[] paramTypes;
- Type returnType;
- if (isWriter)
- {
- returnType = typeof(void);
- paramTypes = new Type[] { typeof(object), typeof(ProtoWriter) };
- }
- else
- {
- returnType = typeof(object);
- paramTypes = new Type[] { typeof(object), typeof(ProtoReader) };
- }
- int uniqueIdentifier;
- #if PLAT_NO_INTERLOCKED
- uniqueIdentifier = ++next;
- #else
- uniqueIdentifier = Interlocked.Increment(ref next);
- #endif
- method = new DynamicMethod("proto_" + uniqueIdentifier.ToString(), returnType, paramTypes, associatedType
- #if COREFX
- .GetTypeInfo()
- #endif
- .IsInterface ? typeof(object) : associatedType, true);
- this.il = method.GetILGenerator();
- if (inputType != null) this.inputValue = new Local(null, inputType);
- TraceCompile(">> " + method.Name);
- }
- private readonly ILGenerator il;
- private void Emit(OpCode opcode)
- {
- il.Emit(opcode);
- TraceCompile(opcode.ToString());
- }
- public void LoadValue(string value)
- {
- if (value == null)
- {
- LoadNullRef();
- }
- else
- {
- il.Emit(OpCodes.Ldstr, value);
- TraceCompile(OpCodes.Ldstr + ": " + value);
- }
- }
- public void LoadValue(float value)
- {
- il.Emit(OpCodes.Ldc_R4, value);
- TraceCompile(OpCodes.Ldc_R4 + ": " + value);
- }
- public void LoadValue(double value)
- {
- il.Emit(OpCodes.Ldc_R8, value);
- TraceCompile(OpCodes.Ldc_R8 + ": " + value);
- }
- public void LoadValue(long value)
- {
- il.Emit(OpCodes.Ldc_I8, value);
- TraceCompile(OpCodes.Ldc_I8 + ": " + value);
- }
- public void LoadValue(int value)
- {
- switch (value)
- {
- case 0: Emit(OpCodes.Ldc_I4_0); break;
- case 1: Emit(OpCodes.Ldc_I4_1); break;
- case 2: Emit(OpCodes.Ldc_I4_2); break;
- case 3: Emit(OpCodes.Ldc_I4_3); break;
- case 4: Emit(OpCodes.Ldc_I4_4); break;
- case 5: Emit(OpCodes.Ldc_I4_5); break;
- case 6: Emit(OpCodes.Ldc_I4_6); break;
- case 7: Emit(OpCodes.Ldc_I4_7); break;
- case 8: Emit(OpCodes.Ldc_I4_8); break;
- case -1: Emit(OpCodes.Ldc_I4_M1); break;
- default:
- if (value >= -128 && value <= 127)
- {
- il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
- TraceCompile(OpCodes.Ldc_I4_S + ": " + value);
- }
- else
- {
- il.Emit(OpCodes.Ldc_I4, value);
- TraceCompile(OpCodes.Ldc_I4 + ": " + value);
- }
- break;
- }
- }
- MutableList locals = new MutableList();
- internal LocalBuilder GetFromPool(Type type)
- {
- int count = locals.Count;
- for (int i = 0; i < count; i++)
- {
- LocalBuilder item = (LocalBuilder)locals[i];
- if (item != null && item.LocalType == type)
- {
- locals[i] = null; // remove from pool
- return item;
- }
- }
- LocalBuilder result = il.DeclareLocal(type);
- TraceCompile("$ " + result + ": " + type);
- return result;
- }
- //
- internal void ReleaseToPool(LocalBuilder value)
- {
- int count = locals.Count;
- for (int i = 0; i < count; i++)
- {
- if (locals[i] == null)
- {
- locals[i] = value; // released into existing slot
- return;
- }
- }
- locals.Add(value); // create a new slot
- }
- public void LoadReaderWriter()
- {
- Emit(isStatic ? OpCodes.Ldarg_1 : OpCodes.Ldarg_2);
- }
- public void StoreValue(Local local)
- {
- if (local == this.InputValue)
- {
- byte b = isStatic ? (byte)0 : (byte)1;
- il.Emit(OpCodes.Starg_S, b);
- TraceCompile(OpCodes.Starg_S + ": $" + b);
- }
- else
- {
- switch (local.Value.LocalIndex)
- {
- case 0: Emit(OpCodes.Stloc_0); break;
- case 1: Emit(OpCodes.Stloc_1); break;
- case 2: Emit(OpCodes.Stloc_2); break;
- case 3: Emit(OpCodes.Stloc_3); break;
- default:
- OpCode code = UseShortForm(local) ? OpCodes.Stloc_S : OpCodes.Stloc;
- il.Emit(code, local.Value);
- TraceCompile(code + ": $" + local.Value);
- break;
- }
- }
- }
- public void LoadValue(Local local)
- {
- if (local == null) { /* nothing to do; top of stack */}
- else if (local == this.InputValue)
- {
- Emit(isStatic ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1);
- }
- else
- {
- switch (local.Value.LocalIndex)
- {
- case 0: Emit(OpCodes.Ldloc_0); break;
- case 1: Emit(OpCodes.Ldloc_1); break;
- case 2: Emit(OpCodes.Ldloc_2); break;
- case 3: Emit(OpCodes.Ldloc_3); break;
- default:
- OpCode code = UseShortForm(local) ? OpCodes.Ldloc_S : OpCodes.Ldloc;
- il.Emit(code, local.Value);
- TraceCompile(code + ": $" + local.Value);
- break;
- }
- }
- }
- public Local GetLocalWithValue(Type type, Compiler.Local fromValue)
- {
- if (fromValue != null)
- {
- if (fromValue.Type == type) return fromValue.AsCopy();
- // otherwise, load onto the stack and let the default handling (below) deal with it
- LoadValue(fromValue);
- if (!Helpers.IsValueType(type) && (fromValue.Type == null || !type.IsAssignableFrom(fromValue.Type)))
- { // need to cast
- Cast(type);
- }
- }
- // need to store the value from the stack
- Local result = new Local(this, type);
- StoreValue(result);
- return result;
- }
- internal void EmitBasicRead(string methodName, Type expectedType)
- {
- MethodInfo method = MapType(typeof(ProtoReader)).GetMethod(
- methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- if (method == null || method.ReturnType != expectedType
- || method.GetParameters().Length != 0) throw new ArgumentException("methodName");
- LoadReaderWriter();
- EmitCall(method);
- }
- internal void EmitBasicRead(Type helperType, string methodName, Type expectedType)
- {
- MethodInfo method = helperType.GetMethod(
- methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- if (method == null || method.ReturnType != expectedType
- || method.GetParameters().Length != 1) throw new ArgumentException("methodName");
- LoadReaderWriter();
- EmitCall(method);
- }
- internal void EmitBasicWrite(string methodName, Compiler.Local fromValue)
- {
- if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName");
- LoadValue(fromValue);
- LoadReaderWriter();
- EmitCall(GetWriterMethod(methodName));
- }
- private MethodInfo GetWriterMethod(string methodName)
- {
- Type writerType = MapType(typeof(ProtoWriter));
- MethodInfo[] methods = writerType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- foreach (MethodInfo method in methods)
- {
- if (method.Name != methodName) continue;
- ParameterInfo[] pis = method.GetParameters();
- if (pis.Length == 2 && pis[1].ParameterType == writerType) return method;
- }
- throw new ArgumentException("No suitable method found for: " + methodName, "methodName");
- }
- internal void EmitWrite(Type helperType, string methodName, Compiler.Local valueFrom)
- {
- if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName");
- MethodInfo method = helperType.GetMethod(
- methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
- if (method == null || method.ReturnType != MapType(typeof(void))) throw new ArgumentException("methodName");
- LoadValue(valueFrom);
- LoadReaderWriter();
- EmitCall(method);
- }
- public void EmitCall(MethodInfo method) { EmitCall(method, null); }
- public void EmitCall(MethodInfo method, Type targetType)
- {
- Helpers.DebugAssert(method != null);
- MemberInfo member = method;
- CheckAccessibility(ref member);
- OpCode opcode;
- if (method.IsStatic || Helpers.IsValueType(method.DeclaringType))
- {
- opcode = OpCodes.Call;
- }
- else
- {
- opcode = OpCodes.Callvirt;
- if (targetType != null && Helpers.IsValueType(targetType) && !Helpers.IsValueType(method.DeclaringType))
- {
- Constrain(targetType);
- }
- }
- il.EmitCall(opcode, method, null);
- TraceCompile(opcode + ": " + method + " on " + method.DeclaringType + (targetType == null ? "" : (" via " + targetType)));
- }
- /// <summary>
- /// Pushes a null reference onto the stack. Note that this should only
- /// be used to return a null (or set a variable to null); for null-tests
- /// use BranchIfTrue / BranchIfFalse.
- /// </summary>
- public void LoadNullRef()
- {
- Emit(OpCodes.Ldnull);
- }
- private int nextLabel;
- internal void WriteNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom)
- {
- if (Helpers.IsValueType(type))
- {
- Type underlyingType = Helpers.GetUnderlyingType(type);
- if (underlyingType == null)
- { // not a nullable T; can invoke directly
- tail.EmitWrite(this, valueFrom);
- }
- else
- { // nullable T; check HasValue
- using (Compiler.Local valOrNull = GetLocalWithValue(type, valueFrom))
- {
- LoadAddress(valOrNull, type);
- LoadValue(type.GetProperty("HasValue"));
- CodeLabel @end = DefineLabel();
- BranchIfFalse(@end, false);
- LoadAddress(valOrNull, type);
- EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes));
- tail.EmitWrite(this, null);
- MarkLabel(@end);
- }
- }
- }
- else
- { // ref-type; do a null-check
- LoadValue(valueFrom);
- CopyValue();
- CodeLabel hasVal = DefineLabel(), @end = DefineLabel();
- BranchIfTrue(hasVal, true);
- DiscardValue();
- Branch(@end, false);
- MarkLabel(hasVal);
- tail.EmitWrite(this, null);
- MarkLabel(@end);
- }
- }
- internal void ReadNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom)
- {
- Type underlyingType;
- if (Helpers.IsValueType(type) && (underlyingType = Helpers.GetUnderlyingType(type)) != null)
- {
- if (tail.RequiresOldValue)
- {
- // we expect the input value to be in valueFrom; need to unpack it from T?
- using (Local loc = GetLocalWithValue(type, valueFrom))
- {
- LoadAddress(loc, type);
- EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes));
- }
- }
- else
- {
- Helpers.DebugAssert(valueFrom == null); // not expecting a valueFrom in this case
- }
- tail.EmitRead(this, null); // either unwrapped on the stack or not provided
- if (tail.ReturnsValue)
- {
- // now re-wrap the value
- EmitCtor(type, underlyingType);
- }
- return;
- }
- // either a ref-type of a non-nullable struct; treat "as is", even if null
- // (the type-serializer will handle the null case; it needs to allow null
- // inputs to perform the correct type of subclass creation)
- tail.EmitRead(this, valueFrom);
- }
- public void EmitCtor(Type type)
- {
- EmitCtor(type, Helpers.EmptyTypes);
- }
- public void EmitCtor(ConstructorInfo ctor)
- {
- if (ctor == null) throw new ArgumentNullException("ctor");
- MemberInfo ctorMember = ctor;
- CheckAccessibility(ref ctorMember);
- il.Emit(OpCodes.Newobj, ctor);
- TraceCompile(OpCodes.Newobj + ": " + ctor.DeclaringType);
- }
- public void InitLocal(Type type, Compiler.Local target)
- {
- LoadAddress(target, type, evenIfClass: true); // for class, initobj is a load-null, store-indirect
- il.Emit(OpCodes.Initobj, type);
- TraceCompile(OpCodes.Initobj + ": " + type);
- }
- public void EmitCtor(Type type, params Type[] parameterTypes)
- {
- Helpers.DebugAssert(type != null);
- Helpers.DebugAssert(parameterTypes != null);
- if (Helpers.IsValueType(type) && parameterTypes.Length == 0)
- {
- il.Emit(OpCodes.Initobj, type);
- TraceCompile(OpCodes.Initobj + ": " + type);
- }
- else
- {
- ConstructorInfo ctor = Helpers.GetConstructor(type
- #if COREFX
- .GetTypeInfo()
- #endif
- , parameterTypes, true);
- if (ctor == null) throw new InvalidOperationException("No suitable constructor found for " + type.FullName);
- EmitCtor(ctor);
- }
- }
- BasicList knownTrustedAssemblies, knownUntrustedAssemblies;
- bool InternalsVisible(Assembly assembly)
- {
- if (string.IsNullOrEmpty(assemblyName)) return false;
- if (knownTrustedAssemblies != null)
- {
- if (knownTrustedAssemblies.IndexOfReference(assembly) >= 0)
- {
- return true;
- }
- }
- if (knownUntrustedAssemblies != null)
- {
- if (knownUntrustedAssemblies.IndexOfReference(assembly) >= 0)
- {
- return false;
- }
- }
- bool isTrusted = false;
- Type attributeType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute));
- if (attributeType == null) return false;
- #if COREFX
- foreach (System.Runtime.CompilerServices.InternalsVisibleToAttribute attrib in assembly.GetCustomAttributes(attributeType))
- #else
- foreach (System.Runtime.CompilerServices.InternalsVisibleToAttribute attrib in assembly.GetCustomAttributes(attributeType, false))
- #endif
- {
- if (attrib.AssemblyName == assemblyName || attrib.AssemblyName.StartsWith(assemblyName + ","))
- {
- isTrusted = true;
- break;
- }
- }
- if (isTrusted)
- {
- if (knownTrustedAssemblies == null) knownTrustedAssemblies = new BasicList();
- knownTrustedAssemblies.Add(assembly);
- }
- else
- {
- if (knownUntrustedAssemblies == null) knownUntrustedAssemblies = new BasicList();
- knownUntrustedAssemblies.Add(assembly);
- }
- return isTrusted;
- }
- internal void CheckAccessibility(ref MemberInfo member)
- {
- if (member == null)
- {
- throw new ArgumentNullException(nameof(member));
- }
- #if !COREFX
- Type type;
- #endif
- if (!NonPublic)
- {
- if (member is FieldInfo && member.Name.StartsWith("<") & member.Name.EndsWith(">k__BackingField"))
- {
- var propName = member.Name.Substring(1, member.Name.Length - 17);
- var prop = member.DeclaringType.GetProperty(propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
- if (prop != null) member = prop;
- }
- bool isPublic;
- #if COREFX
- if (member is TypeInfo)
- {
- TypeInfo ti = (TypeInfo)member;
- do
- {
- isPublic = ti.IsNestedPublic || ti.IsPublic || ((ti.IsNested || ti.IsNestedAssembly || ti.IsNestedFamORAssem) && InternalsVisible(ti.Assembly));
- } while (isPublic && ti.IsNested && (ti = ti.DeclaringType.GetTypeInfo()) != null);
- }
- else if (member is FieldInfo)
- {
- FieldInfo field = ((FieldInfo)member);
- isPublic = field.IsPublic || ((field.IsAssembly || field.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(field.DeclaringType)));
- }
- else if (member is PropertyInfo)
- {
- isPublic = true; // defer to get/set
- }
- else if (member is ConstructorInfo)
- {
- ConstructorInfo ctor = ((ConstructorInfo)member);
- isPublic = ctor.IsPublic || ((ctor.IsAssembly || ctor.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(ctor.DeclaringType)));
- }
- else if (member is MethodInfo)
- {
- MethodInfo method = ((MethodInfo)member);
- isPublic = method.IsPublic || ((method.IsAssembly || method.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(method.DeclaringType)));
- if (!isPublic)
- {
- // allow calls to TypeModel protected methods, and methods we are in the process of creating
- if (
- member is MethodBuilder ||
- member.DeclaringType == MapType(typeof(TypeModel)))
- isPublic = true;
- }
- }
- else
- {
- throw new NotSupportedException(member.GetType().Name);
- }
- #else
- MemberTypes memberType = member.MemberType;
- switch (memberType)
- {
- case MemberTypes.TypeInfo:
- // top-level type
- type = (Type)member;
- isPublic = type.IsPublic || InternalsVisible(type.Assembly);
- break;
- case MemberTypes.NestedType:
- type = (Type)member;
- do
- {
- isPublic = type.IsNestedPublic || type.IsPublic || ((type.DeclaringType == null || type.IsNestedAssembly || type.IsNestedFamORAssem) && InternalsVisible(type.Assembly));
- } while (isPublic && (type = type.DeclaringType) != null); // ^^^ !type.IsNested, but not all runtimes have that
- break;
- case MemberTypes.Field:
- FieldInfo field = ((FieldInfo)member);
- isPublic = field.IsPublic || ((field.IsAssembly || field.IsFamilyOrAssembly) && InternalsVisible(field.DeclaringType.Assembly));
- break;
- case MemberTypes.Constructor:
- ConstructorInfo ctor = ((ConstructorInfo)member);
- isPublic = ctor.IsPublic || ((ctor.IsAssembly || ctor.IsFamilyOrAssembly) && InternalsVisible(ctor.DeclaringType.Assembly));
- break;
- case MemberTypes.Method:
- MethodInfo method = ((MethodInfo)member);
- isPublic = method.IsPublic || ((method.IsAssembly || method.IsFamilyOrAssembly) && InternalsVisible(method.DeclaringType.Assembly));
- if (!isPublic)
- {
- // allow calls to TypeModel protected methods, and methods we are in the process of creating
- if (
- member is MethodBuilder ||
- member.DeclaringType == MapType(typeof(TypeModel))) isPublic = true;
- }
- break;
- case MemberTypes.Property:
- isPublic = true; // defer to get/set
- break;
- default:
- throw new NotSupportedException(memberType.ToString());
- }
- #endif
- if (!isPublic)
- {
- #if COREFX
- if (member is TypeInfo)
- {
- throw new InvalidOperationException("Non-public type cannot be used with full dll compilation: " +
- ((TypeInfo)member).FullName);
- }
- else
- {
- throw new InvalidOperationException("Non-public member cannot be used with full dll compilation: " +
- member.DeclaringType.FullName + "." + member.Name);
- }
- #else
- switch (memberType)
- {
- case MemberTypes.TypeInfo:
- case MemberTypes.NestedType:
- throw new InvalidOperationException("Non-public type cannot be used with full dll compilation: " +
- ((Type)member).FullName);
- default:
- throw new InvalidOperationException("Non-public member cannot be used with full dll compilation: " +
- member.DeclaringType.FullName + "." + member.Name);
- }
- #endif
- }
- }
- }
- public void LoadValue(FieldInfo field)
- {
- MemberInfo member = field;
- CheckAccessibility(ref member);
- if (member is PropertyInfo)
- {
- LoadValue((PropertyInfo)member);
- }
- else
- {
- OpCode code = field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld;
- il.Emit(code, field);
- TraceCompile(code + ": " + field + " on " + field.DeclaringType);
- }
- }
- public void StoreValue(FieldInfo field)
- {
- MemberInfo member = field;
- CheckAccessibility(ref member);
- if (member is PropertyInfo)
- {
- StoreValue((PropertyInfo)member);
- }
- else
- {
- OpCode code = field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld;
- il.Emit(code, field);
- TraceCompile(code + ": " + field + " on " + field.DeclaringType);
- }
- }
- public void LoadValue(PropertyInfo property)
- {
- MemberInfo member = property;
- CheckAccessibility(ref member);
- EmitCall(Helpers.GetGetMethod(property, true, true));
- }
- public void StoreValue(PropertyInfo property)
- {
- MemberInfo member = property;
- CheckAccessibility(ref member);
- EmitCall(Helpers.GetSetMethod(property, true, true));
- }
- //internal void EmitInstance()
- //{
- // if (isStatic) throw new InvalidOperationException();
- // Emit(OpCodes.Ldarg_0);
- //}
- internal static void LoadValue(ILGenerator il, int value)
- {
- switch (value)
- {
- case 0: il.Emit(OpCodes.Ldc_I4_0); break;
- case 1: il.Emit(OpCodes.Ldc_I4_1); break;
- case 2: il.Emit(OpCodes.Ldc_I4_2); break;
- case 3: il.Emit(OpCodes.Ldc_I4_3); break;
- case 4: il.Emit(OpCodes.Ldc_I4_4); break;
- case 5: il.Emit(OpCodes.Ldc_I4_5); break;
- case 6: il.Emit(OpCodes.Ldc_I4_6); break;
- case 7: il.Emit(OpCodes.Ldc_I4_7); break;
- case 8: il.Emit(OpCodes.Ldc_I4_8); break;
- case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
- default: il.Emit(OpCodes.Ldc_I4, value); break;
- }
- }
- private bool UseShortForm(Local local)
- {
- return local.Value.LocalIndex < 256;
- }
- internal void LoadAddress(Local local, Type type, bool evenIfClass = false)
- {
- if (evenIfClass || Helpers.IsValueType(type))
- {
- if (local == null)
- {
- throw new InvalidOperationException("Cannot load the address of the head of the stack");
- }
- if (local == this.InputValue)
- {
- il.Emit(OpCodes.Ldarga_S, (isStatic ? (byte)0 : (byte)1));
- TraceCompile(OpCodes.Ldarga_S + ": $" + (isStatic ? 0 : 1));
- }
- else
- {
- OpCode code = UseShortForm(local) ? OpCodes.Ldloca_S : OpCodes.Ldloca;
- il.Emit(code, local.Value);
- TraceCompile(code + ": $" + local.Value);
- }
- }
- else
- { // reference-type; already *is* the address; just load it
- LoadValue(local);
- }
- }
- internal void Branch(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Br_S : OpCodes.Br;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal void BranchIfFalse(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Brfalse_S : OpCodes.Brfalse;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal void BranchIfTrue(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Brtrue_S : OpCodes.Brtrue;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal void BranchIfEqual(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Beq_S : OpCodes.Beq;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- //internal void TestEqual()
- //{
- // Emit(OpCodes.Ceq);
- //}
- internal void CopyValue()
- {
- Emit(OpCodes.Dup);
- }
- internal void BranchIfGreater(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Bgt_S : OpCodes.Bgt;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal void BranchIfLess(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Blt_S : OpCodes.Blt;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal void DiscardValue()
- {
- Emit(OpCodes.Pop);
- }
- public void Subtract()
- {
- Emit(OpCodes.Sub);
- }
- public void Switch(CodeLabel[] jumpTable)
- {
- const int MAX_JUMPS = 128;
- if (jumpTable.Length <= MAX_JUMPS)
- {
- // simple case
- Label[] labels = new Label[jumpTable.Length];
- for (int i = 0; i < labels.Length; i++)
- {
- labels[i] = jumpTable[i].Value;
- }
- TraceCompile(OpCodes.Switch.ToString());
- il.Emit(OpCodes.Switch, labels);
- }
- else
- {
- // too many to jump easily (especially on Android) - need to split up (note: uses a local pulled from the stack)
- using (Local val = GetLocalWithValue(MapType(typeof(int)), null))
- {
- int count = jumpTable.Length, offset = 0;
- int blockCount = count / MAX_JUMPS;
- if ((count % MAX_JUMPS) != 0) blockCount++;
- Label[] blockLabels = new Label[blockCount];
- for (int i = 0; i < blockCount; i++)
- {
- blockLabels[i] = il.DefineLabel();
- }
- CodeLabel endOfSwitch = DefineLabel();
- LoadValue(val);
- LoadValue(MAX_JUMPS);
- Emit(OpCodes.Div);
- TraceCompile(OpCodes.Switch.ToString());
- il.Emit(OpCodes.Switch, blockLabels);
- Branch(endOfSwitch, false);
- Label[] innerLabels = new Label[MAX_JUMPS];
- for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
- {
- il.MarkLabel(blockLabels[blockIndex]);
- int itemsThisBlock = Math.Min(MAX_JUMPS, count);
- count -= itemsThisBlock;
- if (innerLabels.Length != itemsThisBlock) innerLabels = new Label[itemsThisBlock];
- int subtract = offset;
- for (int j = 0; j < itemsThisBlock; j++)
- {
- innerLabels[j] = jumpTable[offset++].Value;
- }
- LoadValue(val);
- if (subtract != 0) // switches are always zero-based
- {
- LoadValue(subtract);
- Emit(OpCodes.Sub);
- }
- TraceCompile(OpCodes.Switch.ToString());
- il.Emit(OpCodes.Switch, innerLabels);
- if (count != 0)
- { // force default to the very bottom
- Branch(endOfSwitch, false);
- }
- }
- Helpers.DebugAssert(count == 0, "Should use exactly all switch items");
- MarkLabel(endOfSwitch);
- }
- }
- }
- internal void EndFinally()
- {
- il.EndExceptionBlock();
- TraceCompile("EndExceptionBlock");
- }
- internal void BeginFinally()
- {
- il.BeginFinallyBlock();
- TraceCompile("BeginFinallyBlock");
- }
- internal void EndTry(CodeLabel label, bool @short)
- {
- OpCode code = @short ? OpCodes.Leave_S : OpCodes.Leave;
- il.Emit(code, label.Value);
- TraceCompile(code + ": " + label.Index);
- }
- internal CodeLabel BeginTry()
- {
- CodeLabel label = new CodeLabel(il.BeginExceptionBlock(), nextLabel++);
- TraceCompile("BeginExceptionBlock: " + label.Index);
- return label;
- }
- internal void Constrain(Type type)
- {
- il.Emit(OpCodes.Constrained, type);
- TraceCompile(OpCodes.Constrained + ": " + type);
- }
- internal void TryCast(Type type)
- {
- il.Emit(OpCodes.Isinst, type);
- TraceCompile(OpCodes.Isinst + ": " + type);
- }
- internal void Cast(Type type)
- {
- il.Emit(OpCodes.Castclass, type);
- TraceCompile(OpCodes.Castclass + ": " + type);
- }
- public IDisposable Using(Local local)
- {
- return new UsingBlock(this, local);
- }
- private sealed class UsingBlock : IDisposable
- {
- private Local local;
- CompilerContext ctx;
- CodeLabel label;
- /// <summary>
- /// Creates a new "using" block (equivalent) around a variable;
- /// the variable must exist, and note that (unlike in C#) it is
- /// the variables *final* value that gets disposed. If you need
- /// *original* disposal, copy your variable first.
- ///
- /// It is the callers responsibility to ensure that the variable's
- /// scope fully-encapsulates the "using"; if not, the variable
- /// may be re-used (and thus re-assigned) unexpectedly.
- /// </summary>
- public UsingBlock(CompilerContext ctx, Local local)
- {
- if (ctx == null) throw new ArgumentNullException("ctx");
- if (local == null) throw new ArgumentNullException("local");
- Type type = local.Type;
- // check if **never** disposable
- if ((Helpers.IsValueType(type) || Helpers.IsSealed(type)) &&
- !ctx.MapType(typeof(IDisposable)).IsAssignableFrom(type))
- {
- return; // nothing to do! easiest "using" block ever
- // (note that C# wouldn't allow this as a "using" block,
- // but we'll be generous and simply not do anything)
- }
- this.local = local;
- this.ctx = ctx;
- label = ctx.BeginTry();
- }
- public void Dispose()
- {
- if (local == null || ctx == null) return;
- ctx.EndTry(label, false);
- ctx.BeginFinally();
- Type disposableType = ctx.MapType(typeof(IDisposable));
- MethodInfo dispose = disposableType.GetMethod("Dispose");
- Type type = local.Type;
- // remember that we've already (in the .ctor) excluded the case
- // where it *cannot* be disposable
- if (Helpers.IsValueType(type))
- {
- ctx.LoadAddress(local, type);
- switch (ctx.MetadataVersion)
- {
- case ILVersion.Net1:
- ctx.LoadValue(local);
- ctx.CastToObject(type);
- break;
- default:
- ctx.Constrain(type);
- break;
- }
- ctx.EmitCall(dispose);
- }
- else
- {
- Compiler.CodeLabel @null = ctx.DefineLabel();
- if (disposableType.IsAssignableFrom(type))
- { // *known* to be IDisposable; just needs a null-check
- ctx.LoadValue(local);
- ctx.BranchIfFalse(@null, true);
- ctx.LoadAddress(local, type);
- }
- else
- { // *could* be IDisposable; test via "as"
- using (Compiler.Local disp = new Compiler.Local(ctx, disposableType))
- {
- ctx.LoadValue(local);
- ctx.TryCast(disposableType);
- ctx.CopyValue();
- ctx.StoreValue(disp);
- ctx.BranchIfFalse(@null, true);
- ctx.LoadAddress(disp, disposableType);
- }
- }
- ctx.EmitCall(dispose);
- ctx.MarkLabel(@null);
- }
- ctx.EndFinally();
- this.local = null;
- this.ctx = null;
- label = new CodeLabel(); // default
- }
- }
- internal void Add()
- {
- Emit(OpCodes.Add);
- }
- internal void LoadLength(Local arr, bool zeroIfNull)
- {
- Helpers.DebugAssert(arr.Type.IsArray && arr.Type.GetArrayRank() == 1);
- if (zeroIfNull)
- {
- Compiler.CodeLabel notNull = DefineLabel(), done = DefineLabel();
- LoadValue(arr);
- CopyValue(); // optimised for non-null case
- BranchIfTrue(notNull, true);
- DiscardValue();
- LoadValue(0);
- Branch(done, true);
- MarkLabel(notNull);
- Emit(OpCodes.Ldlen);
- Emit(OpCodes.Conv_I4);
- MarkLabel(done);
- }
- else
- {
- LoadValue(arr);
- Emit(OpCodes.Ldlen);
- Emit(OpCodes.Conv_I4);
- }
- }
- internal void CreateArray(Type elementType, Local length)
- {
- LoadValue(length);
- il.Emit(OpCodes.Newarr, elementType);
- TraceCompile(OpCodes.Newarr + ": " + elementType);
- }
- internal void LoadArrayValue(Local arr, Local i)
- {
- Type type = arr.Type;
- Helpers.DebugAssert(type.IsArray && arr.Type.GetArrayRank() == 1);
- type = type.GetElementType();
- Helpers.DebugAssert(type != null, "Not an array: " + arr.Type.FullName);
- LoadValue(arr);
- LoadValue(i);
- switch (Helpers.GetTypeCode(type))
- {
- case ProtoTypeCode.SByte: Emit(OpCodes.Ldelem_I1); break;
- case ProtoTypeCode.Int16: Emit(OpCodes.Ldelem_I2); break;
- case ProtoTypeCode.Int32: Emit(OpCodes.Ldelem_I4); break;
- case ProtoTypeCode.Int64: Emit(OpCodes.Ldelem_I8); break;
- case ProtoTypeCode.Byte: Emit(OpCodes.Ldelem_U1); break;
- case ProtoTypeCode.UInt16: Emit(OpCodes.Ldelem_U2); break;
- case ProtoTypeCode.UInt32: Emit(OpCodes.Ldelem_U4); break;
- case ProtoTypeCode.UInt64: Emit(OpCodes.Ldelem_I8); break; // odd, but this is what C# does...
- case ProtoTypeCode.Single: Emit(OpCodes.Ldelem_R4); break;
- case ProtoTypeCode.Double: Emit(OpCodes.Ldelem_R8); break;
- default:
- if (Helpers.IsValueType(type))
- {
- il.Emit(OpCodes.Ldelema, type);
- il.Emit(OpCodes.Ldobj, type);
- TraceCompile(OpCodes.Ldelema + ": " + type);
- TraceCompile(OpCodes.Ldobj + ": " + type);
- }
- else
- {
- Emit(OpCodes.Ldelem_Ref);
- }
- break;
- }
- }
- internal void LoadValue(Type type)
- {
- il.Emit(OpCodes.Ldtoken, type);
- TraceCompile(OpCodes.Ldtoken + ": " + type);
- EmitCall(MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"));
- }
- internal void ConvertToInt32(ProtoTypeCode typeCode, bool uint32Overflow)
- {
- switch (typeCode)
- {
- case ProtoTypeCode.Byte:
- case ProtoTypeCode.SByte:
- case ProtoTypeCode.Int16:
- case ProtoTypeCode.UInt16:
- Emit(OpCodes.Conv_I4);
- break;
- case ProtoTypeCode.Int32:
- break;
- case ProtoTypeCode.Int64:
- Emit(OpCodes.Conv_Ovf_I4);
- break;
- case ProtoTypeCode.UInt32:
- Emit(uint32Overflow ? OpCodes.Conv_Ovf_I4_Un : OpCodes.Conv_Ovf_I4);
- break;
- case ProtoTypeCode.UInt64:
- Emit(OpCodes.Conv_Ovf_I4_Un);
- break;
- default:
- throw new InvalidOperationException("ConvertToInt32 not implemented for: " + typeCode.ToString());
- }
- }
- internal void ConvertFromInt32(ProtoTypeCode typeCode, bool uint32Overflow)
- {
- switch (typeCode)
- {
- case ProtoTypeCode.SByte: Emit(OpCodes.Conv_Ovf_I1); break;
- case ProtoTypeCode.Byte: Emit(OpCodes.Conv_Ovf_U1); break;
- case ProtoTypeCode.Int16: Emit(OpCodes.Conv_Ovf_I2); break;
- case ProtoTypeCode.UInt16: Emit(OpCodes.Conv_Ovf_U2); break;
- case ProtoTypeCode.Int32: break;
- case ProtoTypeCode.UInt32: Emit(uint32Overflow ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4); break;
- case ProtoTypeCode.Int64: Emit(OpCodes.Conv_I8); break;
- case ProtoTypeCode.UInt64: Emit(OpCodes.Conv_U8); break;
- default: throw new InvalidOperationException();
- }
- }
- internal void LoadValue(decimal value)
- {
- if (value == 0M)
- {
- LoadValue(typeof(decimal).GetField("Zero"));
- }
- else
- {
- int[] bits = decimal.GetBits(value);
- LoadValue(bits[0]); // lo
- LoadValue(bits[1]); // mid
- LoadValue(bits[2]); // hi
- LoadValue((int)(((uint)bits[3]) >> 31)); // isNegative (bool, but int for CLI purposes)
- LoadValue((bits[3] >> 16) & 0xFF); // scale (byte, but int for CLI purposes)
- EmitCtor(MapType(typeof(decimal)), new Type[] { MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(bool)), MapType(typeof(byte)) });
- }
- }
- internal void LoadValue(Guid value)
- {
- if (value == Guid.Empty)
- {
- LoadValue(typeof(Guid).GetField("Empty"));
- }
- else
- { // note we're adding lots of shorts/bytes here - but at the IL level they are I4, not I1/I2 (which barely exist)
- byte[] bytes = value.ToByteArray();
- int i = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
- LoadValue(i);
- short s = (short)((bytes[4]) | (bytes[5] << 8));
- LoadValue(s);
- s = (short)((bytes[6]) | (bytes[7] << 8));
- LoadValue(s);
- for (i = 8; i <= 15; i++)
- {
- LoadValue(bytes[i]);
- }
- EmitCtor(MapType(typeof(Guid)), new Type[] { MapType(typeof(int)), MapType(typeof(short)), MapType(typeof(short)),
- MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)) });
- }
- }
- //internal void LoadValue(bool value)
- //{
- // Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
- //}
- internal void LoadSerializationContext()
- {
- LoadReaderWriter();
- LoadValue((isWriter ? typeof(ProtoWriter) : typeof(ProtoReader)).GetProperty("Context"));
- }
- private readonly TypeModel model;
- internal Type MapType(Type type)
- {
- return model.MapType(type);
- }
- private readonly ILVersion metadataVersion;
- public ILVersion MetadataVersion { get { return metadataVersion; } }
- public enum ILVersion
- {
- Net1, Net2
- }
- internal bool AllowInternal(PropertyInfo property)
- {
- return NonPublic ? true : InternalsVisible(Helpers.GetAssembly(property.DeclaringType));
- }
- }
- }
- #endif
|