/Dependencies/boo/src/Boo.Lang/Runtime/MethodDispatcherEmitter.cs
C# | 170 lines | 126 code | 19 blank | 25 comment | 8 complexity | e7c2a4b7c473f5968c51a483ecf9122c MD5 | raw file
Possible License(s): GPL-2.0
- #region license
- // Copyright (c) 2004, 2007 Rodrigo B. de Oliveira (rbo@acm.org)
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- // * Neither the name of Rodrigo B. de Oliveira nor the names of its
- // contributors may be used to endorse or promote products derived from this
- // software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #endregion
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- namespace Boo.Lang.Runtime
- {
- public delegate object Dispatcher(object target, object[] args);
- public class MethodDispatcherEmitter : DispatcherEmitter
- {
- protected readonly CandidateMethod _found;
- protected readonly Type[] _argumentTypes;
- public MethodDispatcherEmitter(CandidateMethod found, params Type[] argumentTypes) : this(found.Method.DeclaringType, found, argumentTypes)
- {
- }
- public MethodDispatcherEmitter(Type owner, CandidateMethod found, Type[] argumentTypes) : base(owner, found.Method.Name + "$" + Builtins.join(argumentTypes, "$"))
- {
- _found = found;
- _argumentTypes = argumentTypes;
- }
- protected override void EmitMethodBody()
- {
- EmitInvocation();
- EmitMethodReturn();
- }
- protected void EmitInvocation()
- {
- EmitLoadTargetObject();
- EmitMethodArguments();
- EmitMethodCall();
- }
- protected void EmitMethodCall()
- {
- _il.Emit(_found.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, _found.Method);
- }
- protected void EmitMethodArguments()
- {
- EmitFixedMethodArguments();
- if (_found.VarArgs) EmitVarArgsMethodArguments();
- }
- private void EmitFixedMethodArguments()
- {
- int offset = FixedArgumentOffset;
- int count = MinimumArgumentCount();
- for (int i = 0; i < count; ++i)
- {
- Type paramType = _found.GetParameterType(i + offset);
- EmitMethodArgument(i, paramType);
- }
- }
- protected virtual int FixedArgumentOffset
- {
- get { return 0; }
- }
- private void EmitVarArgsMethodArguments()
- {
- int varArgCount = _argumentTypes.Length - MinimumArgumentCount();
- Type varArgType = _found.VarArgsParameterType;
- OpCode storeOpCode = GetStoreElementOpCode(varArgType);
- _il.Emit(OpCodes.Ldc_I4, varArgCount);
- _il.Emit(OpCodes.Newarr, varArgType);
- for (int i = 0; i < varArgCount; ++i)
- {
- Dup();
- _il.Emit(OpCodes.Ldc_I4, i);
- if (IsStobj(storeOpCode))
- {
- _il.Emit(OpCodes.Ldelema, varArgType);
- EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
- _il.Emit(storeOpCode, varArgType);
- }
- else
- {
- EmitMethodArgument(MinimumArgumentCount() + i, varArgType);
- _il.Emit(storeOpCode);
- }
- }
- }
- private int MinimumArgumentCount()
- {
- return _found.MinimumArgumentCount - FixedArgumentOffset;
- }
- static OpCode GetStoreElementOpCode(Type type)
- {
- if (type.IsValueType)
- {
- if (type.IsEnum) return OpCodes.Stelem_I4;
- switch (Type.GetTypeCode(type))
- {
- case TypeCode.Byte:
- return OpCodes.Stelem_I1;
- case TypeCode.Int16:
- return OpCodes.Stelem_I2;
- case TypeCode.Int32:
- return OpCodes.Stelem_I4;
- case TypeCode.Int64:
- return OpCodes.Stelem_I8;
- case TypeCode.Single:
- return OpCodes.Stelem_R4;
- case TypeCode.Double:
- return OpCodes.Stelem_R8;
- }
- return OpCodes.Stobj;
- }
- return OpCodes.Stelem_Ref;
- }
- protected void EmitMethodArgument(int argumentIndex, Type expectedType)
- {
- EmitArgArrayElement(argumentIndex);
- EmitCoercion(argumentIndex, expectedType, _found.ArgumentScores[argumentIndex]);
- }
- private void EmitCoercion(int argumentIndex, Type expectedType, int score)
- {
- EmitCoercion(_argumentTypes[argumentIndex], expectedType, score);
- }
- protected virtual void EmitLoadTargetObject()
- {
- if (_found.Method.IsStatic) return;
- EmitLoadTargetObject(_found.Method.DeclaringType);
- }
- private void EmitMethodReturn()
- {
- EmitReturn(_found.Method.ReturnType);
- }
- }
- }