PageRenderTime 34ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Callvirt.cs

#
C# | 230 lines | 101 code | 24 blank | 105 comment | 17 complexity | 9fda91432306c427e2f0746df5e7a1f4 MD5 | raw file
Possible License(s): BSD-2-Clause
  1. using System;
  2. // using System.Collections.Generic;
  3. // using System.Linq;
  4. using CPU = Cosmos.Assembler.x86;
  5. using CPUx86 = Cosmos.Assembler.x86;
  6. using Cosmos.IL2CPU.ILOpCodes;
  7. using Cosmos.Assembler;
  8. using System.Reflection;
  9. // using System.Reflection;
  10. // using Cosmos.IL2CPU.X86;
  11. // using Cosmos.IL2CPU.Compiler;
  12. namespace Cosmos.IL2CPU.X86.IL
  13. {
  14. [Cosmos.IL2CPU.OpCode( ILOpCode.Code.Callvirt )]
  15. public class Callvirt : ILOp
  16. {
  17. public Callvirt( Cosmos.Assembler.Assembler aAsmblr )
  18. : base( aAsmblr )
  19. {
  20. }
  21. public override void Execute( MethodInfo aMethod, ILOpCode aOpCode )
  22. {
  23. var xOpMethod = aOpCode as OpMethod;
  24. string xCurrentMethodLabel = GetLabel(aMethod, aOpCode.Position);
  25. DoExecute(Assembler, aMethod, xOpMethod.Value, xOpMethod.ValueUID, aOpCode);
  26. }
  27. public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aMethod, MethodBase aTargetMethod, uint aTargetMethodUID, ILOpCode aOp) {
  28. string xCurrentMethodLabel = GetLabel(aMethod, aOp.Position);
  29. // mTargetMethodInfo = GetService<IMetaDataInfoService>().GetMethodInfo(mMethod
  30. // , mMethod, mMethodDescription, null, mCurrentMethodInfo.DebugMode);
  31. string xNormalAddress = "";
  32. if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) {
  33. xNormalAddress = MethodInfoLabelGenerator.GenerateLabelName(aTargetMethod);
  34. }
  35. // mMethodIdentifier = GetService<IMetaDataInfoService>().GetMethodIdLabel(mMethod);
  36. int xArgCount = aTargetMethod.GetParameters().Length;
  37. uint xReturnSize = 0;
  38. var xMethodInfo = aTargetMethod as System.Reflection.MethodInfo;
  39. if (xMethodInfo != null) {
  40. xReturnSize = Align(SizeOfType(xMethodInfo.ReturnType), 4);
  41. }
  42. // Extracted from MethodInformation: Calculated offset
  43. // var xRoundedSize = ReturnSize;
  44. //if (xRoundedSize % 4 > 0) {
  45. // xRoundedSize += (4 - (ReturnSize % 4));
  46. //}
  47. //ExtraStackSize = (int)xRoundedSize;
  48. uint xExtraStackSize = Call.GetStackSizeToReservate(aTargetMethod);
  49. uint xThisOffset = 0;
  50. var xParameters = aTargetMethod.GetParameters();
  51. foreach (var xItem in xParameters) {
  52. xThisOffset += Align(SizeOfType(xItem.ParameterType), 4);
  53. Assembler.Stack.Pop();
  54. }
  55. if (!aTargetMethod.IsStatic) {
  56. //xThisOffset += Align(SizeOfType(aTargetMethod.DeclaringType), 4);
  57. Assembler.Stack.Pop();
  58. }
  59. // This is finding offset to self? It looks like we dont need offsets of other
  60. // arguments, but only self. If so can calculate without calculating all fields
  61. // Might have to go to old data structure for the offset...
  62. // Can we add this method info somehow to the data passed in?
  63. // mThisOffset = mTargetMethodInfo.Arguments[0].Offset;
  64. new Comment(Assembler, "ThisOffset = " + xThisOffset);
  65. // Action xEmitCleanup = delegate() {
  66. // foreach (MethodInformation.Argument xArg in mTargetMethodInfo.Arguments) {
  67. // new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = xArg.Size };
  68. // }
  69. // };
  70. //EmitCompareWithNull( Assembler,
  71. // mCurrentMethodInfo,
  72. // delegate( CPUx86.Compare c )
  73. // {
  74. // c.DestinationReg = CPUx86.Registers.ESP;
  75. // c.DestinationIsIndirect = true;
  76. // c.DestinationDisplacement = mThisOffset;
  77. // },
  78. // mLabelName,
  79. // mLabelName + "_AfterNullRefCheck",
  80. // xEmitCleanup,
  81. // ( int )mCurrentILOffset,
  82. // GetService<IMetaDataInfoService>().GetTypeIdLabel( typeof( NullReferenceException ) ),
  83. // GetService<IMetaDataInfoService>().GetTypeInfo( typeof( NullReferenceException ) ),
  84. // GetService<IMetaDataInfoService>().GetMethodInfo( typeof( NullReferenceException ).GetConstructor( Type.EmptyTypes ), false ),
  85. // GetServiceProvider() );
  86. // todo: add exception support
  87. new Label(xCurrentMethodLabel + ".AfterNullRefCheck");
  88. if (!String.IsNullOrEmpty(xNormalAddress)) {
  89. if (xExtraStackSize > 0) {
  90. new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xExtraStackSize };
  91. }
  92. new CPUx86.Call { DestinationLabel = xNormalAddress };
  93. } else {
  94. /*
  95. * On the stack now:
  96. * $esp Params
  97. * $esp + mThisOffset This
  98. */
  99. new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset };
  100. new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true };
  101. new CPUx86.Push { DestinationValue = aTargetMethodUID };
  102. new CPUx86.Call {
  103. DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(VTablesImplRefs.GetMethodAddressForTypeRef)
  104. };
  105. if (xExtraStackSize > 0)
  106. {
  107. xThisOffset -= xExtraStackSize;
  108. }
  109. /*
  110. * On the stack now:
  111. * $esp Params
  112. * $esp + mThisOffset This
  113. */
  114. //Call.EmitExceptionLogic( Assembler,
  115. // mCurrentILOffset,
  116. // mCurrentMethodInfo,
  117. // mLabelName + "_AfterAddressCheck",
  118. // true,
  119. // xEmitCleanup );
  120. new Label(xCurrentMethodLabel + ".AfterAddressCheck");
  121. if (xMethodInfo.DeclaringType == typeof(object)) {
  122. /*
  123. * On the stack now:
  124. * $esp method to call
  125. * $esp + 4 Params
  126. * $esp + mThisOffset + 4 This
  127. */
  128. // we need to see if $this is a boxed object, and if so, we need to box it
  129. new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)(xThisOffset + 4) };
  130. //new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = ( ( uint )InstanceTypeEnum.BoxedValueType ), Size = 32 };
  131. //InstanceTypeEnum.BoxedValueType == 3 =>
  132. new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 3, Size = 32 };
  133. /*
  134. * On the stack now:
  135. * $esp Params
  136. * $esp + mThisOffset This
  137. *
  138. * EAX contains the method to call
  139. */
  140. new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.NotEqual, DestinationLabel = xCurrentMethodLabel + ".NotBoxedThis" };
  141. new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX };
  142. /*
  143. * On the stack now:
  144. * $esp Params
  145. * $esp + mThisOffset This
  146. *
  147. * ECX contains the method to call
  148. */
  149. new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset };
  150. /*
  151. * On the stack now:
  152. * $esp Params
  153. * $esp + mThisOffset This
  154. *
  155. * ECX contains the method to call
  156. * EAX contains $This, but boxed
  157. */
  158. //new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = ( uint )ObjectImpl.FieldDataOffset };
  159. //public const int FieldDataOffset = 12; // ObjectImpl says that. so..
  160. new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 12 };
  161. new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xThisOffset, SourceReg = CPUx86.Registers.EAX};
  162. /*
  163. * On the stack now:
  164. * $esp Params
  165. * $esp + mThisOffset Pointer to address inside box
  166. *
  167. * ECX contains the method to call
  168. */
  169. new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX };
  170. /*
  171. * On the stack now:
  172. * $esp Method to call
  173. * $esp + 4 Params
  174. * $esp + mThisOffset + 4 This
  175. */
  176. }
  177. new Label(xCurrentMethodLabel + ".NotBoxedThis");
  178. new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };
  179. if (xExtraStackSize > 0) {
  180. new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = xExtraStackSize };
  181. }
  182. new CPUx86.Call { DestinationReg = CPUx86.Registers.EAX };
  183. new Label(xCurrentMethodLabel + ".AfterNotBoxedThis");
  184. }
  185. ILOp.EmitExceptionLogic(Assembler, aMethod, aOp, true,
  186. delegate()
  187. {
  188. var xResultSize = xReturnSize;
  189. if (xResultSize % 4 != 0)
  190. {
  191. xResultSize += 4 - (xResultSize % 4);
  192. }
  193. for (int i = 0; i < xResultSize / 4; i++)
  194. {
  195. new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 };
  196. }
  197. });
  198. new Label(xCurrentMethodLabel + ".NoExceptionAfterCall");
  199. new Comment(Assembler, "Argument Count = " + xParameters.Length.ToString());
  200. if (xReturnSize > 0) {
  201. Assembler.Stack.Push(new StackContents.Item(xReturnSize, typeof(Int32)));
  202. }
  203. //throw new NotImplementedException();
  204. }
  205. }
  206. }