Cosmos/source/Cosmos.IL2CPU/IL/Newarr.cs
2015-07-28 20:18:14 -04:00

61 lines
3.4 KiB
C#

using System;
using CPUx86 = Cosmos.Assembler.x86;
using CPU = Cosmos.Assembler.x86;
using Cosmos.Assembler;
using System.Reflection;
using Cosmos.IL2CPU.IL.CustomImplementations.System;
namespace Cosmos.IL2CPU.X86.IL
{
/// <summary>
/// Pushes an object reference to a new zero-based, one-dimensional array whose elements are of a specific type onto the evaluation stack.
/// </summary>
[Cosmos.IL2CPU.OpCode( ILOpCode.Code.Newarr )]
public class Newarr : ILOp
{
public Newarr( Cosmos.Assembler.Assembler aAsmblr )
: base( aAsmblr )
{
}
public override void Execute( MethodInfo aMethod, ILOpCode aOpCode )
{
Cosmos.IL2CPU.ILOpCodes.OpType xType = ( Cosmos.IL2CPU.ILOpCodes.OpType )aOpCode;
uint xSize = SizeOfType( xType.Value );
//TODO cache it to reduce calculation
string xTypeID = GetTypeIDLabel(typeof(Array));
MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0];
string xCtorName = LabelName.Get( xCtor );
new Comment( Assembler, "Element Size = " + xSize );
// element count is on the stack
new CPUx86.Pop { DestinationReg = CPUx86.Registers.ESI };
new CPUx86.Push { DestinationReg = CPUx86.Registers.ESI };
//Assembler.StackSizes.Push(xElementCountSize);
new CPUx86.Push { DestinationValue = xSize };
new Mul( Assembler ).Execute( aMethod, aOpCode );
// the total items size is now on the stack
new CPUx86.Push { DestinationValue = ( ObjectImpl.FieldDataOffset + 4 ) };
new Add( Assembler ).Execute( aMethod, aOpCode );
// the total array size is now on the stack.
new CPUx86.Call { DestinationLabel = LabelName.Get( GCImplementationRefs.AllocNewObjectRef ) };
new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true };
new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true };
// it's on the stack 3 times now, once from the return value, twice from the pushes;
new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceRef = Cosmos.Assembler.ElementReference.New( xTypeID ), SourceIsIndirect = true };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EBX };
new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 4 };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceValue = ( uint )InstanceTypeEnum.Array, Size = 32 };
new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 4 };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.ESI, Size = 32 };
new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 4 };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceValue = ( uint )xSize, Size = 32 };
new CPUx86.Call { DestinationLabel = xCtorName };
}
}
}