BOO-999
[boo.git] / src / Boo.Lang / Runtime / MethodDispatcherEmitter.cs
blob3855166813ebae65c296ca6d9813ded73f681734
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.
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
29 using System;
30 using System.Reflection;
31 using System.Reflection.Emit;
33 namespace Boo.Lang.Runtime
35 public delegate object Dispatcher(object target, object[] args);
37 public class MethodDispatcherEmitter : DispatcherEmitter
39 protected readonly CandidateMethod _found;
40 protected readonly Type[] _argumentTypes;
42 public MethodDispatcherEmitter(CandidateMethod found, params Type[] argumentTypes) : this(found.Method.DeclaringType, found, argumentTypes)
46 public MethodDispatcherEmitter(Type owner, CandidateMethod found, Type[] argumentTypes) : base(owner, found.Method.Name + "$" + Builtins.join(argumentTypes, "$"))
48 _found = found;
49 _argumentTypes = argumentTypes;
52 protected override void EmitMethodBody()
54 EmitInvocation();
55 EmitMethodReturn();
58 protected void EmitInvocation()
60 EmitLoadTargetObject();
61 EmitMethodArguments();
62 EmitMethodCall();
65 protected void EmitMethodCall()
67 _il.Emit(_found.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, _found.Method);
70 protected void EmitMethodArguments()
72 EmitFixedMethodArguments();
73 if (_found.VarArgs) EmitVarArgsMethodArguments();
76 private void EmitFixedMethodArguments()
78 int offset = FixedArgumentOffset;
79 int count = MinimumArgumentCount();
80 for (int i = 0; i < count; ++i)
82 Type paramType = _found.GetParameterType(i + offset);
83 EmitMethodArgument(i, paramType);
87 protected virtual int FixedArgumentOffset
89 get { return 0; }
92 private void EmitVarArgsMethodArguments()
94 int varArgCount = _argumentTypes.Length - MinimumArgumentCount();
95 Type varArgType = _found.VarArgsParameterType;
96 OpCode storeOpCode = GetStoreElementOpCode(varArgType);
97 _il.Emit(OpCodes.Ldc_I4, varArgCount);
98 _il.Emit(OpCodes.Newarr, varArgType);
99 for (int i = 0; i < varArgCount; ++i)
101 Dup();
102 _il.Emit(OpCodes.Ldc_I4, i);
103 if (IsStobj(storeOpCode))
105 _il.Emit(OpCodes.Ldelema, varArgType);
106 EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
107 _il.Emit(storeOpCode, varArgType);
109 else
111 EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
112 _il.Emit(storeOpCode);
117 private int MinimumArgumentCount()
119 return _found.MinimumArgumentCount - FixedArgumentOffset;
122 static OpCode GetStoreElementOpCode(Type type)
124 if (type.IsValueType)
126 if (type.IsEnum) return OpCodes.Stelem_I4;
128 switch (Type.GetTypeCode(type))
130 case TypeCode.Byte:
131 return OpCodes.Stelem_I1;
132 case TypeCode.Int16:
133 return OpCodes.Stelem_I2;
134 case TypeCode.Int32:
135 return OpCodes.Stelem_I4;
136 case TypeCode.Int64:
137 return OpCodes.Stelem_I8;
138 case TypeCode.Single:
139 return OpCodes.Stelem_R4;
140 case TypeCode.Double:
141 return OpCodes.Stelem_R8;
143 return OpCodes.Stobj;
145 return OpCodes.Stelem_Ref;
148 protected void EmitMethodArgument(int argumentIndex, Type expectedType)
150 EmitArgArrayElement(argumentIndex);
151 EmitCoercion(argumentIndex, expectedType, _found.ArgumentScores[argumentIndex]);
154 private void EmitCoercion(int argumentIndex, Type expectedType, int score)
156 EmitCoercion(_argumentTypes[argumentIndex], expectedType, score);
159 protected virtual void EmitLoadTargetObject()
161 if (_found.Method.IsStatic) return;
162 EmitLoadTargetObject(_found.Method.DeclaringType);
165 private void EmitMethodReturn()
167 EmitReturn(_found.Method.ReturnType);