public LocalCtxFrame CreateNext()
            {
                var nextFrame = new LocalCtxFrame(this);

                this.Next = nextFrame;
                return(nextFrame);
            }
 public LocalCtxFrame(LocalCtxFrame prev)
 {
     this.Prev   = prev;
     this.Next   = null;
     this.Depth  = prev.Depth + 1;
     this.Locals = new HashSet <ObjPtr>();
 }
        private ObjPtr SelectObject(LocalCtxFrame frame, bool useStatics = true)
        {
            List <ObjPtr> ptrs;

            if (useStatics)
            {
                ptrs = frame.Locals.Concat(_ctx.Statics).Distinct().ToList();
            }
            else
            {
                ptrs = frame.Locals.ToList();
            }

            if (ptrs.Count == 0)
            {
                return(ObjPtr.Zero);
            }
            else
            {
                return(this.SelectDeepObject(ptrs[_rnd.Next(0, ptrs.Count)]));
            }

            //if (_rnd.Next(100) > 50 && useStatics)
            //{
            //    if (_ctx.Statics.Count > 0)
            //        return this.SelectDeepObject(_ctx.Statics.Skip(_rnd.Next(0, _ctx.Statics.Count)).First());
            //    else
            //        return ObjPtr.Zero;
            //}
            //else
            //{
            //    if (frame.Locals.Count > 0)
            //        return this.SelectDeepObject(frame.Locals.Skip(_rnd.Next(0, frame.Locals.Count)).First());
            //    else
            //        return ObjPtr.Zero;
            //}
        }
        private ObjPtr PerformAction(MutatorActionKind actionKind, ref LocalCtxFrame frame)
        {
            ObjPtr ptr;

            switch (actionKind)
            {
            case MutatorActionKind.None:
                ptr = ObjPtr.Zero;
                break;

            case MutatorActionKind.Call:
                frame = frame.CreateNext();
                ptr   = ObjPtr.Zero;
                break;

            case MutatorActionKind.Return:
                frame = frame.ResumePrev();
                ptr   = ObjPtr.Zero;
                break;

            case MutatorActionKind.Newobj:
                frame.Locals.Add(ptr = _ctx.Runtime.AllocRandomObj(_rnd));
                break;

            case MutatorActionKind.PutStatic:
            {
                lock (_ctx.Statics)
                {
                    if (frame.Locals.Count > 0)
                    {
                        _ctx.Statics.Add(ptr = frame.Locals.Skip(_rnd.Next(0, frame.Locals.Count)).First());
                    }
                    else
                    {
                        ptr = ObjPtr.Zero;
                    }
                }
            }
            break;

            case MutatorActionKind.ChangeStatic:
            {
                lock (_ctx.Statics)
                {
                    if (_ctx.Statics.Count > 0 && frame.Locals.Count > 0)
                    {
                        _ctx.Statics.Remove(_ctx.Statics.Skip(_rnd.Next(0, _ctx.Statics.Count)).First());
                        _ctx.Statics.Add(ptr = frame.Locals.Skip(_rnd.Next(0, frame.Locals.Count)).First());
                    }
                    else
                    {
                        ptr = ObjPtr.Zero;
                    }
                }
            }
            break;

            case MutatorActionKind.EraseStatic:
            {
                lock (_ctx.Statics)
                {
                    if (_ctx.Statics.Count > 0)
                    {
                        _ctx.Statics.Remove(ptr = _ctx.Statics.Skip(_rnd.Next(0, _ctx.Statics.Count)).First());
                    }
                    else
                    {
                        ptr = ObjPtr.Zero;
                    }
                }
            }
            break;

            case MutatorActionKind.PutRef:
            {
                lock (_ctx.Statics)
                {
                    ptr = this.SelectObject(frame);

                    if (ptr.value != IntPtr.Zero)
                    {
                        _refBuffer.Value = _ctx.Runtime.ObjToBlock(this.SelectObject(frame, useStatics: false)).value;

                        var refs  = _ctx.Runtime.GetRefs(ptr);
                        var field = refs.FirstOrDefault(f => { f.GetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr); return(_refBuffer.Value == IntPtr.Zero); });

                        if (field != null)
                        {
                            field.SetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr);
                        }
                        else
                        {
                            refs[_rnd.Next(0, refs.Length)].SetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr);
                        }
                    }
                }
            }
            break;

            case MutatorActionKind.ChangeRef:
            {
                lock (_ctx.Statics)
                {
                    ptr = this.SelectObject(frame);

                    if (ptr.value != IntPtr.Zero)
                    {
                        _refBuffer.Value = _ctx.Runtime.ObjToBlock(this.SelectObject(frame, useStatics: false)).value;

                        var refs = _ctx.Runtime.GetRefs(ptr);
                        refs[_rnd.Next(0, refs.Length)].SetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr);
                    }
                }
            }
            break;

            case MutatorActionKind.EraseRef:
            {
                lock (_ctx.Statics)
                {
                    ptr = this.SelectObject(frame);

                    if (ptr.value != IntPtr.Zero)
                    {
                        var refs  = _ctx.Runtime.GetRefs(ptr);
                        var field = refs.FirstOrDefault(f => { f.GetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr); return(_refBuffer.Value != IntPtr.Zero); });

                        _refBuffer.Value = IntPtr.Zero;
                        if (field != null)
                        {
                            field.SetValue(_ctx.Runtime.ObjToBlock(ptr), _refBuffer.buffPtr);
                        }
                    }
                }
            }
            break;

            default:
                throw new NotImplementedException("Unknown action " + actionKind);
            }

            return(ptr);
        }