PageRenderTime 53ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Boo.Lang/Runtime/MethodDispatcherEmitter.cs

https://github.com/boo/boo-lang
C# | 170 lines | 126 code | 19 blank | 25 comment | 8 complexity | 295f7d1fa4eb19c2862d37ec70ea8da7 MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, 2007 Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. using System;
  29. using System.Reflection;
  30. using System.Reflection.Emit;
  31. namespace Boo.Lang.Runtime
  32. {
  33. public delegate object Dispatcher(object target, object[] args);
  34. public class MethodDispatcherEmitter : DispatcherEmitter
  35. {
  36. protected readonly CandidateMethod _found;
  37. protected readonly Type[] _argumentTypes;
  38. public MethodDispatcherEmitter(CandidateMethod found, params Type[] argumentTypes) : this(found.Method.DeclaringType, found, argumentTypes)
  39. {
  40. }
  41. public MethodDispatcherEmitter(Type owner, CandidateMethod found, Type[] argumentTypes) : base(owner, found.Method.Name + "$" + Builtins.join(argumentTypes, "$"))
  42. {
  43. _found = found;
  44. _argumentTypes = argumentTypes;
  45. }
  46. protected override void EmitMethodBody()
  47. {
  48. EmitInvocation();
  49. EmitMethodReturn();
  50. }
  51. protected void EmitInvocation()
  52. {
  53. EmitLoadTargetObject();
  54. EmitMethodArguments();
  55. EmitMethodCall();
  56. }
  57. protected void EmitMethodCall()
  58. {
  59. _il.Emit(_found.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, _found.Method);
  60. }
  61. protected void EmitMethodArguments()
  62. {
  63. EmitFixedMethodArguments();
  64. if (_found.VarArgs) EmitVarArgsMethodArguments();
  65. }
  66. private void EmitFixedMethodArguments()
  67. {
  68. int offset = FixedArgumentOffset;
  69. int count = MinimumArgumentCount();
  70. for (int i = 0; i < count; ++i)
  71. {
  72. Type paramType = _found.GetParameterType(i + offset);
  73. EmitMethodArgument(i, paramType);
  74. }
  75. }
  76. protected virtual int FixedArgumentOffset
  77. {
  78. get { return 0; }
  79. }
  80. private void EmitVarArgsMethodArguments()
  81. {
  82. int varArgCount = _argumentTypes.Length - MinimumArgumentCount();
  83. Type varArgType = _found.VarArgsParameterType;
  84. OpCode storeOpCode = GetStoreElementOpCode(varArgType);
  85. _il.Emit(OpCodes.Ldc_I4, varArgCount);
  86. _il.Emit(OpCodes.Newarr, varArgType);
  87. for (int i = 0; i < varArgCount; ++i)
  88. {
  89. Dup();
  90. _il.Emit(OpCodes.Ldc_I4, i);
  91. if (IsStobj(storeOpCode))
  92. {
  93. _il.Emit(OpCodes.Ldelema, varArgType);
  94. EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
  95. _il.Emit(storeOpCode, varArgType);
  96. }
  97. else
  98. {
  99. EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
  100. _il.Emit(storeOpCode);
  101. }
  102. }
  103. }
  104. private int MinimumArgumentCount()
  105. {
  106. return _found.MinimumArgumentCount - FixedArgumentOffset;
  107. }
  108. static OpCode GetStoreElementOpCode(Type type)
  109. {
  110. if (type.IsValueType)
  111. {
  112. if (type.IsEnum) return OpCodes.Stelem_I4;
  113. switch (Type.GetTypeCode(type))
  114. {
  115. case TypeCode.Byte:
  116. return OpCodes.Stelem_I1;
  117. case TypeCode.Int16:
  118. return OpCodes.Stelem_I2;
  119. case TypeCode.Int32:
  120. return OpCodes.Stelem_I4;
  121. case TypeCode.Int64:
  122. return OpCodes.Stelem_I8;
  123. case TypeCode.Single:
  124. return OpCodes.Stelem_R4;
  125. case TypeCode.Double:
  126. return OpCodes.Stelem_R8;
  127. }
  128. return OpCodes.Stobj;
  129. }
  130. return OpCodes.Stelem_Ref;
  131. }
  132. protected void EmitMethodArgument(int argumentIndex, Type expectedType)
  133. {
  134. EmitArgArrayElement(argumentIndex);
  135. EmitCoercion(argumentIndex, expectedType, _found.ArgumentScores[argumentIndex]);
  136. }
  137. private void EmitCoercion(int argumentIndex, Type expectedType, int score)
  138. {
  139. EmitCoercion(_argumentTypes[argumentIndex], expectedType, score);
  140. }
  141. protected virtual void EmitLoadTargetObject()
  142. {
  143. if (_found.Method.IsStatic) return;
  144. EmitLoadTargetObject(_found.Method.DeclaringType);
  145. }
  146. private void EmitMethodReturn()
  147. {
  148. EmitReturn(_found.Method.ReturnType);
  149. }
  150. }
  151. }