Пример #1
0
        public void MarkLabel(Sigil.Label label)
        {
            InstructionSizes.Add(() => InstructionSize.MarkLabel());

            LengthCache.Clear();

            Buffer.Add(
                (il, logOnly, log) =>
            {
                if (!logOnly)
                {
                    var l = label.LabelDel(il);
                    il.MarkLabel(l);
                }

                log.AppendLine();
                log.AppendLine(label + ":");
            }
                );

            TraversableBuffer.Add(new BufferedILInstruction {
                MarksLabel = label
            });

            Operations.Add(null);
        }
        private static void BuildGetParameter(TypeBuilder typeBuilder, Type[] parameterTypes, FieldBuilder[] fields)
        {
            var get    = Emit.BuildInstanceMethod(typeof(object), new[] { typeof(int), typeof(string), typeof(Type) }, typeBuilder, "GetParameter", MethodAttributes.Public | MethodAttributes.Virtual);
            var labels = new Sigil.Label[parameterTypes.Length];

            for (var i = 0; i < labels.Length; i++)
            {
                labels[i] = get.DefineLabel();
            }

            get.LoadArgument(1);
            get.Switch(labels);
            get.LoadArgument(2);
            get.NewObject <ArgumentOutOfRangeException, string>();
            get.Throw();

            for (var i = 0; i < parameterTypes.Length; i++)
            {
                get.MarkLabel(labels[i]);
                get.LoadArgument(0);
                get.LoadField(fields[i]);

                var parameterType = parameterTypes[i];
                if (!parameterType.IsClass)
                {
                    get.Box(parameterType);
                }
                get.Return();
            }

            var getter = get.CreateMethod();

            typeBuilder.DefineMethodOverride(getter, typeof(IServiceRemotingRequestMessageBody).GetMethod("GetParameter"));
        }
Пример #3
0
        void EmitSimpleComplete(Schema schema, ValueWriter writer)
        {
            var effective = schema.NetType;

            Sigil.Label theEnd = null;

            if (Nullable.GetUnderlyingType(effective) != null)
            {
                Emit.Duplicate();                 // prepare argument 0 for GetValueOrDefault call

                Emit.Call(effective.GetProperty("HasValue").GetGetMethod());

                var hasValueTrue = Emit.DefineLabel("HasValue_true");
                Emit.BranchIfTrue(hasValueTrue);
                Emit.Pop();                 // discard argument 0
                // byte* destination
                Emit.LoadArgument(1);
                // available
                if (Destination == DestinationType.Stream)
                {
                    Emit.LoadLocal(LocalAvailable);
                }
                else
                {
                    Emit.LoadArgument(2);
                }
                // .WriteNull
                Emit.Call(WriteNull);

                if (Destination == DestinationType.Stream)
                {
                    Flush();
                }

                theEnd = Emit.DefineLabel("theEnd");
                Emit.Branch(theEnd);

                Emit.MarkLabel(hasValueTrue);

                Emit.Call(effective.GetMethod("GetValueOrDefault", Type.EmptyTypes));

                effective = Nullable.GetUnderlyingType(effective);
            }

            CallWriter(writer, effective, false);

            if (Destination == DestinationType.Stream)
            {
                Flush();
            }

            if (theEnd != null)
            {
                Emit.MarkLabel(theEnd);
            }

            Emit.Return();
        }
Пример #4
0
        public void LeaveDataOnStackBetweenBranchesNonGeneric()
        {
            var il = Emit.NewDynamicMethod(typeof(int), Type.EmptyTypes, "LeaveDataOnStackBetweenBranches");

            Sigil.Label b0 = il.DefineLabel("b0"), b1 = il.DefineLabel("b1"), b2 = il.DefineLabel("b2");
            il.LoadConstant("abc");
            il.Branch(b0);    // jump to b0 with "abc"

            il.MarkLabel(b1); // incoming: 3
            il.LoadConstant(4);
            il.Call(typeof(Math).GetMethod("Max", new[] { typeof(int), typeof(int) }));
            il.Branch(b2);    // jump to b2 with 4

            il.MarkLabel(b0); // incoming: "abc"
            il.CallVirtual(typeof(string).GetProperty("Length").GetGetMethod());
            il.Branch(b1);    // jump to b1 with 3

            il.MarkLabel(b2); // incoming: 4
            il.Return();
            int i = il.CreateDelegate <Func <int> >()();

            Assert.AreEqual(4, i);
        }
Пример #5
0
        public void Emit(OpCode op, Sigil.Label label, out UpdateOpCodeDelegate update)
        {
            var localOp = op;

            update =
                newOpcode =>
            {
                LengthCache.Clear();

                localOp = newOpcode;
            };

            InstructionSizes.Add(() => InstructionSize.Get(localOp));

            LengthCache.Clear();

            Buffer.Add(
                (il, logOnly, log) =>
            {
                if (!logOnly)
                {
                    var l = label.LabelDel(il);
                    il.Emit(localOp, l);
                }

                log.AppendLine(localOp + " " + label);
            }
                );

            TraversableBuffer.Add(new BufferedILInstruction {
                IsInstruction = op
            });

            Operations.Add(new Operation <DelegateType> {
                OpCode = op, Parameters = new object[] { label }
            });
        }
Пример #6
0
        void EmitObject(Schema schema, bool pushResult = false)
        {
            // merge consecutive constant strings
            var spans = new List <KeyValuePair <string, Schema> >();

            for (int i = 0; i < schema.Members.Count; i++)
            {
                Append(spans,
                       (i == 0 ? "{\"" : ",\"") +
                       Escape(schema.Members[i].Key) +
                       "\":");

                string constant = null;
                var    member   = schema.Members[i].Value;
                var    prop     = member.PropertyInfo;
                if (prop != null)
                {
                    constant = ConstantMethods.TryGetJson(prop.GetMethod, schema.NetType);
                }

                if (constant != null)
                {
                    Append(spans, constant);
                }
                else
                {
                    spans.Add(new KeyValuePair <string, Schema>(null, member));
                }

                if (i == schema.Members.Count - 1)
                {
                    Append(spans, "}");
                }
            }

            var underlying     = Nullable.GetUnderlyingType(schema.NetType);
            var systemNullable = underlying != null;

            Sigil.Label ifNull     = null;
            bool        anyMembers = spans.Any(span => span.Value != null);

            if (schema.Nullable)
            {
                var ifNotNull = DefineLabel("IfNotNull");
                ifNull = DefineLabel("ifNull");

                if (anyMembers)
                {
                    Emit.Duplicate();                     // preserve the value
                }
                if (systemNullable)
                {
                    Emit.Call(schema.NetType.GetProperty("HasValue").GetMethod);
                }
                Emit.BranchIfTrue(ifNotNull);
                if (anyMembers)
                {
                    Emit.Pop();                             // discard value
                }
                if (pushResult)
                {
                    Emit.Pop();                             // discard avail
                }
                WriteConstant("null", push: pushResult);
                Emit.Branch(ifNull);

                Emit.MarkLabel(ifNotNull);
                if (systemNullable)
                {
                    Emit.Call(schema.NetType.GetMethod("GetValueOrDefault", Type.EmptyTypes));
                }
            }

            if (schema.Members.Count == 0)
            {
                if (pushResult)
                {
                    Depth++;
                }
                WriteConstant("{}");
                if (pushResult)
                {
                    Depth--;
                }
            }
            else
            {
                int lastNonConstant = -1;
                int minLength       = 0;

                // find last non constant and min length
                for (int i = 0; i < spans.Count; i++)
                {
                    var span = spans[i];
                    if (span.Key != null)
                    {
                        minLength += Encoding.UTF8.GetByteCount(span.Key);
                    }
                    else
                    {
                        lastNonConstant = i;
                        minLength      += span.Value.CalculateMinimumLength(considerNullMembers: true);
                    }
                }

                for (int i = 0; i < spans.Count; i++)
                {
                    var span = spans[i];

                    // assert we've got enough
                    var enoughAvailable = DefineLabel("enoughAvailable");
                    Emit.LoadLocal(LocalAvailable);
                    Emit.LoadConstant(minLength);
                    Emit.BranchIfGreaterOrEqual(enoughAvailable);
                    {
                        int extra = pushResult ? 2 : 1;
                        if (i > lastNonConstant)
                        {
                            extra--;
                        }
                        Depth += extra;
                        ReturnFailed();
                        Depth -= extra;
                    }

                    Emit.MarkLabel(enoughAvailable);

                    if (span.Key != null)
                    {
                        int written = WriteConstant(span.Key, assertAvailable: false);
                        minLength -= written;
                        continue;
                    }

                    var member = span.Value;
                    minLength -= member.CalculateMinimumLength(considerNullSelf: true);

                    var lastMember = i == lastNonConstant;
                    if (!lastMember)
                    {
                        // sanity check minLength
                        if (minLength < 6)                         // ,"a":0
                        {
                            // FIXME use/create appropriate Exception type
                            throw new InvalidOperationException("Minimum length calculation failed");
                        }

                        // preserve value except last time through the loop
                        Emit.Duplicate();
                    }
                    int loopDepth = (lastMember ? 1 : 2) - (pushResult ? 0 : 1);
                    Depth += loopDepth;

                    // get the member value
                    if (member.FieldInfo != null)
                    {
                        Emit.LoadField(member.FieldInfo);
                    }
                    else
                    {
                        if (schema.NetType.IsValueType)
                        {
                            PushAddress(systemNullable ? underlying : schema.NetType);
                        }
                        Emit.Call(member.PropertyInfo.GetMethod);
                    }

                    // write the member value
                    EmitInline(member);

                    Depth -= loopDepth;

                    // if we ran out of room inner writer will have bailed completely rather than push negative (currently)

                    // we probably won't care about result until we create more fine grained estimates when out of room
                }
            }

            if (pushResult)
            {
                // push bytes written
                Emit.LoadLocal(LocalAvailable);
                Emit.Subtract();
            }

            if (schema.Nullable)
            {
                Emit.MarkLabel(ifNull);
            }
        }
Пример #7
0
        // never pushes result
        void EmitSimpleInline(Schema schema, ValueWriter writer)
        {
            var effective = schema.NetType;

            Sigil.Label ifNull = null;

            var underlying = Nullable.GetUnderlyingType(effective);

            if (underlying != null)
            {
                ifNull = DefineLabel("ifNull");
                var hasValueTrue = DefineLabel("hasValueTrue");

                Emit.Duplicate();                 // preserve value

                Emit.Call(effective.GetProperty("HasValue").GetGetMethod());

                Emit.BranchIfTrue(hasValueTrue);
                Emit.Pop();                 // discard value
                WriteConstant("null", push: false);
                Emit.Branch(ifNull);

                Emit.MarkLabel(hasValueTrue);

                Emit.Call(effective.GetMethod("GetValueOrDefault", Type.EmptyTypes));

                effective = underlying;
            }

            if (writer.MaxLength.HasValue && Destination == DestinationType.Stream)
            {
                // flush if available < writer.MaxLength
                var afterFlush = DefineLabel("afterFlush");
                Emit.LoadLocal(LocalAvailable);
                Emit.LoadConstant(writer.MaxLength.Value);
                Emit.BranchIfGreaterOrEqual(afterFlush);
                Flush(writtenTop: false, resetAvailable: true);
                Emit.MarkLabel(afterFlush);
            }

            CallWriter(writer, effective, true);

            // simple writers must flush to stream directly
            if (Destination == DestinationType.Pointer)
            {
                Emit.Duplicate();                 // preserve the written count

                // check if the write succeeded
                var success = DefineLabel("success");
                Emit.LoadConstant(0);
                Emit.BranchIfGreater(success);
                {
                    Depth++;
                    ReturnFailed();
                    Depth--;
                }

                Emit.MarkLabel(success);
            }

            if (Destination == DestinationType.Pointer || writer.MaxLength.HasValue)
            {
                Emit.Duplicate();                 // preserve written count

                // advance LocalDestination
                Emit.Convert <IntPtr>();
                Emit.LoadLocal(LocalDestination);
                Emit.Add();
                Emit.StoreLocal(LocalDestination);


                // Emit.Duplicate(); // preserve written count

                // decrement LocalAvailable
                Emit.LoadConstant(-1);
                Emit.Multiply();
                Emit.LoadLocal(LocalAvailable);
                Emit.Add();
                Emit.StoreLocal(LocalAvailable);
            }


            if (underlying != null)
            {
                Emit.MarkLabel(ifNull);
            }
        }