You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

634 lines
24 KiB

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);
}
}
}