You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

985 lines
34 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using ILRuntime.Mono.Cecil;
using ILRuntime.Runtime;
using ILRuntime.Runtime.Intepreter.OpCodes;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.Runtime.Intepreter.RegisterVM;
using ILRuntime.Runtime.Debugger;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.Reflection;
namespace ILRuntime.CLR.Method
{
public class ILMethod : IMethod
{
OpCode[] body;
OpCodeR[] bodyRegister;
Dictionary<int, RegisterVMSymbol> registerSymbols;
bool symbolFixed;
MethodDefinition def;
List<IType> parameters;
ILRuntime.Runtime.Enviorment.AppDomain appdomain;
ILType declaringType;
ExceptionHandler[] exceptionHandler, exceptionHandlerR;
KeyValuePair<string, IType>[] genericParameters;
IType[] genericArguments;
Dictionary<int, int[]> jumptables, jumptablesR;
bool isDelegateInvoke;
bool jitPending;
ILRuntimeMethodInfo refletionMethodInfo;
ILRuntimeConstructorInfo reflectionCtorInfo;
int paramCnt, localVarCnt, stackRegisterCnt;
int jitFlags;
bool jitOnDemand;
bool jitImmediately;
int warmupCounter = 0;
Mono.Collections.Generic.Collection<Mono.Cecil.Cil.VariableDefinition> variables;
int hashCode = -1;
static int instance_id = 0x10000000;
const int JITWarmUpThreshold = 10;
public bool Compiling { get; set; }
public bool IsRegisterBodyReady { get { return bodyRegister != null; } }
public MethodDefinition Definition { get { return def; } }
public Dictionary<int, int[]> JumpTables { get { return jumptables; } }
public Dictionary<int, int[]> JumpTablesRegister { get { return jumptablesR; } }
internal Dictionary<int, RegisterVMSymbol> RegisterVMSymbols { get { return registerSymbols; } }
internal int JITFlags { get { return jitFlags; } }
internal bool IsRegisterVMSymbolFixed { get { return symbolFixed; } }
internal IDelegateAdapter DelegateAdapter { get; set; }
internal int StartLine { get; set; }
internal int EndLine { get; set; }
public ILRuntime.Runtime.Enviorment.AppDomain AppDomain { get { return appdomain; } }
public MethodInfo ReflectionMethodInfo
{
get
{
if (IsConstructor)
throw new NotSupportedException();
if (refletionMethodInfo == null)
refletionMethodInfo = new ILRuntimeMethodInfo(this);
return refletionMethodInfo;
}
}
public ConstructorInfo ReflectionConstructorInfo
{
get
{
if (!IsConstructor)
throw new NotSupportedException();
if (reflectionCtorInfo == null)
reflectionCtorInfo = new ILRuntimeConstructorInfo(this);
return reflectionCtorInfo;
}
}
internal ExceptionHandler[] ExceptionHandler
{
get
{
return exceptionHandler;
}
}
internal ExceptionHandler[] ExceptionHandlerRegister
{
get
{
return exceptionHandlerR;
}
}
public string Name
{
get
{
return def.Name;
}
}
public IType DeclearingType
{
get
{
return declaringType;
}
}
public bool HasThis
{
get
{
return def.HasThis;
}
}
public int GenericParameterCount
{
get
{
if (IsGenericInstance)
return 0;
return def.GenericParameters.Count;
}
}
public bool IsGenericInstance
{
get
{
return genericParameters != null;
}
}
public Mono.Collections.Generic.Collection<Mono.Cecil.Cil.VariableDefinition> Variables
{
get
{
return variables;
}
}
public KeyValuePair<string, IType>[] GenericArguments { get { return genericParameters; } }
public IType[] GenericArugmentsArray { get { return genericArguments; } }
public bool ShouldUseRegisterVM
{
get
{
if (bodyRegister != null)
{
body = null;
exceptionHandler = null;
return true;
}
else
{
if (jitImmediately)
{
InitCodeBody(true);
return true;
}
else
{
if (jitOnDemand)
{
warmupCounter++;
if (warmupCounter > JITWarmUpThreshold && !jitPending)
{
jitPending = true;
AppDomain.EnqueueJITCompileJob(this);
}
}
return false;
}
}
}
}
public ILMethod(MethodDefinition def, ILType type, ILRuntime.Runtime.Enviorment.AppDomain domain, int flags)
{
this.def = def;
declaringType = type;
this.jitFlags = flags;
if (def.ReturnType.IsGenericParameter)
{
ReturnType = FindGenericArgument(def.ReturnType.Name);
}
else
ReturnType = domain.GetType(def.ReturnType, type, this);
if (type.IsDelegate && def.Name == "Invoke")
isDelegateInvoke = true;
this.appdomain = domain;
paramCnt = def.HasParameters ? def.Parameters.Count : 0;
if(def.HasCustomAttributes)
{
for(int i = 0; i < def.CustomAttributes.Count; i++)
{
int f;
if(def.CustomAttributes[i].GetJITFlags(domain, out f))
{
this.jitFlags = f;
break;
}
}
}
jitImmediately = (jitFlags & ILRuntimeJITFlags.JITImmediately) == ILRuntimeJITFlags.JITImmediately;
jitOnDemand = (jitFlags & ILRuntimeJITFlags.JITOnDemand) == ILRuntimeJITFlags.JITOnDemand;
#if DEBUG && !DISABLE_ILRUNTIME_DEBUG
if (def.HasBody)
{
var sp = GetValidSequence(0, 1);
if (sp != null)
{
StartLine = sp.StartLine;
sp = GetValidSequence(def.Body.Instructions.Count - 1, -1);
if (sp != null)
{
EndLine = sp.EndLine;
}
}
}
#endif
}
public void FixRegisterVMSymbol()
{
if (!symbolFixed && registerSymbols != null)
{
symbolFixed = true;
JITCompiler.FixSymbol(registerSymbols);
}
}
Mono.Cecil.Cil.SequencePoint GetValidSequence(int startIdx, int dir)
{
var seqMapping = def.DebugInformation.GetSequencePointMapping();
var cur = DebugService.FindSequencePoint(def.Body.Instructions[startIdx], seqMapping);
while (cur != null && cur.StartLine == 0x0feefee)
{
startIdx += dir;
if (startIdx >= 0 && startIdx < def.Body.Instructions.Count)
{
cur = DebugService.FindSequencePoint(def.Body.Instructions[startIdx], seqMapping);
}
else
break;
}
return cur;
}
public IType FindGenericArgument(string name)
{
IType res = declaringType.FindGenericArgument(name);
if (res == null && genericParameters != null)
{
foreach (var i in genericParameters)
{
if (i.Key == name)
return i.Value;
}
}
else
return res;
return null;
}
internal OpCode[] Body
{
get
{
if (body == null)
InitCodeBody(false);
return body;
}
}
internal OpCodeR[] BodyRegister
{
get
{
if (bodyRegister == null)
InitCodeBody(true);
return bodyRegister;
}
}
public bool HasBody
{
get
{
return body != null;
}
}
public int LocalVariableCount
{
get
{
return localVarCnt;
}
}
public int StackRegisterCount
{
get
{
return stackRegisterCnt;
}
}
public bool IsConstructor
{
get
{
return def.IsConstructor;
}
}
public bool IsVirtual
{
get
{
return def.IsVirtual;
}
}
public bool IsDelegateInvoke
{
get
{
return isDelegateInvoke;
}
}
public bool IsStatic
{
get { return def.IsStatic; }
}
public int ParameterCount
{
get
{
return paramCnt;
}
}
public List<IType> Parameters
{
get
{
if (def.HasParameters && parameters == null)
{
InitParameters();
}
return parameters;
}
}
public IType ReturnType
{
get;
private set;
}
public void Prewarm(bool recursive)
{
HashSet<ILMethod> alreadyPrewarmed = null;
if (recursive)
{
alreadyPrewarmed = new HashSet<ILMethod>();
}
Prewarm(alreadyPrewarmed);
}
void PrewarmBody(HashSet<ILMethod> alreadyPrewarmed)
{
//当前方法用到的IType,提前InitializeMethods()。各个子调用,提前InitParameters()
var body = Body;
foreach (var ins in body)
{
switch (ins.Code)
{
case OpCodeEnum.Call:
case OpCodeEnum.Newobj:
case OpCodeEnum.Ldftn:
case OpCodeEnum.Ldvirtftn:
case OpCodeEnum.Callvirt:
{
var m = appdomain.GetMethod(ins.TokenInteger);
if (m is ILMethod)
{
ILMethod ilm = (ILMethod)m;
//如果参数alreadyPrewarmed不为空,则不仅prewarm当前方法,还会递归prewarm所有子调用
//如果参数alreadyPrewarmed为空,则只prewarm当前方法
if (alreadyPrewarmed != null)
{
ilm.Prewarm(alreadyPrewarmed);
}
}
else if (m is CLRMethod)
{
CLRMethod clrm = (CLRMethod)m;
ILRuntime.CLR.Utils.Extensions.GetTypeFlags(clrm.DeclearingType.TypeForCLR);
}
}
break;
case OpCodeEnum.Ldfld:
case OpCodeEnum.Stfld:
case OpCodeEnum.Ldflda:
case OpCodeEnum.Ldsfld:
case OpCodeEnum.Ldsflda:
case OpCodeEnum.Stsfld:
case OpCodeEnum.Ldtoken:
{
//提前InitializeBaseType()
var t = appdomain.GetType((int)(ins.TokenLong >> 32));
if (t != null)
{
var baseType = t.BaseType;
}
}
break;
}
}
}
void PrewarmBodyRegister(HashSet<ILMethod> alreadyPrewarmed)
{
//当前方法用到的IType,提前InitializeMethods()。各个子调用,提前InitParameters()
var body = BodyRegister;
foreach (var ins in body)
{
switch (ins.Code)
{
case OpCodeREnum.Call:
case OpCodeREnum.Newobj:
case OpCodeREnum.Ldftn:
case OpCodeREnum.Ldvirtftn:
case OpCodeREnum.Callvirt:
{
var m = appdomain.GetMethod(ins.Operand);
if (m is ILMethod)
{
ILMethod ilm = (ILMethod)m;
//如果参数alreadyPrewarmed不为空,则不仅prewarm当前方法,还会递归prewarm所有子调用
//如果参数alreadyPrewarmed为空,则只prewarm当前方法
if (alreadyPrewarmed != null)
{
ilm.Prewarm(alreadyPrewarmed);
}
}
else if (m is CLRMethod)
{
CLRMethod clrm = (CLRMethod)m;
ILRuntime.CLR.Utils.Extensions.GetTypeFlags(clrm.DeclearingType.TypeForCLR);
}
}
break;
case OpCodeREnum.Ldfld:
case OpCodeREnum.Stfld:
case OpCodeREnum.Ldflda:
case OpCodeREnum.Ldsfld:
case OpCodeREnum.Ldsflda:
case OpCodeREnum.Stsfld:
case OpCodeREnum.Ldtoken:
{
//提前InitializeBaseType()
var t = appdomain.GetType((int)(ins.OperandLong >> 32));
if (t != null)
{
var baseType = t.BaseType;
}
}
break;
}
}
}
private void Prewarm(HashSet<ILMethod> alreadyPrewarmed)
{
if (alreadyPrewarmed != null && alreadyPrewarmed.Add(this) == false)
return;
if (GenericParameterCount > 0 && !IsGenericInstance)
return;
//当前方法用到的CLR局部变量,提前InitializeFields()、GetTypeFlags()
for (int i = 0; i < LocalVariableCount; i++)
{
var v = Variables[i];
var vt = v.VariableType;
IType t;
if (vt.IsGenericParameter)
{
t = FindGenericArgument(vt.Name);
}
else
{
t = appdomain.GetType(v.VariableType, DeclearingType, this);
}
if (t is CLRType)
{
CLRType ct = (CLRType)t;
var fields = ct.Fields;
ILRuntime.CLR.Utils.Extensions.GetTypeFlags(ct.TypeForCLR);
}
}
if (jitImmediately || jitOnDemand)
PrewarmBodyRegister(alreadyPrewarmed);
else
PrewarmBody(alreadyPrewarmed);
}
internal void InitCodeBody(bool register)
{
if (def.HasBody)
{
localVarCnt = def.Body.Variables.Count;
Dictionary<Mono.Cecil.Cil.Instruction, int> addr = new Dictionary<Mono.Cecil.Cil.Instruction, int>();
bool noRelease = false;
if (register)
{
JITCompiler jit = new JITCompiler(appdomain, declaringType, this);
bodyRegister = jit.Compile(out stackRegisterCnt, out jumptablesR, addr, out registerSymbols);
}
else
{
InitStackCodeBody(addr);
if (jitOnDemand)
noRelease = bodyRegister == null;
}
if (def.Body.ExceptionHandlers.Count > 0)
{
ExceptionHandler[] ehs;
if (register)
{
if (exceptionHandlerR == null)
exceptionHandlerR = new Method.ExceptionHandler[def.Body.ExceptionHandlers.Count];
ehs = exceptionHandlerR;
}
else
{
if (exceptionHandler == null)
exceptionHandler = new Method.ExceptionHandler[def.Body.ExceptionHandlers.Count];
ehs = exceptionHandler;
}
for (int i = 0; i < def.Body.ExceptionHandlers.Count; i++)
{
var eh = def.Body.ExceptionHandlers[i];
ExceptionHandler e = new ExceptionHandler();
e.HandlerStart = addr[eh.HandlerStart];
e.HandlerEnd = eh.HandlerEnd != null ? addr[eh.HandlerEnd] - 1 : def.Body.Instructions.Count - 1;
e.TryStart = addr[eh.TryStart];
e.TryEnd = addr[eh.TryEnd] - 1;
switch (eh.HandlerType)
{
case Mono.Cecil.Cil.ExceptionHandlerType.Catch:
e.CatchType = appdomain.GetType(eh.CatchType, declaringType, this);
e.HandlerType = ExceptionHandlerType.Catch;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
e.HandlerType = ExceptionHandlerType.Finally;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
e.HandlerType = ExceptionHandlerType.Fault;
break;
default:
throw new NotImplementedException();
}
ehs[i] = e;
}
//Mono.Cecil.Cil.ExceptionHandlerType.
}
variables = def.Body.Variables;
#if !DEBUG || DISABLE_ILRUNTIME_DEBUG
//Release Method body to save memory
if(!noRelease)
def.Body = null;
#endif
}
else
body = new OpCode[0];
}
void InitStackCodeBody(Dictionary<Mono.Cecil.Cil.Instruction, int> addr)
{
body = new OpCode[def.Body.Instructions.Count];
for (int i = 0; i < body.Length; i++)
{
var c = def.Body.Instructions[i];
OpCode code = new OpCode();
code.Code = (OpCodeEnum)c.OpCode.Code;
addr[c] = i;
body[i] = code;
}
for (int i = 0; i < body.Length; i++)
{
var c = def.Body.Instructions[i];
InitToken(ref body[i], c.Operand, addr);
if (i > 0 && c.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt && def.Body.Instructions[i - 1].OpCode.Code == Mono.Cecil.Cil.Code.Constrained)
{
body[i - 1].TokenLong = body[i].TokenInteger;
}
}
}
unsafe void InitToken(ref OpCode code, object token, Dictionary<Mono.Cecil.Cil.Instruction, int> addr)
{
switch (code.Code)
{
case OpCodeEnum.Leave:
case OpCodeEnum.Leave_S:
case OpCodeEnum.Br:
case OpCodeEnum.Br_S:
case OpCodeEnum.Brtrue:
case OpCodeEnum.Brtrue_S:
case OpCodeEnum.Brfalse:
case OpCodeEnum.Brfalse_S:
//比较流程控制
case OpCodeEnum.Beq:
case OpCodeEnum.Beq_S:
case OpCodeEnum.Bne_Un:
case OpCodeEnum.Bne_Un_S:
case OpCodeEnum.Bge:
case OpCodeEnum.Bge_S:
case OpCodeEnum.Bge_Un:
case OpCodeEnum.Bge_Un_S:
case OpCodeEnum.Bgt:
case OpCodeEnum.Bgt_S:
case OpCodeEnum.Bgt_Un:
case OpCodeEnum.Bgt_Un_S:
case OpCodeEnum.Ble:
case OpCodeEnum.Ble_S:
case OpCodeEnum.Ble_Un:
case OpCodeEnum.Ble_Un_S:
case OpCodeEnum.Blt:
case OpCodeEnum.Blt_S:
case OpCodeEnum.Blt_Un:
case OpCodeEnum.Blt_Un_S:
code.TokenInteger = addr[(Mono.Cecil.Cil.Instruction)token];
break;
case OpCodeEnum.Ldc_I4:
code.TokenInteger = (int)token;
break;
case OpCodeEnum.Ldc_I4_S:
code.TokenInteger = (sbyte)token;
break;
case OpCodeEnum.Ldc_I8:
code.TokenLong = (long)token;
break;
case OpCodeEnum.Ldc_R4:
{
float val = (float)token;
code.TokenInteger = *(int*)&val;
}
break;
case OpCodeEnum.Ldc_R8:
{
double val = (double)token;
code.TokenLong = *(long*)&val;
}
break;
case OpCodeEnum.Stloc:
case OpCodeEnum.Stloc_S:
case OpCodeEnum.Ldloc:
case OpCodeEnum.Ldloc_S:
case OpCodeEnum.Ldloca:
case OpCodeEnum.Ldloca_S:
{
Mono.Cecil.Cil.VariableDefinition vd = (Mono.Cecil.Cil.VariableDefinition)token;
code.TokenInteger = vd.Index;
}
break;
case OpCodeEnum.Ldarg_S:
case OpCodeEnum.Ldarg:
case OpCodeEnum.Ldarga:
case OpCodeEnum.Ldarga_S:
case OpCodeEnum.Starg:
case OpCodeEnum.Starg_S:
{
Mono.Cecil.ParameterDefinition vd = (Mono.Cecil.ParameterDefinition)token;
code.TokenInteger = vd.Index;
if (HasThis)
code.TokenInteger++;
}
break;
case OpCodeEnum.Call:
case OpCodeEnum.Newobj:
case OpCodeEnum.Ldftn:
case OpCodeEnum.Ldvirtftn:
case OpCodeEnum.Callvirt:
{
bool invalidToken;
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
if (m != null)
{
if(code.Code == OpCodeEnum.Callvirt && m is ILMethod)
{
ILMethod ilm = (ILMethod)m;
if (!ilm.def.IsAbstract && !ilm.def.IsVirtual && !ilm.DeclearingType.IsInterface)
code.Code = OpCodeEnum.Call;
}
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
code.TokenInteger = token.GetHashCode();
}
else
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
}
}
break;
case OpCodeEnum.Constrained:
case OpCodeEnum.Box:
case OpCodeEnum.Unbox_Any:
case OpCodeEnum.Unbox:
case OpCodeEnum.Initobj:
case OpCodeEnum.Isinst:
case OpCodeEnum.Newarr:
case OpCodeEnum.Stobj:
case OpCodeEnum.Ldobj:
case OpCodeEnum.Castclass:
{
code.TokenInteger = GetTypeTokenHashCode(token);
}
break;
case OpCodeEnum.Stfld:
case OpCodeEnum.Ldfld:
case OpCodeEnum.Ldflda:
{
code.TokenLong = appdomain.GetStaticFieldIndex(token, declaringType, this);
}
break;
case OpCodeEnum.Stsfld:
case OpCodeEnum.Ldsfld:
case OpCodeEnum.Ldsflda:
{
code.TokenLong = appdomain.GetStaticFieldIndex(token, declaringType, this);
}
break;
case OpCodeEnum.Ldstr:
{
long hashCode = appdomain.CacheString(token);
code.TokenLong = hashCode;
}
break;
case OpCodeEnum.Ldtoken:
{
if (token is FieldReference)
{
code.TokenInteger = 0;
code.TokenLong = appdomain.GetStaticFieldIndex(token, declaringType, this);
}
else if (token is TypeReference)
{
code.TokenInteger = 1;
code.TokenLong = GetTypeTokenHashCode(token);
}
else
throw new NotImplementedException();
}
break;
case OpCodeEnum.Switch:
{
PrepareJumpTable(token, addr);
code.TokenInteger = token.GetHashCode();
}
break;
}
}
internal int GetTypeTokenHashCode(object token)
{
var t = appdomain.GetType(token, declaringType, this);
bool isGenericParameter = CheckHasGenericParamter(token);
if (t == null && isGenericParameter)
{
t = FindGenericArgument(((TypeReference)token).Name);
}
if (t != null)
{
if (t is ILType || isGenericParameter)
{
return t.GetHashCode();
}
else
return token.GetHashCode();
}
return 0;
}
bool CheckHasGenericParamter(object token)
{
if (token is TypeReference)
{
TypeReference _ref = ((TypeReference)token);
if (_ref.IsArray)
return CheckHasGenericParamter(((ArrayType)_ref).ElementType);
if (_ref.IsGenericParameter)
return true;
if (_ref.IsGenericInstance)
{
GenericInstanceType gi = (GenericInstanceType)_ref;
foreach(var i in gi.GenericArguments)
{
if (CheckHasGenericParamter(i))
return true;
}
return false;
}
else
return false;
}
else
return false;
}
void PrepareJumpTable(object token, Dictionary<Mono.Cecil.Cil.Instruction, int> addr)
{
int hashCode = token.GetHashCode();
if (jumptables == null)
jumptables = new Dictionary<int, int[]>();
if (jumptables.ContainsKey(hashCode))
return;
Mono.Cecil.Cil.Instruction[] e = token as Mono.Cecil.Cil.Instruction[];
int[] addrs = new int[e.Length];
for (int i = 0; i < e.Length; i++)
{
addrs[i] = addr[e[i]];
}
jumptables[hashCode] = addrs;
}
void InitParameters()
{
parameters = new List<IType>();
foreach (var i in def.Parameters)
{
IType type = null;
bool isByRef = false;
bool isArray = false;
int rank = 1;
TypeReference pt = i.ParameterType;
if (pt.IsByReference)
{
isByRef = true;
pt = ((ByReferenceType)pt).ElementType;
}
if (pt.IsArray)
{
isArray = true;
rank = ((ArrayType)pt).Rank;
pt = ((ArrayType)pt).ElementType;
}
if (pt.IsGenericParameter)
{
type = FindGenericArgument(pt.Name);
if (type == null && def.HasGenericParameters)
{
bool found = false;
foreach (var j in def.GenericParameters)
{
if (j.Name == pt.Name)
{
found = true;
break;
}
}
if (found)
{
type = new ILGenericParameterType(pt.Name);
}
else
throw new NotSupportedException("Cannot find Generic Parameter " + pt.Name + " in " + def.FullName);
}
}
else
type = appdomain.GetType(pt, declaringType, this);
if (isArray)
type = type.MakeArrayType(rank);
if (isByRef)
type = type.MakeByRefType();
parameters.Add(type);
}
}
public IMethod MakeGenericMethod(IType[] genericArguments)
{
KeyValuePair<string, IType>[] genericParameters = new KeyValuePair<string, IType>[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++)
{
string name = def.GenericParameters[i].Name;
IType val = genericArguments[i];
genericParameters[i] = new KeyValuePair<string, IType>(name, val);
}
ILMethod m = new ILMethod(def, declaringType, appdomain, jitFlags);
m.genericParameters = genericParameters;
m.genericArguments = genericArguments;
if (m.def.ReturnType.IsGenericParameter)
{
m.ReturnType = m.FindGenericArgument(m.def.ReturnType.Name);
}
return m;
}
string cachedName;
public override string ToString()
{
if (cachedName == null)
{
StringBuilder sb = new StringBuilder();
sb.Append(declaringType.FullName);
sb.Append('.');
sb.Append(Name);
sb.Append('(');
bool isFirst = true;
if (parameters == null)
InitParameters();
for (int i = 0; i < parameters.Count; i++)
{
if (isFirst)
isFirst = false;
else
sb.Append(", ");
sb.Append(parameters[i].FullName);
sb.Append(' ');
sb.Append(def.Parameters[i].Name);
}
sb.Append(')');
cachedName = sb.ToString();
}
return cachedName;
}
public override int GetHashCode()
{
if (hashCode == -1)
hashCode = System.Threading.Interlocked.Add(ref instance_id, 1);
return hashCode;
}
bool? isExtend;
public bool IsExtend
{
get
{
if (isExtend == null)
{
isExtend = this.IsExtendMethod();
}
return isExtend.Value;
}
}
}
}