mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-30 04:40:14 +00:00
114 lines
No EOL
5 KiB
C#
114 lines
No EOL
5 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Indy.IL2CPU.Assembler;
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Cil;
|
|
using CPU = Indy.IL2CPU.Assembler.X86;
|
|
using Instruction = Mono.Cecil.Cil.Instruction;
|
|
|
|
namespace Indy.IL2CPU.IL.X86 {
|
|
[OpCode(Code.Ldc_I4)]
|
|
public class Ldc_I4: Op {
|
|
private int mValue;
|
|
private bool mOptimizedArrayFieldCode = false;
|
|
private FieldDefinition mTokenField;
|
|
private FieldDefinition mStaticField;
|
|
private int mCount;
|
|
private int mElementSize;
|
|
protected void SetValue(int aValue) {
|
|
mValue = aValue;
|
|
}
|
|
|
|
protected void SetValue(string aValue) {
|
|
SetValue(Int32.Parse(aValue));
|
|
}
|
|
|
|
public Ldc_I4(Mono.Cecil.Cil.Instruction aInstruction, MethodInformation aMethodInfo)
|
|
: base(aInstruction, aMethodInfo) {
|
|
// see if this opcode is part of a situation which can be optimized
|
|
#region explanation
|
|
/*
|
|
* See the following MSIL snippet as example:
|
|
*
|
|
* L_000a: ldc.i4.s 0x19
|
|
* L_000c: newarr char
|
|
* L_0011: dup
|
|
* L_0012: ldtoken valuetype <PrivateImplementationDetails>{0902461D-F9D1-470E-8BBD-C644516033E3}/__StaticArrayInitTypeSize=50 <PrivateImplementationDetails>{0902461D-F9D1-470E-8BBD-C644516033E3}::$$method0x60052b0-1
|
|
* L_0017: call void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class System.Array, valuetype System.RuntimeFieldHandle)
|
|
* L_001c: stsfld char[] System.String::WhitespaceChars
|
|
*
|
|
* Practically speaking, we can optimize this code (completey get rid of it) by
|
|
* initializing the field WhitespaceChars directly using the contents of the token
|
|
*
|
|
*/
|
|
if (aInstruction.Next != null && aInstruction.Next.OpCode.Code == Code.Newarr) {
|
|
Instruction xNewArr = aInstruction.Next;
|
|
if (xNewArr.Next != null && xNewArr.Next.OpCode.Code == Code.Dup) {
|
|
Instruction xDup = xNewArr.Next;
|
|
if (xDup.Next != null && xDup.Next.OpCode.Code == Code.Ldtoken) {
|
|
Instruction xLdtoken = xDup.Next;
|
|
if (xLdtoken.Next != null && xLdtoken.Next.OpCode.Code == Code.Call) {
|
|
Instruction xCall = xLdtoken.Next;
|
|
if (xCall.Next != null && xCall.Next.OpCode.Code == Code.Stsfld) {
|
|
Instruction xStsfld = xCall.Next;
|
|
// so far so good. only next constraint is that Call calls RuntimeHelpers::InitializeArray
|
|
// and the field to which it's stored is readonly
|
|
MethodReference xMethodRef = xCall.Operand as MethodReference;
|
|
FieldReference xFieldRef = xStsfld.Operand as FieldReference;
|
|
FieldReference xFieldContentsRef = xLdtoken.Operand as FieldReference;
|
|
TypeSpecification xFieldElementType = (xFieldRef != null ? xFieldRef.FieldType as TypeSpecification : null);
|
|
if (xFieldRef != null && xMethodRef != null && xFieldContentsRef != null && xFieldElementType != null) {
|
|
MethodDefinition xMethodDef = Engine.GetDefinitionFromMethodReference(xMethodRef);
|
|
FieldDefinition xFieldDef = Engine.GetDefinitionFromFieldReference(xFieldRef);
|
|
FieldDefinition xFieldContentsDef = Engine.GetDefinitionFromFieldReference(xFieldContentsRef);
|
|
if (xFieldDef.IsInitOnly && xMethodDef.ToString() == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") {
|
|
mElementSize = ObjectUtilities.GetObjectStorageSize(Engine.GetDefinitionFromTypeReference(xFieldElementType.ElementType));
|
|
mTokenField = xFieldContentsDef;
|
|
mStaticField = xFieldDef;
|
|
mOptimizedArrayFieldCode = true;
|
|
mCount = Int32.Parse(aInstruction.Operand.ToString());
|
|
Engine.SetInstructionsToSkip(5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
if (!mOptimizedArrayFieldCode) {
|
|
if (aInstruction.Operand != null) {
|
|
SetValue(aInstruction.Operand.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
public int Value {
|
|
get {
|
|
return mValue;
|
|
}
|
|
}
|
|
public override sealed void DoAssemble() {
|
|
if (mOptimizedArrayFieldCode) {
|
|
new Comment("Optimization:");
|
|
string xDataMemberName = DataMember.GetStaticFieldName(mStaticField);
|
|
DataMember xFieldDataMember = (from item in Assembler.DataMembers
|
|
where item.Name == xDataMemberName
|
|
select item).FirstOrDefault();
|
|
Assembler.DataMembers.Remove(xFieldDataMember);
|
|
xFieldDataMember = null;
|
|
string xTheData = BitConverter.GetBytes(Engine.RegisterTypeRef(mStaticField.FieldType)).Aggregate("", (r, b) => r + b + ",");
|
|
xTheData += BitConverter.GetBytes(0x80000002).Aggregate("", (r, b) => r + b + ",");
|
|
xTheData += BitConverter.GetBytes(mCount).Aggregate("", (r, b) => r + b + ",");
|
|
xTheData += BitConverter.GetBytes(mElementSize).Aggregate("", (r, b) => r + b + ",");
|
|
xTheData += mTokenField.InitialValue.Aggregate("", (r, b) => r + b + ",");
|
|
xTheData = xTheData.TrimEnd(',');
|
|
Assembler.DataMembers.Add(new DataMember(xDataMemberName, "db", xTheData));
|
|
|
|
} else {
|
|
new CPU.Pushd("0" + mValue.ToString("X") + "h");
|
|
Assembler.StackSizes.Push(4);
|
|
}
|
|
}
|
|
}
|
|
} |