如何找到extern bool InternalEquals的实现代码
之前看Allen lee的《如何找到public extern bool Equals(String value)的实现代码》,现在sscli2.0中comstring里已经没有Equals了
在微软提供的Rotor源代码中,Object.InternalEquals的代码只有下面两行:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internalstaticexternbool InternalEquals(Object objA, Object objB);
internalstaticexternbool InternalEquals(Object objA, Object objB);
在哪里可以找到该方法的实现代码呢?
打开Rotor源代码的sscli20/clr/src/vm/ecall.cpp文件,搜索“InternalEquals”关键字,你将找到如下所示的相关的一些宏:
FCFuncStart(gObjectFuncs)
//......省略若干
FCFuncElement("InternalEquals", ObjectNative::Equals)
//......省略若干
FCFuncEnd()
//......省略若干
FCFuncElement("InternalEquals", ObjectNative::Equals)
//......省略若干
FCFuncEnd()
他们的相关定义为:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#define FCFuncFlags(intrinsicID, dynamicID) \
(BYTE*)( (((BYTE)intrinsicID) <<16) + (((BYTE)dynamicID) <<24) )
#define FCFuncElement(name, impl) FCFuncFlags(CORINFO_INTRINSIC_Illegal, ECall::InvalidDynamicFCallId), \
GetEEFuncEntryPoint(impl), NULL, NULL, (LPVOID)name,
#define FCFuncStart(name) static LPVOID name[] = {
#define FCFuncEnd() FCFuncFlag_EndOfArray + FCFuncFlags(CORINFO_INTRINSIC_Illegal, ECall::InvalidDynamicFCallId) };
(BYTE*)( (((BYTE)intrinsicID) <<16) + (((BYTE)dynamicID) <<24) )
#define FCFuncElement(name, impl) FCFuncFlags(CORINFO_INTRINSIC_Illegal, ECall::InvalidDynamicFCallId), \
GetEEFuncEntryPoint(impl), NULL, NULL, (LPVOID)name,
#define FCFuncStart(name) static LPVOID name[] = {
#define FCFuncEnd() FCFuncFlag_EndOfArray + FCFuncFlags(CORINFO_INTRINSIC_Illegal, ECall::InvalidDynamicFCallId) };
其中ObjectNative::Equals是实现的函数,查找FCFuncStart、FCFuncElement、FCFuncEnd宏展开来就是:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
static LPVOID gObjectFuncs[] =
{
//......省略若干
FCFuncFlags( CORINFO_INTRINSIC_Illegal,ECall::InvalidDynamicFCallId),
GetEEFuncEntryPoint(ObjectNative::Equals),
NULL,
NULL,
(LPVOID)InternalEquals,
//......省略若干
FCFuncFlag_EndOfArray + FCFuncFlags(CORINFO_INTRINSIC_Illegal,ECall::InvalidDynamicFCallId)
};
{
//......省略若干
FCFuncFlags( CORINFO_INTRINSIC_Illegal,ECall::InvalidDynamicFCallId),
GetEEFuncEntryPoint(ObjectNative::Equals),
NULL,
NULL,
(LPVOID)InternalEquals,
//......省略若干
FCFuncFlag_EndOfArray + FCFuncFlags(CORINFO_INTRINSIC_Illegal,ECall::InvalidDynamicFCallId)
};
其中 FCFuncFlags又是一个宏,完全展开后的原型:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
static LPVOID gObjectFuncs[] =
{
//......省略若干
(BYTE*)( (((BYTE)CORINFO_INTRINSIC_Illegal) <<16) + (((BYTE)ECall::InvalidDynamicFCallId) <<24) ),
GetEEFuncEntryPoint(ObjectNative::Equals),
NULL,
NULL,
(LPVOID)InternalEquals,
//......省略若干
FCFuncFlag_EndOfArray + (BYTE*)( (((BYTE)CORINFO_INTRINSIC_Illegal) <<16) + (((BYTE)ECall::InvalidDynamicFCallId) <<24) )
};
{
//......省略若干
(BYTE*)( (((BYTE)CORINFO_INTRINSIC_Illegal) <<16) + (((BYTE)ECall::InvalidDynamicFCallId) <<24) ),
GetEEFuncEntryPoint(ObjectNative::Equals),
NULL,
NULL,
(LPVOID)InternalEquals,
//......省略若干
FCFuncFlag_EndOfArray + (BYTE*)( (((BYTE)CORINFO_INTRINSIC_Illegal) <<16) + (((BYTE)ECall::InvalidDynamicFCallId) <<24) )
};
一堆宏看得人眼花缭乱,但是不必要理会,我们只要找寻 ObjectNative::Equals,原先String的extern Equals
实现在comstring.cpp里,但是因为版本不同,现在comstring已经没有Equals了,而Object.InternalEquals由ObjectNative来处理
打开Rotor源代码的sscli20/clr/src/vm/comobject.cpp文件,搜索“ObjectNative::Equals”关键字找到了如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
FCIMPL2(FC_BOOL_RET, ObjectNative::Equals, Object *pThisRef, Object *pCompareRef)
{
CONTRACTL
{
THROWS;
DISABLED(GC_NOTRIGGER);
INJECT_FAULT(FCThrow(kOutOfMemoryException););
MODE_COOPERATIVE;
SO_TOLERANT;
}
CONTRACTL_END;
if (pThisRef == pCompareRef)
FC_RETURN_BOOL(TRUE);
// Since we are in FCALL, we must handle NULL specially.
if (pThisRef == NULL || pCompareRef == NULL)
FC_RETURN_BOOL(FALSE);
MethodTable *pThisMT = pThisRef->GetMethodTable();
// If it's not a value class, don't compare by value
if (!pThisMT->IsValueClass())
FC_RETURN_BOOL(FALSE);
// Make sure they are the same type.
if (pThisMT != pCompareRef->GetMethodTable())
FC_RETURN_BOOL(FALSE);
// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
(void*) (pThisRef+1),
(void*) (pCompareRef+1),
pThisRef->GetMethodTable()->GetBaseSize() -sizeof(Object) -sizeof(int)) ==0;
FC_GC_POLL_RET();
FC_RETURN_BOOL(ret);
}
FCIMPLEND
{
CONTRACTL
{
THROWS;
DISABLED(GC_NOTRIGGER);
INJECT_FAULT(FCThrow(kOutOfMemoryException););
MODE_COOPERATIVE;
SO_TOLERANT;
}
CONTRACTL_END;
if (pThisRef == pCompareRef)
FC_RETURN_BOOL(TRUE);
// Since we are in FCALL, we must handle NULL specially.
if (pThisRef == NULL || pCompareRef == NULL)
FC_RETURN_BOOL(FALSE);
MethodTable *pThisMT = pThisRef->GetMethodTable();
// If it's not a value class, don't compare by value
if (!pThisMT->IsValueClass())
FC_RETURN_BOOL(FALSE);
// Make sure they are the same type.
if (pThisMT != pCompareRef->GetMethodTable())
FC_RETURN_BOOL(FALSE);
// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
(void*) (pThisRef+1),
(void*) (pCompareRef+1),
pThisRef->GetMethodTable()->GetBaseSize() -sizeof(Object) -sizeof(int)) ==0;
FC_GC_POLL_RET();
FC_RETURN_BOOL(ret);
}
FCIMPLEND
其中FCIMPL2和FCIMPLEND是一组成对出现的宏:
#define FCIMPL2(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1) { FCIMPL_PROLOG(funcname)
#define FCIMPLEND FCIMPL_EPILOG(); }
#define FCIMPLEND FCIMPL_EPILOG(); }
展开后以上一段代码的开头和结尾成了:
FC_BOOL_RET F_CALL_CONV ObjectNative::Equals(int/* EAX */, Object *pThisRef, Object *pCompareRef)
{
FCIMPL_PROLOG(ObjectNative::Equals)
//......省略若干
FCIMPL_EPILOG();
}
{
FCIMPL_PROLOG(ObjectNative::Equals)
//......省略若干
FCIMPL_EPILOG();
}
其中夹杂的几个宏我们不必理会,关键的代码是:
BOOL ret = memcmp((void*)(pThisRef+1), (void*)(pCompareRef+1), pThisRef->GetMethodTable()->GetBaseSize() -sizeof(Object) -sizeof(int)) ==0;
这里调用了C标准库的memcmp函数比较两个Object*对象是否相等。