2 // Copyright (c) 2004, 2007 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
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.
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
, "$"))
49 _argumentTypes
= argumentTypes
;
52 protected override void EmitMethodBody()
58 protected void EmitInvocation()
60 EmitLoadTargetObject();
61 EmitMethodArguments();
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
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
)
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
);
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
))
131 return OpCodes
.Stelem_I1
;
133 return OpCodes
.Stelem_I2
;
135 return OpCodes
.Stelem_I4
;
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
);