Beispiel #1
0
        /// <summary>
        /// Pops a value off the stack and stores it into the given local.
        ///
        /// To create a local, use DeclareLocal().
        /// </summary>
        public Emit <DelegateType> StoreLocal(Local local)
        {
            if (local == null)
            {
                throw new ArgumentNullException("local");
            }

            if (((IOwned)local).Owner != this)
            {
                if (((IOwned)local).Owner is DisassembledOperations <DelegateType> )
                {
                    return(StoreLocal(local.Name));
                }

                FailOwnership(local);
            }

            UnusedLocals.Remove(local);

            switch (local.Index)
            {
            case 0: UpdateState(OpCodes.Stloc_0, Wrap(StackTransition.Pop(local.StackType), "StoreLocal")); return(this);

            case 1: UpdateState(OpCodes.Stloc_1, Wrap(StackTransition.Pop(local.StackType), "StoreLocal")); return(this);

            case 2: UpdateState(OpCodes.Stloc_2, Wrap(StackTransition.Pop(local.StackType), "StoreLocal")); return(this);

            case 3: UpdateState(OpCodes.Stloc_3, Wrap(StackTransition.Pop(local.StackType), "StoreLocal")); return(this);
            }

            if (local.Index >= byte.MinValue && local.Index <= byte.MaxValue)
            {
                byte asByte;
                unchecked
                {
                    asByte = (byte)local.Index;
                }

                UpdateState(OpCodes.Stloc_S, asByte, Wrap(StackTransition.Pop(local.StackType), "StoreLocal"));
                return(this);
            }

            UpdateState(OpCodes.Stloc, local, Wrap(StackTransition.Pop(local.StackType), "StoreLocal"));

            return(this);
        }
Beispiel #2
0
        /// <summary>
        /// Pushes a pointer to the given local onto the stack.
        ///
        /// To create a local, use DeclareLocal.
        /// </summary>
        public Emit <DelegateType> LoadLocalAddress(Local local)
        {
            if (local == null)
            {
                throw new ArgumentNullException("local");
            }

            if (((IOwned)local).Owner != this)
            {
                if (((IOwned)local).Owner is DisassembledOperations <DelegateType> )
                {
                    return(LoadLocalAddress(local.Name));
                }

                FailOwnership(local);
            }

            UnusedLocals.Remove(local);

            var type = local.StackType.Type;

            var ptrType = type.MakePointerType();

            if (local.Index >= byte.MinValue && local.Index <= byte.MaxValue)
            {
                byte asByte;
                unchecked
                {
                    asByte = (byte)local.Index;
                }

                UpdateState(OpCodes.Ldloca_S, asByte, Wrap(StackTransition.Push(ptrType), "LoadLocalAddress"));
                return(this);
            }

            short asShort;

            unchecked
            {
                asShort = (short)local.Index;
            }

            UpdateState(OpCodes.Ldloca, asShort, Wrap(StackTransition.Push(ptrType), "LoadLocalAddress"));

            return(this);
        }
Beispiel #3
0
        /// <summary>
        /// Declare a new local of the given type in the current method.
        ///
        /// Name is optional, and only provided for debugging purposes.  It has no
        /// effect on emitted IL.
        ///
        /// Be aware that each local takes some space on the stack, inefficient use of locals
        /// could lead to StackOverflowExceptions at runtime.
        /// </summary>
        public Local DeclareLocal(Type type, string name = null)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            name = name ?? AutoNamer.Next(this, "_local", Locals.Names, Labels.Names);

            if (CurrentLocals.ContainsKey(name))
            {
                throw new InvalidOperationException("Local with name '" + name + "' already exists");
            }

            var existingLocal = FreedLocals.FirstOrDefault(l => l.LocalType == type);

            DeclareLocallDelegate local;
            ushort localIndex;

            if (existingLocal == null)
            {
                local = IL.DeclareLocal(type);

                localIndex = NextLocalIndex;
                NextLocalIndex++;
            }
            else
            {
                local      = existingLocal.LocalDel;
                localIndex = existingLocal.Index;

                FreedLocals.Remove(existingLocal);
            }

            var ret = new Local(this, localIndex, type, local, name, LocalReleased, IL.Index);

            UnusedLocals.Add(ret);

            AllLocals.Add(ret);

            CurrentLocals[ret.Name] = ret;

            return(ret);
        }
Beispiel #4
0
        /// <summary>
        /// Declare a new local of the given type in the current method.
        ///
        /// Name is optional, and only provided for debugging purposes.  It has no
        /// effect on emitted IL.
        ///
        /// Be aware that each local takes some space on the stack, inefficient use of locals
        /// could lead to StackOverflowExceptions at runtime.
        ///
        /// Jil will reuse local index on the stack if the corresponding Local instance has been disposed.
        /// By default Jil will set reused locals to their default value, you can change this behavior
        /// by passing initializeReused = false.
        /// </summary>
        public Local DeclareLocal(Type type, string name = null, bool initializeReused = true)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            name = name ?? AutoNamer.Next(this, "_local", Locals.Names, Labels.Names);

            if (CurrentLocals.ContainsKey(name))
            {
                throw new InvalidOperationException("Local with name '" + name + "' already exists");
            }

            var existingLocal = FreedLocals.FirstOrDefault(l => l.LocalType == type);

            DeclareLocallDelegate local;
            ushort localIndex;

            if (existingLocal == null)
            {
                local = IL.DeclareLocal(type);

                localIndex = NextLocalIndex;
                NextLocalIndex++;
            }
            else
            {
                local      = existingLocal.LocalDel;
                localIndex = existingLocal.Index;

                FreedLocals.Remove(existingLocal);
            }

            var ret = new Local(this, localIndex, type, local, name, LocalReleased, IL.Index);

            UnusedLocals.Add(ret);

            AllLocals.Add(ret);

            CurrentLocals[ret.Name] = ret;

            // we need to initialize this local to it's default value, because otherwise
            //   it might be read from to get some non-sense
            if (existingLocal != null && initializeReused)
            {
                if (!TypeHelpers.IsValueType(type))
                {
                    // reference types all get nulled
                    LoadNull();
                    StoreLocal(ret);
                }
                else
                {
                    // handle known primitives better
                    //   so as not to confuse the JIT
                    var defaultLoaded = false;

                    if (type == typeof(bool))
                    {
                        LoadConstant(default(bool));
                        defaultLoaded = true;
                    }

                    if (type == typeof(byte))
                    {
                        LoadConstant(default(byte));
                        defaultLoaded = true;
                    }

                    if (type == typeof(sbyte))
                    {
                        LoadConstant(default(sbyte));
                        defaultLoaded = true;
                    }

                    if (type == typeof(short))
                    {
                        LoadConstant(default(short));
                        defaultLoaded = true;
                    }

                    if (type == typeof(ushort))
                    {
                        LoadConstant(default(ushort));
                        defaultLoaded = true;
                    }

                    if (type == typeof(int))
                    {
                        LoadConstant(default(int));
                        defaultLoaded = true;
                    }

                    if (type == typeof(uint))
                    {
                        LoadConstant(default(uint));
                        defaultLoaded = true;
                    }

                    if (type == typeof(long))
                    {
                        LoadConstant(default(long));
                        defaultLoaded = true;
                    }

                    if (type == typeof(ulong))
                    {
                        LoadConstant(default(ulong));
                        defaultLoaded = true;
                    }

                    if (type == typeof(float))
                    {
                        LoadConstant(default(float));
                        defaultLoaded = true;
                    }

                    if (type == typeof(double))
                    {
                        LoadConstant(default(double));
                        defaultLoaded = true;
                    }

                    if (defaultLoaded)
                    {
                        StoreLocal(ret);
                    }
                    else
                    {
                        // if it's use defined though, we've got little choice
                        LoadLocalAddress(ret);
                        InitializeObject(type);
                    }
                }
            }

            return(ret);
        }