| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 | using System;using System.Collections.Generic;using System.Linq;using System.Text;using ILRuntime.CLR.Method;using ILRuntime.CLR.TypeSystem;using ILRuntime.Other;using ILRuntime.Runtime.Intepreter;namespace ILRuntime.Runtime.Stack{    unsafe class RuntimeStack : IDisposable    {        ILIntepreter intepreter;        StackObject* pointer;        StackObject* endOfMemory;        StackObject* valueTypePtr;        StackObjectAllocator allocator;        IntPtr nativePointer;#if DEBUG && !DISABLE_ILRUNTIME_DEBUG        IList<object> managedStack = new List<object>(32);#else        IList<object> managedStack = new UncheckedList<object>(32);#endif        UncheckedStack<StackFrame> frames = new UncheckedStack<StackFrame>();        public const int MAXIMAL_STACK_OBJECTS = 1024 * 16;        public UncheckedStack<StackFrame> Frames { get { return frames; } }        public RuntimeStack(ILIntepreter intepreter)        {            this.intepreter = intepreter;            nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);            pointer = (StackObject*)nativePointer.ToPointer();            endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);            valueTypePtr = endOfMemory - 1;        }        ~RuntimeStack()        {            Dispose();        }        public StackObject* StackBase        {            get            {                return pointer;            }        }        public StackObject* ValueTypeStackPointer        {            get            {                return valueTypePtr;            }            internal set            {                if (value > ValueTypeStackBase)                    throw new StackOverflowException();                valueTypePtr = value;            }        }        public StackObject* ValueTypeStackBase        {            get            {                return endOfMemory - 1;            }        }        public IList<object> ManagedStack { get { return managedStack; } }        public void ResetValueTypePointer()        {            valueTypePtr = endOfMemory - 1;        }        public void InitializeFrame(ILMethod method, StackObject* esp, out StackFrame res)        {#if DEBUG            if (esp < pointer || esp >= endOfMemory)                throw new StackOverflowException();            if (frames.Count > 0 && frames.Peek().BasePointer > esp)                throw new StackOverflowException();#endif            res = new StackFrame();            res.LocalVarPointer = esp;            res.Method = method;#if DEBUG && !DISABLE_ILRUNTIME_DEBUG            res.Address = new IntegerReference();            for (int i = 0; i < method.LocalVariableCount; i++)            {                var p = Add(esp, i);                p->ObjectType = ObjectTypes.Null;            }#endif            res.BasePointer = method.LocalVariableCount > 0 ? Add(esp, method.LocalVariableCount) : esp;            res.ManagedStackBase = managedStack.Count;            res.ValueTypeBasePointer = valueTypePtr;            //frames.Push(res);        }        public void PushFrame(ref StackFrame frame)        {            frames.Push(ref frame);        }        public StackObject* PopFrame(ref StackFrame frame, StackObject* esp)        {#if DEBUG            if (frames.Count > 0 && frames.Peek().BasePointer == frame.BasePointer)#endif                frames.Pop();#if DEBUG            else                throw new NotSupportedException();#endif            StackObject* returnVal = esp - 1;            var method = frame.Method;            StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);            int mStackBase = frame.ManagedStackBase;            if (method.HasThis)                ret--;            if (allocator != null)                allocator.FreeBefore(frame.ValueTypeBasePointer);            for (StackObject* ptr = ret; ptr < frame.LocalVarPointer; ptr++)            {                if (ptr->ObjectType == ObjectTypes.ValueTypeObjectReference)                {                    var addr = ILIntepreter.ResolveReference(ptr);                    int start = int.MaxValue;                    int end = int.MaxValue;                    var tmp = addr;                    CountValueTypeManaged(ptr, ref start, ref end, &tmp);                    if (addr > frame.ValueTypeBasePointer)                    {                        frame.ValueTypeBasePointer = addr;                    }                    if (start < mStackBase)                        mStackBase = start;                }            }            if(method.ReturnType != intepreter.AppDomain.VoidType)            {                *ret = *returnVal;                if(ret->ObjectType == ObjectTypes.Object)                {                    ret->Value = mStackBase;                    managedStack[mStackBase] = managedStack[returnVal->Value];                    mStackBase++;                }                else if(ret->ObjectType == ObjectTypes.ValueTypeObjectReference)                {                    StackObject* oriAddr = frame.ValueTypeBasePointer;                    RelocateValueType(ret, ref frame.ValueTypeBasePointer, ref mStackBase);                    *(long*)&ret->Value = (long)oriAddr;                }                ret++;            }#if DEBUG && !DISABLE_ILRUNTIME_DEBUG            ((List<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);#else            ((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);#endif            valueTypePtr = frame.ValueTypeBasePointer;            return ret;        }        public void RelocateValueTypeAndFreeAfterDst(StackObject* src, StackObject* dst)        {            var objRef2 = dst;            dst = ILIntepreter.ResolveReference(dst);            int start = int.MaxValue;            int end = int.MaxValue;            CountValueTypeManaged(objRef2, ref start, ref end, &objRef2);            RelocateValueType(src, ref dst, ref start);            ValueTypeStackPointer = dst;            if (start <= end)                RemoveManagedStackRange(start, end);        }        void RelocateValueType(StackObject* src, ref StackObject* dst, ref int mStackBase)        {            StackObject* descriptor = ILIntepreter.ResolveReference(src);            if (descriptor > dst)                throw new StackOverflowException();            *dst = *descriptor;            int cnt = descriptor->ValueLow;            StackObject* endAddr = ILIntepreter.Minus(dst, cnt + 1);            for(int i = 0; i < cnt; i++)            {                StackObject* addr = ILIntepreter.Minus(descriptor, i + 1);                StackObject* tarVal = ILIntepreter.Minus(dst, i + 1);                *tarVal = *addr;                switch (addr->ObjectType)                {                    case ObjectTypes.Object:                    case ObjectTypes.ArrayReference:                    case ObjectTypes.FieldReference:                        if (tarVal->Value >= mStackBase)                        {                            int oldIdx = addr->Value;                            tarVal->Value = mStackBase;                            managedStack[mStackBase] = managedStack[oldIdx];                            mStackBase++;                        }                        break;                    case ObjectTypes.ValueTypeObjectReference:                        var newAddr = endAddr;                        RelocateValueType(addr, ref endAddr, ref mStackBase);                        *(long*)&tarVal->Value = (long)newAddr;                        break;                }            }            dst = endAddr;        }        int CountValueTypeManaged(IType type)        {            int res = 0;            if (type is ILType)            {                ILType t = (ILType)type;                for (int i = 0; i < t.FieldTypes.Length; i++)                {                    var ft = t.FieldTypes[i];                    if (!ft.IsPrimitive && !ft.IsEnum)                    {                        if (ft.IsValueType)                        {                            if (!(ft is ILType) && ((CLRType)ft).ValueTypeBinder == null)                            {                                res++;                            }                        }                        else                        {                            res++;                        }                    }                }                if (type.BaseType != null && type.BaseType is ILType)                    res += CountValueTypeManaged((ILType)type.BaseType);            }            else            {                CLRType t = (CLRType)type;                var cnt = t.TotalFieldCount;                for (int i = 0; i < cnt; i++)                {                    var it = t.OrderedFieldTypes[i] as CLRType;                    if (!it.IsPrimitive && it.IsEnum)                    {                        if (it.IsValueType)                        {                            if (it.ValueTypeBinder == null)                            {                                res++;                            }                        }                        else                        {                            res++;                        }                    }                }            }            return res;        }        void AllocBlock(int size, out StackObject* dst, out int managedIdx)        {            dst = valueTypePtr;            valueTypePtr = ILIntepreter.Minus(valueTypePtr, size);            if (valueTypePtr <= StackBase)                throw new StackOverflowException();            managedIdx = managedStack.Count;                    }        public void ClearAllocator()        {            if (allocator != null)                allocator.Clear();        }        public void AllocValueTypeAndCopy(StackObject* ptr, StackObject* src)        {            var dst = ILIntepreter.ResolveReference(src);            var type = intepreter.AppDomain.GetTypeByIndex(dst->Value);            int size, managedCount;            type.GetValueTypeSize(out size, out managedCount);            if (allocator == null)                allocator = new StackObjectAllocator(AllocBlock);            StackObjectAllocation alloc;            if(allocator.AllocExisting(ptr, size, managedCount, out alloc))            {                if (dst != alloc.Address)                {                    dst = alloc.Address;                    ptr->ObjectType = ObjectTypes.ValueTypeObjectReference;                    *(long*)&ptr->Value = (long)dst;                    int managedIdx = alloc.ManagedIndex;                    InitializeValueTypeObject(type, dst, true, ref managedIdx, false);                    intepreter.CopyStackValueType(src, ptr, managedStack);                    FreeValueTypeObject(src);                }                else                {                    ptr->ObjectType = ObjectTypes.ValueTypeObjectReference;                    *(long*)&ptr->Value = (long)dst;                }            }            else            {                int start = int.MaxValue;                int end = int.MinValue;                StackObject* endAddr;                CountValueTypeManaged(src, ref start, ref end, &endAddr);                if (endAddr == valueTypePtr)                    valueTypePtr = dst;                allocator.RegisterAllocation(ptr, dst, size, start, managedCount);                ptr->ObjectType = ObjectTypes.ValueTypeObjectReference;                *(long*)&ptr->Value = (long)dst;            }        }        public void AllocValueType(StackObject* ptr, IType type, bool register = false, bool noInitialize = false)        {            if (type.IsValueType)            {                StackObject* dst;                int size, managedCount;                type.GetValueTypeSize(out size, out managedCount);                int managedIdx = -1;                if (register)                {                    if (allocator == null)                        allocator = new StackObjectAllocator(AllocBlock);                    var allocation = allocator.Alloc(ptr, size, managedCount);                    dst = allocation.Address;                    managedIdx = allocation.ManagedIndex;                }                else                {                    dst = valueTypePtr;                    managedIdx = managedStack.Count;                    valueTypePtr = ILIntepreter.Minus(valueTypePtr, size);                    if (valueTypePtr <= StackBase)                        throw new StackOverflowException();                }                ptr->ObjectType = ObjectTypes.ValueTypeObjectReference;                *(long*)&ptr->Value = (long)dst;                InitializeValueTypeObject(type, dst, register, ref managedIdx, noInitialize);            }            else                throw new ArgumentException(type.FullName + " is not a value type.", "type");        }        internal void InitializeValueTypeObject(IType type, StackObject* ptr, bool register, ref int managedIdx, bool noInitialize)        {            ptr->ObjectType = ObjectTypes.ValueTypeDescriptor;            ptr->Value = type.TypeIndex;            ptr->ValueLow = type.TotalFieldCount;            StackObject* endPtr = ptr - (type.TotalFieldCount + 1);            if (noInitialize)                return;            if (type is ILType)            {                ILType t = (ILType)type;                for (int i = 0; i < t.FieldTypes.Length; i++)                {                    var ft = t.FieldTypes[i];                    StackObject* val = ILIntepreter.Minus(ptr, t.FieldStartIndex + i + 1);                    if (ft.IsPrimitive)                        *val = ft.DefaultObject;                    else if (ft.IsEnum)                        StackObject.Initialized(val, ft);                    else                    {                        if (ft.IsValueType)                        {                            if (ft is ILType || ((CLRType)ft).ValueTypeBinder != null)                            {                                val->ObjectType = ObjectTypes.ValueTypeObjectReference;                                *(long*)&val->Value = (long)endPtr;                                InitializeValueTypeObject(ft, endPtr, register, ref managedIdx, noInitialize);                                int size, mCnt;                                ft.GetValueTypeSize(out size, out mCnt);                                endPtr -= size;                            }                            else                            {                                val->ObjectType = ObjectTypes.Object;                                val->Value = managedIdx;                                if (managedIdx < managedStack.Count)                                    managedStack[managedIdx] = ((CLRType)ft).CreateDefaultInstance();                                else                                    managedStack.Add(((CLRType)ft).CreateDefaultInstance());                                managedIdx++;                            }                        }                        else                        {                            val->ObjectType = ObjectTypes.Object;                            val->Value = managedIdx;                            if (managedIdx < managedStack.Count)                                managedStack[managedIdx] = null;                            else                                managedStack.Add(null);                            managedIdx++;                        }                    }                }                if (type.BaseType != null && type.BaseType is ILType)                    InitializeValueTypeObject((ILType)type.BaseType, ptr, register, ref managedIdx, noInitialize);            }            else            {                CLRType t = (CLRType)type;                var cnt = t.TotalFieldCount;                for (int i = 0; i < cnt; i++)                {                    var it = t.OrderedFieldTypes[i] as CLRType;                    StackObject* val = ILIntepreter.Minus(ptr, i + 1);                    if (it.IsPrimitive)                        *val = it.DefaultObject;                    else if (it.IsEnum)                        StackObject.Initialized(val, it);                    else                    {                        if (it.IsValueType)                        {                            if (it.ValueTypeBinder != null)                            {                                val->ObjectType = ObjectTypes.ValueTypeObjectReference;                                *(long*)&val->Value = (long)endPtr;                                InitializeValueTypeObject(it, endPtr, register, ref managedIdx, noInitialize);                                int size, mCnt;                                it.GetValueTypeSize(out size, out mCnt);                                endPtr -= size;                            }                            else                            {                                val->ObjectType = ObjectTypes.Object;                                val->Value = managedIdx;                                if (managedIdx < managedStack.Count)                                    managedStack[managedIdx] = it.CreateDefaultInstance();                                else                                    managedStack.Add(it.CreateDefaultInstance());                                managedIdx++;                            }                        }                        else                        {                            val->ObjectType = ObjectTypes.Object;                            val->Value = managedIdx;                            if (managedIdx < managedStack.Count)                                managedStack[managedIdx] = null;                            else                                managedStack.Add(null);                            managedIdx++;                        }                    }                }            }        }        public void ClearValueTypeObject(IType type, StackObject* ptr)        {            if (type is ILType)            {                ILType t = (ILType)type;                for (int i = 0; i < t.FieldTypes.Length; i++)                {                    var ft = t.FieldTypes[i];                    StackObject* val = ILIntepreter.Minus(ptr, t.FieldStartIndex + i + 1);                    if (ft.IsPrimitive || ft.IsEnum)                        StackObject.Initialized(val, ft);                    else                    {                        switch (val->ObjectType)                        {                            case ObjectTypes.ValueTypeObjectReference:                                ClearValueTypeObject(ft, ILIntepreter.ResolveReference(val));                                break;                            default:                                if (ft.IsValueType)                                {                                    if(ft is ILType)                                    {                                        throw new NotImplementedException();                                    }                                    else                                    {                                        managedStack[val->Value] = ((CLRType)ft).CreateDefaultInstance();                                    }                                }                                else                                    managedStack[val->Value] = null;                                break;                        }                    }                }                if (type.BaseType != null && type.BaseType is ILType)                    ClearValueTypeObject((ILType)type.BaseType, ptr);            }            else            {                CLRType t = (CLRType)type;                var cnt = t.TotalFieldCount;                for (int i = 0; i < cnt; i++)                {                    var vt = t.OrderedFieldTypes[i] as CLRType;                    StackObject* val = ILIntepreter.Minus(ptr, i + 1);                    if (vt.IsPrimitive)                        StackObject.Initialized(val, vt);                    else                    {                        switch (val->ObjectType)                        {                            case ObjectTypes.ValueTypeObjectReference:                                {                                    var dst = ILIntepreter.ResolveReference(val);                                    ClearValueTypeObject(vt, dst);                                }                                break;                            default:                                if (vt.IsValueType)                                {                                    managedStack[val->Value] = vt.CreateDefaultInstance();                                }                                else                                    managedStack[val->Value] = null;                                break;                        }                    }                }            }        }        internal void RemoveManagedStackRange(int start, int end)        {            if (start != int.MaxValue)            {                if (end == managedStack.Count - 1)                {#if DEBUG && !DISABLE_ILRUNTIME_DEBUG                    ((List<object>)managedStack).RemoveRange(start, managedStack.Count - start);#else                    ((UncheckedList<object>)managedStack).RemoveRange(start, managedStack.Count - start);#endif                }                else                    throw new NotSupportedException();            }        }        public void FreeRegisterValueType(StackObject* esp)        {            if (esp->ObjectType != ObjectTypes.ValueTypeObjectReference)                return;            allocator.Free(esp);        }        public void FreeValueTypeObject(StackObject* esp)        {            if (esp->ObjectType != ObjectTypes.ValueTypeObjectReference)                return;            int start = int.MaxValue;            int end = int.MinValue;            StackObject* endAddr;            CountValueTypeManaged(esp, ref start, ref end, &endAddr);            if (endAddr == valueTypePtr)                valueTypePtr = ILIntepreter.ResolveReference(esp);            else                throw new NotSupportedException();            RemoveManagedStackRange(start, end);        }        public void CountValueTypeManaged(StackObject* esp, ref int start, ref int end, StackObject** endAddr)        {            StackObject* descriptor = ILIntepreter.ResolveReference(esp);            int cnt = descriptor->ValueLow;            *endAddr = ILIntepreter.Minus(descriptor, cnt + 1);            for (int i = 0; i < cnt; i++)            {                StackObject* addr = ILIntepreter.Minus(descriptor, i + 1);                switch (addr->ObjectType)                {                    case ObjectTypes.Object:                    case ObjectTypes.ArrayReference:                    case ObjectTypes.FieldReference:                        {                            if (start == int.MaxValue)                            {                                start = addr->Value;                                end = start;                            }                            else if (addr->Value == end + 1)                                end++;                            else                                throw new NotSupportedException();                        }                        break;                    case ObjectTypes.ValueTypeObjectReference:                        CountValueTypeManaged(addr, ref start, ref end, endAddr);                        break;                }            }        }        public void Dispose()        {            if (nativePointer != IntPtr.Zero)            {                System.Runtime.InteropServices.Marshal.FreeHGlobal(nativePointer);                nativePointer = IntPtr.Zero;            }        }        StackObject* Add(StackObject* a, int b)        {            return (StackObject*)((long)a + sizeof(StackObject) * b);        }    }}
 |