// Produce code for a GT_CALL node void CodeGen::genCallInstruction(GenTreePtr node) { // 省略部分代码...... if (callType == CT_HELPER) { // 把句柄转换为帮助函数的句柄,默认是CORINFO_HELP_NEWFAST helperNum = compiler->eeGetHelperNum(methHnd); // 获取指向帮助函数的指针 // 这里等于调用compiler->compGetHelperFtn(CORINFO_HELP_NEWFAST, ...) addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr); } else { // 调用普通函数 // Direct call to a non-virtual user function. addr = call->gtDirectCallAddress; } }
我们来看下compGetHelperFtn究竟把CORINFO_HELP_NEWFAST转换到了什么函数
compGetHelperFtn的定义
源代码:
void* Compiler::compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void** ppIndirection) /* OUT */ { // 省略部分代码...... addr = info.compCompHnd->getHelperFtn(ftnNum, ppIndirection); return addr; }
getHelperFtn的定义
这里我们可以看到获取了hlpDynamicFuncTable这个函数表中的函数
源代码:
void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection) /* OUT */ { // 省略部分代码...... pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper; // 省略部分代码...... result = (LPVOID)GetEEFuncEntryPoint(pfnHelper); return result; }
hlpDynamicFuncTable函数表使用了jithelpers.h中的定义,其中CORINFO_HELP_NEWFAST对应的函数如下
源代码:
JITHELPER(CORINFO_HELP_NEWFAST, JIT_New, CORINFO_HELP_SIG_REG_ONLY)
可以看到对应了JIT_New,这个就是JIT生成的代码调用分配内存的函数了,JIT_New的定义如下
需要注意的是函数表中的JIT_New在满足一定条件时会被替换为更快的实现,但作用和JIT_New是一样的,这一块将在后面提及
源代码:
HCIMPL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_) { // 省略部分代码...... MethodTable *pMT = typeHnd.AsMethodTable(); newobj = AllocateObject(pMT); // 省略部分代码...... return(OBJECTREFToObject(newobj)); } HCIMPLEND
总结:
JIT从CEE_NEWOBJ生成了两段代码,一段是调用JIT_New函数分配内存的代码,一段是调用构造函数的代码
我们来看一下CEE_NEWARR指令是怎样处理的,因为前面已经花了很大篇幅介绍对CEE_NEWOBJ的处理,这里仅列出不同的部分
源代码:
Compiler::impImportBlockCode(BasicBlock* block) { CEE_NEWARR: // 省略部分代码...... args = gtNewArgList(op1, op2); op1 = gtNewHelperCallNode(info.compCompHnd->getNewArrHelper(resolvedToken.hClass), TYP_REF, 0, args); }
我们可以看到CEE_NEWARR直接生成了GT_CALL节点,不像CEE_NEWOBJ需要进一步的转换
getNewArrHelper返回了调用的帮助函数,我们来看一下getNewArrHelper
源代码:
CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd) { // 省略部分代码...... TypeHandle arrayType(arrayClsHnd); result = getNewArrHelperStatic(arrayType); // 省略部分代码...... return result; }
再看getNewArrHelperStatic,我们可以看到一般情况下会返回CORINFO_HELP_NEWARR_1_OBJ
源代码:
CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd) { // 省略部分代码...... if (CorTypeInfo::IsGenericVariable(elemType)) { result = CORINFO_HELP_NEWARR_1_OBJ; } else if (CorTypeInfo::IsObjRef(elemType)) { // It is an array of object refs result = CORINFO_HELP_NEWARR_1_OBJ; } else { // These cases always must use the slow helper // 省略部分代码...... } return result; {
CORINFO_HELP_NEWARR_1_OBJ对应的函数如下
源代码:
DYNAMICJITHELPER(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1,CORINFO_HELP_SIG_REG_ONLY)
可以看到对应了JIT_NewArr1这个包装给JIT调用的帮助函数
和JIT_New一样,在满足一定条件时会被替换为更快的实现
源代码:
HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size) { // 省略部分代码...... CorElementType elemType = pArrayClassRef->GetArrayElementTypeHandle().GetSignatureCorElementType(); if (CorTypeInfo::IsPrimitiveType(elemType) { // 省略部分代码...... // 如果类型是基元类型(int, double等)则使用更快的FastAllocatePrimitiveArray函数 newArray = FastAllocatePrimitiveArray(pArrayClassRef->GetMethodTable(), static_cast<DWORD>(size), bAllocateInLargeHeap); } else { // 省略部分代码...... // 默认使用AllocateArrayEx函数 INT32 size32 = (INT32)size; newArray = AllocateArrayEx(typeHnd, &size32, 1); } // 省略部分代码...... return(OBJECTREFToObject(newArray)); } HCIMPLEND
总结:
JIT从CEE_NEWARR只生成了一段代码,就是调用JIT_NewArr1函数的代码