mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-29 12:20:36 +00:00
188 lines
No EOL
6.2 KiB
C#
188 lines
No EOL
6.2 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Indy.IL2CPU.Assembler;
|
|
using Indy.IL2CPU.Assembler.X86;
|
|
using CPUx86 = Indy.IL2CPU.Assembler.X86;
|
|
using Instruction = Mono.Cecil.Cil.Instruction;
|
|
|
|
namespace Indy.IL2CPU.IL.X86 {
|
|
public abstract class Op: IL.Op {
|
|
public Op(Instruction aInstruction, MethodInformation aMethodInfo)
|
|
: base(aInstruction, aMethodInfo) {
|
|
}
|
|
|
|
public static void Ldarg(Assembler.Assembler aAssembler, MethodInformation.Argument aArg) {
|
|
Ldarg(aAssembler, aArg, true);
|
|
}
|
|
|
|
public static void Ldarg(Assembler.Assembler aAssembler, MethodInformation.Argument aArg, bool aAddGCCode) {
|
|
foreach (string xAddress in aArg.VirtualAddresses) {
|
|
new Move(CPUx86.Registers.EAX, "[" + xAddress + "]");
|
|
new Push(CPUx86.Registers.EAX);
|
|
}
|
|
aAssembler.StackSizes.Push(aArg.Size);
|
|
if (!aAssembler.InMetalMode && aAddGCCode && aArg.IsReferenceType) {
|
|
new CPUx86.Push(CPUx86.Registers.EAX);
|
|
Engine.QueueMethodRef(GCImplementationRefs.IncRefCountRef);
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.IncRefCountRef));
|
|
}
|
|
}
|
|
|
|
public static void Ldflda(Assembler.Assembler aAssembler, TypeInformation.Field aField) {
|
|
int aExtraOffset = 0;
|
|
if (aField.NeedsGC && !aAssembler.InMetalMode) {
|
|
aExtraOffset = 8;
|
|
}
|
|
new Popd(CPUx86.Registers.EAX);
|
|
new CPUx86.Add(CPUx86.Registers.EAX, "0x" + (aField.Offset + aExtraOffset).ToString("X"));
|
|
new Pushd(CPUx86.Registers.EAX);
|
|
aAssembler.StackSizes.Push(4);
|
|
}
|
|
|
|
public static void Multiply(Assembler.Assembler aAssembler) {
|
|
aAssembler.StackSizes.Pop();
|
|
new CPUx86.Pop("eax");
|
|
new CPUx86.Multiply("dword [esp]");
|
|
new CPUx86.Add("esp", "4");
|
|
new Pushd("eax");
|
|
}
|
|
|
|
public static void Ldfld(Assembler.Assembler aAssembler, TypeInformation.Field aField) {
|
|
Ldfld(aAssembler, aField, true);
|
|
}
|
|
|
|
public static void Ldfld(Assembler.Assembler aAssembler, TypeInformation.Field aField, bool aAddGCCode) {
|
|
aAssembler.StackSizes.Pop();
|
|
int aExtraOffset = 0;
|
|
if (aField.NeedsGC && !aAssembler.InMetalMode) {
|
|
aExtraOffset = 12;
|
|
}
|
|
new CPUx86.Pop("ecx");
|
|
new CPUx86.Add("ecx", "0x" + (aField.Offset + aExtraOffset).ToString("X"));
|
|
if (aField.Size >= 4) {
|
|
for (int i = 0; i < (aField.Size / 4); i++) {
|
|
new CPUx86.Move("eax", "[ecx + 0x" + (i * 4).ToString("X") + "]");
|
|
new CPUx86.Pushd("eax");
|
|
}
|
|
switch (aField.Size % 4) {
|
|
case 1: {
|
|
new CPUx86.Move("eax", "0");
|
|
new CPUx86.Move("al", "[ecx + 0x" + (aField.Size - 1).ToString("X") + "]");
|
|
new CPUx86.Push("eax");
|
|
break;
|
|
}
|
|
case 2: {
|
|
new CPUx86.Move("eax", "0");
|
|
new CPUx86.Move("ax", "[ecx + 0x" + (aField.Size - 2).ToString("X") + "]");
|
|
new CPUx86.Push("eax");
|
|
break;
|
|
}
|
|
case 0: {
|
|
break;
|
|
}
|
|
default:
|
|
throw new Exception("Remainder size " + (aField.Size % 4) + " not supported!");
|
|
}
|
|
} else {
|
|
switch (aField.Size) {
|
|
case 1: {
|
|
new CPUx86.Move("eax", "0");
|
|
new CPUx86.Move("al", "[ecx]");
|
|
new CPUx86.Push("eax");
|
|
break;
|
|
}
|
|
case 2: {
|
|
new CPUx86.Move("eax", "0");
|
|
new CPUx86.Move("ax", "[ecx]");
|
|
new CPUx86.Push("eax");
|
|
break;
|
|
}
|
|
case 0: {
|
|
break;
|
|
}
|
|
default:
|
|
throw new Exception("Remainder size " + (aField.Size) + " not supported!");
|
|
}
|
|
}
|
|
if (aAddGCCode && aField.NeedsGC && !aAssembler.InMetalMode) {
|
|
new CPUx86.Pushd(Registers.AtESP);
|
|
Engine.QueueMethodRef(GCImplementationRefs.IncRefCountRef);
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.IncRefCountRef));
|
|
}
|
|
aAssembler.StackSizes.Push(aField.Size);
|
|
}
|
|
|
|
public static void Stfld(Assembler.Assembler aAssembler, TypeInformation.Field aField) {
|
|
aAssembler.StackSizes.Pop();
|
|
int xRoundedSize = aField.Size;
|
|
if (xRoundedSize % 4 != 0) {
|
|
xRoundedSize += 4 - (xRoundedSize % 4);
|
|
}
|
|
int aExtraOffset = 0;
|
|
if (aField.NeedsGC && !aAssembler.InMetalMode) {
|
|
aExtraOffset = 12;
|
|
new CPUx86.Pushd("[esp + 4]");
|
|
Ldfld(aAssembler, aField, false);
|
|
Engine.QueueMethod(GCImplementationRefs.DecRefCountRef);
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.DecRefCountRef));
|
|
}
|
|
new CPUx86.Move("ecx", "[esp + 0x" + xRoundedSize.ToString("X") + "]");
|
|
new CPUx86.Add("ecx", "0x" + (aField.Offset + aExtraOffset).ToString("X"));
|
|
for (int i = 1; i <= (aField.Size / 4); i++) {
|
|
new CPUx86.Pop("eax");
|
|
new Move("dword [ecx + 0x" + (aField.Size - (i * 4)).ToString("X") + "]", "eax");
|
|
}
|
|
switch (aField.Size % 4) {
|
|
case 1: {
|
|
new CPUx86.Pop("eax");
|
|
new Move("byte [ecx]", "al");
|
|
break;
|
|
}
|
|
case 2: {
|
|
new CPUx86.Pop("eax");
|
|
new Move("word [ecx]", "ax");
|
|
break;
|
|
}
|
|
case 0: {
|
|
break;
|
|
}
|
|
default:
|
|
throw new Exception("Remainder size " + (aField.Size % 4) + " not supported!");
|
|
|
|
}
|
|
if (aField.NeedsGC && !aAssembler.InMetalMode) {
|
|
new CPUx86.Pushd(Registers.ECX);
|
|
new CPUx86.Pushd(Registers.EAX);
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.DecRefCountRef));
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.DecRefCountRef));
|
|
}
|
|
new CPUx86.Add("esp", "4");
|
|
aAssembler.StackSizes.Pop();
|
|
}
|
|
|
|
public static void Add(Assembler.Assembler aAssembler) {
|
|
aAssembler.StackSizes.Pop();
|
|
new CPUx86.Pop("eax");
|
|
new CPUx86.Add("eax", "[esp]");
|
|
new CPUx86.Add("esp", "4");
|
|
new Pushd("eax");
|
|
}
|
|
|
|
public static void Ldloc(Assembler.Assembler aAssembler, MethodInformation.Variable aLocal) {
|
|
Ldloc(aAssembler, aLocal, true);
|
|
}
|
|
|
|
public static void Ldloc(Assembler.Assembler aAssembler, MethodInformation.Variable aLocal, bool aAddGCCode) {
|
|
foreach (string s in aLocal.VirtualAddresses) {
|
|
new CPUx86.Move("eax", "[" + s + "]");
|
|
new CPUx86.Push("eax");
|
|
}
|
|
aAssembler.StackSizes.Push(aLocal.Size);
|
|
if (!aAssembler.InMetalMode && aAddGCCode && aLocal.IsReferenceType) {
|
|
new CPUx86.Push("eax");
|
|
Engine.QueueMethodRef(GCImplementationRefs.IncRefCountRef);
|
|
new CPUx86.Call(Label.GenerateLabelName(GCImplementationRefs.IncRefCountRef));
|
|
}
|
|
}
|
|
}
|
|
} |