HRESULT FilterManager::MarkSignature( PCCOR_SIGNATURE pbSig, // [IN] point to the current byte to visit in the signature ULONG cbSig, // [IN] count of bytes available. ULONG *pcbUsed) // [OUT] count of bytes consumed. { HRESULT hr = NOERROR; // A result. ULONG cArg = 0; // count of arguments in the signature ULONG cTypes = 0; // Count of argument types in the signature. ULONG cb; // Bytes used in a sig element. ULONG cbUsed = 0; // Total bytes consumed. ULONG callingconv = IMAGE_CEE_CS_CALLCONV_MAX; // calling convention VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &callingconv) ); if ((callingconv & IMAGE_CEE_CS_CALLCONV_MASK) >= IMAGE_CEE_CS_CALLCONV_MAX) IfFailGo(META_E_BAD_SIGNATURE); // Field signature is a single element. if (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_FIELD)) { // It is a FieldDef VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) ); } else { // If Generic call, get count of type parameters. //@TODO: where are the type params? if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC) { VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &cTypes) ); } // Count of arguments passed in call. VALIDATE_SIGNATURE_LEN( CorSigUncompressData(pbSig, &cArg) ); // Mark the return type, if there is one (LocalVarSig and GenericInst don't have return types). if ( !( isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) || isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_GENERICINST)) ) { // process the return type VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) ); } // Iterate over the arguments, and mark each one. while (cArg--) { VALIDATE_SIGNATURE_LEN_HR( MarkFieldSignature(pbSig, cbSig - cbUsed, &cb) ); } } ErrExit: *pcbUsed = cbUsed; return hr; } // HRESULT FilterManager::MarkSignature()
//***************************************************************************** // copy fixed part of VarArg signature to a buffer //***************************************************************************** HRESULT _GetFixedSigOfVarArg( // S_OK or error. PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature ULONG cbSigBlob, // [IN] size of signature CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature ULONG *pcbSigBlob) // [OUT] number of bytes written to the above output buffer { HRESULT hr = NOERROR; ULONG cbCalling; ULONG cbTyArgsNumber = 0; // number of bytes to store the type arg count (generics only) ULONG cbArgsNumber; // number of bytes to store the original arg count ULONG cbArgsNumberTemp; // number of bytes to store the fixed arg count ULONG cbTotal = 0; // total of number bytes for return type + all fixed arguments ULONG cbCur = 0; // index through the pvSigBlob ULONG cb; ULONG cArg; ULONG cTyArg; ULONG callingconv; ULONG cArgsIndex; CorElementType ulElementType; BYTE *pbSig; _ASSERTE (pvSigBlob && pcbSigBlob); // remember the number of bytes to represent the calling convention cbCalling = CorSigUncompressData (pvSigBlob, &callingconv); if (cbCalling == ((ULONG)(-1))) { return E_INVALIDARG; } _ASSERTE (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_VARARG)); cbCur += cbCalling; if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC) { cbTyArgsNumber = CorSigUncompressData(&pvSigBlob[cbCur], &cTyArg); if (cbTyArgsNumber == ((ULONG)(-1))) { return E_INVALIDARG; } cbCur += cbTyArgsNumber; } // remember number of bytes to represent the arg counts cbArgsNumber= CorSigUncompressData (&pvSigBlob[cbCur], &cArg); if (cbArgsNumber == ((ULONG)(-1))) { return E_INVALIDARG; } cbCur += cbArgsNumber; // how many bytes to represent the return type cb = cbSigBlob-cbCur; IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) ); cbCur += cb; cbTotal += cb; // loop through argument until we found ELEMENT_TYPE_SENTINEL or run // out of arguments for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) { _ASSERTE(cbCur < cbSigBlob); // peak the outer most ELEMENT_TYPE_* CorSigUncompressElementType (&pvSigBlob[cbCur], &ulElementType); if (ulElementType == ELEMENT_TYPE_SENTINEL) break; cb = cbSigBlob-cbCur; IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) ); cbTotal += cb; cbCur += cb; } cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &cArg); // now cbCalling : the number of bytes needed to store the calling convention // cbArgNumberTemp : number of bytes to store the fixed arg count // cbTotal : the number of bytes to store the ret and fixed arguments *pcbSigBlob = cbCalling + cbArgsNumberTemp + cbTotal; // resize the buffer IfFailGo( pqbSig->ReSizeNoThrow(*pcbSigBlob) ); pbSig = (BYTE *)pqbSig->Ptr(); // copy over the calling convention cb = CorSigCompressData(callingconv, pbSig); // copy over the fixed arg count cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &pbSig[cb]); // copy over the fixed args + ret type memcpy(&pbSig[cb + cbArgsNumberTemp], &pvSigBlob[cbCalling + cbArgsNumber], cbTotal); ErrExit: return hr; }
unsigned SizeOfField(PCCOR_SIGNATURE *ppSig, ULONG cSig, IMDInternalImport* pImport) { unsigned ret = 0xFFFFFFFF; if(ppSig && *ppSig && cSig && pImport) { unsigned callConv = CorSigUncompressData(*ppSig); if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) { mdToken tk; int typ; BOOL Reiterate; unsigned uElementNumber = 1; PCCOR_SIGNATURE pSigOrig = *ppSig; PCCOR_SIGNATURE pSigEnd = *ppSig+cSig; do { Reiterate = FALSE; switch(typ = *(*ppSig)++) { case ELEMENT_TYPE_VOID : return 0; case ELEMENT_TYPE_I1 : case ELEMENT_TYPE_U1 : case ELEMENT_TYPE_BOOLEAN : return uElementNumber; case ELEMENT_TYPE_CHAR : case ELEMENT_TYPE_I2 : case ELEMENT_TYPE_U2 : return (uElementNumber << 1); case ELEMENT_TYPE_I4 : case ELEMENT_TYPE_U4 : case ELEMENT_TYPE_R4 : return (uElementNumber << 2); case ELEMENT_TYPE_I8 : case ELEMENT_TYPE_U8 : case ELEMENT_TYPE_R8 : return (uElementNumber << 3); //case ELEMENT_TYPE_R : // return (uElementNumber * sizeof(float)); case ELEMENT_TYPE_OBJECT : case ELEMENT_TYPE_STRING : case ELEMENT_TYPE_FNPTR : case ELEMENT_TYPE_CLASS : case ELEMENT_TYPE_PTR : case ELEMENT_TYPE_BYREF : //case ELEMENT_TYPE_VAR : case ELEMENT_TYPE_U : case ELEMENT_TYPE_I : return (uElementNumber * sizeof(void*)); case ELEMENT_TYPE_TYPEDBYREF : // pair of ptrs return (uElementNumber * sizeof(void*)<<1); case ELEMENT_TYPE_VALUETYPE : *ppSig += CorSigUncompressToken(*ppSig, &tk); ret = SizeOfValueType(tk,pImport); if(ret != 0xFFFFFFFF) ret *= uElementNumber; return ret; // Modifiers or depedant types // uncomment when and if this type is supported by the Runtime //case ELEMENT_TYPE_VALUEARRAY : case ELEMENT_TYPE_ARRAY : ret = SizeOfField(ppSig, cSig-(unsigned)((*ppSig)-pSigOrig), pImport); if(ret != 0xFFFFFFFF) { unsigned rank = CorSigUncompressData(*ppSig); if (rank == 0) ret = 0xFFFFFFFF; else { int* lowerBounds = (int*) _alloca(sizeof(int)*2*rank); int* sizes = &lowerBounds[rank]; memset(lowerBounds, 0, sizeof(int)*2*rank); unsigned numSizes = CorSigUncompressData(*ppSig); _ASSERTE(numSizes <= rank); unsigned i; for(i =0; i < numSizes; i++) sizes[i] = CorSigUncompressData(*ppSig); unsigned numLowBounds = CorSigUncompressData(*ppSig); _ASSERTE(numLowBounds <= rank); for(i = 0; i < numLowBounds; i++) *ppSig+=CorSigUncompressSignedInt(*ppSig,&lowerBounds[i]); for(i = 0; i < numSizes; i++) { if (sizes[i]) uElementNumber *= sizes[i]; } ret *= uElementNumber; } } return ret; case ELEMENT_TYPE_CMOD_OPT : case ELEMENT_TYPE_CMOD_REQD : *ppSig += CorSigUncompressToken(*ppSig, &tk); case ELEMENT_TYPE_PINNED : case ELEMENT_TYPE_SZARRAY : // uElementNumber doesn't change if(*ppSig < pSigEnd) Reiterate = TRUE; break; default: case ELEMENT_TYPE_SENTINEL : case ELEMENT_TYPE_END : break; } // end switch } while(Reiterate); } // end if(CALLCONV_FIELD) } // end if(signature && import) return ret; }
//+---------------------------------------------------------------------------- // // Function: CallDescrWithObjectArray, private // // Synopsis: Builds the stack from a object array and call the object // // Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are // all already protected!! //+---------------------------------------------------------------------------- void CallDescrWithObjectArray(OBJECTREF& pServer, ReflectMethod *pRM, const BYTE *pTarget, MetaSig* sig, VASigCookie *pCookie, BOOL fIsStatic, PTRARRAYREF& pArgArray, OBJECTREF *pVarRet, PTRARRAYREF *ppVarOutParams) { THROWSCOMPLUSEXCEPTION(); TRIGGERSGC(); // the debugger, profiler code triggers a GC LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray IN\n")); ByRefInfo *pByRefs = NULL; INT64 retval = 0; UINT nActualStackBytes = 0; LPBYTE pAlloc = 0; LPBYTE pFrameBase = 0; UINT32 numByRef = 0; DWORD attr = pRM->dwFlags; #ifdef _DEBUG MethodDesc *pMD = pRM->pMethod; #endif // check the calling convention BYTE callingconvention = sig->GetCallingConvention(); if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT)) { _ASSERTE(!"This calling convention is not supported."); COMPlusThrow(kInvalidProgramException); } #ifdef DEBUGGING_SUPPORTED // debugger goo What does this do? can someone put a comment here? if (CORDebuggerTraceCall()) g_pDebugInterface->TraceCall(pTarget); #endif // DEBUGGING_SUPPORTED #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationStarted( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED // Create a fake FramedMethodFrame on the stack. nActualStackBytes = sig->SizeOfActualFixedArgStack(fIsStatic); pAlloc = (LPBYTE)_alloca(FramedMethodFrame::GetNegSpaceSize() + sizeof(FramedMethodFrame) + nActualStackBytes); pFrameBase = pAlloc + FramedMethodFrame::GetNegSpaceSize(); // cycle through the parameters and see if there are byrefs BYTE typ = 0; BOOL fHasByRefs = FALSE; if (attr & RM_ATTR_BYREF_FLAG_SET) fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG; else { sig->Reset(); while ((typ = sig->NextArg()) != ELEMENT_TYPE_END) { if (typ == ELEMENT_TYPE_BYREF) { fHasByRefs = TRUE; attr |= RM_ATTR_HAS_BYREF_ARG; break; } } attr |= RM_ATTR_BYREF_FLAG_SET; pRM->dwFlags = attr; sig->Reset(); } int nFixedArgs = sig->NumFixedArgs(); // if there are byrefs allocate and array for the out parameters if (fHasByRefs) { *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass)); // Null out the array memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs()); } ArgIterator argit(pFrameBase, sig, fIsStatic); // set the this pointer OBJECTREF *ppThis = (OBJECTREF*)argit.GetThisAddr(); *ppThis = NULL; // if there is a return buffer, allocate it if (sig->HasRetBuffArg()) { EEClass *pEECValue = sig->GetRetEEClass(); _ASSERTE(pEECValue->IsValueClass()); MethodTable * mt = pEECValue->GetMethodTable(); *pVarRet = AllocateObject(mt); *(argit.GetRetBuffArgAddr()) = (*pVarRet)->UnBox(); #if defined(_PPC_) || defined(_SPARC_) // retbuf // the CallDescrWorker callsite for methods with return buffer is // different for RISC CPUs - we pass this information along by setting // the lowest bit in pTarget pTarget = (const BYTE *)((UINT_PTR)pTarget | 0x1); #endif } // gather data about the parameters by iterating over the sig: UINT32 arg = 0; UINT32 structSize = 0; int ofs = 0; // REVIEW: need to use actual arg count if VarArgs are supported ArgInfo* pArgInfo = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo)); #ifdef _DEBUG // We expect to write useful data over every part of this so need // not do this in retail! memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif for( ; 0 != (ofs = argit.GetNextOffset(&typ, &structSize)); arg++, pArgInfo++ ) { if (typ == ELEMENT_TYPE_BYREF) { EEClass *pClass = NULL; CorElementType brType = sig->GetByRefType(&pClass); if (CorIsPrimitiveType(brType)) { pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize; } else if (pClass->IsValueClass()) { pArgInfo->dataSize = pClass->GetAlignedNumInstanceFieldBytes(); numByRef ++; } else { pArgInfo->dataSize = sizeof(Object *); numByRef ++; } ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize); brInfo->argIndex = arg; brInfo->typ = brType; brInfo->pClass = pClass; brInfo->pNext = pByRefs; pByRefs = brInfo; pArgInfo->dataLocation = (BYTE*)brInfo->data; *((void**)(pFrameBase + ofs)) = (void*)pArgInfo->dataLocation; pArgInfo->dataClass = pClass; pArgInfo->dataType = brType; pArgInfo->byref = TRUE; } else { pArgInfo->dataLocation = pFrameBase + ofs; pArgInfo->dataSize = StackElemSize(structSize); pArgInfo->dataClass = sig->GetTypeHandle().GetClass(); // this may cause GC! pArgInfo->dataType = typ; pArgInfo->byref = FALSE; } } if (!fIsStatic) { // If this isn't a value class, verify the objectref #ifdef _DEBUG if (pMD->GetClass()->IsValueClass() == FALSE) { VALIDATEOBJECTREF(pServer); } #endif //_DEBUG *ppThis = pServer; } // There should be no GC when we fill up the stack with parameters, as we don't protect them // Assignment of "*ppThis" above triggers the point where we become unprotected. BEGINFORBIDGC(); // reset pArgInfo to point to the start of the block we _alloca-ed pArgInfo = pArgInfo-nFixedArgs; PBYTE dataLocation; INT32 dataSize; EEClass *dataClass; BYTE dataType; OBJECTREF* pArguments = pArgArray->m_Array; UINT32 i, j = arg; for (i=0; i<j; i++) { dataSize = pArgInfo->dataSize; dataLocation = pArgInfo->dataLocation; dataClass = pArgInfo->dataClass; dataType = pArgInfo->dataType; switch (dataSize) { case 1: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData()); break; case 2: // This "if" statement is necessary to make the assignement big-endian aware if (pArgInfo->byref) *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData()); else *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData()); break; case 4: if ((dataType == ELEMENT_TYPE_STRING) || (dataType == ELEMENT_TYPE_OBJECT) || (dataType == ELEMENT_TYPE_CLASS) || (dataType == ELEMENT_TYPE_SZARRAY) || (dataType == ELEMENT_TYPE_ARRAY)) { *(OBJECTREF *)dataLocation = pArguments[i]; } else { *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData()); } break; case 8: *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData()); break; default: { memcpy(dataLocation, pArguments[i]->UnBox(), dataSize); } } pArgInfo++; } #ifdef _DEBUG // Should not be using this any more pArgInfo = pArgInfo - nFixedArgs; memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs); #endif // if there were byrefs, push a protection frame ProtectByRefsFrame *pProtectionFrame = NULL; if (pByRefs && numByRef > 0) { char *pBuffer = (char*)_alloca (sizeof (ProtectByRefsFrame)); pProtectionFrame = new (pBuffer) ProtectByRefsFrame(GetThread(), pByRefs); } // call the correct worker function depending of if the method // is varargs or not ENDFORBIDGC(); #ifdef _PPC_ FramedMethodFrame::Enregister(pFrameBase, sig, fIsStatic, nActualStackBytes); #endif INSTALL_COMPLUS_EXCEPTION_HANDLER(); retval = CallDescrWorker( pFrameBase + sizeof(FramedMethodFrame) + nActualStackBytes, nActualStackBytes / STACK_ELEM_SIZE, #if defined(_X86_) || defined(_PPC_) // argregs (ArgumentRegisters*)(pFrameBase + FramedMethodFrame::GetOffsetOfArgumentRegisters()), #endif (LPVOID)pTarget); UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); // set floating point return values getFPReturn(sig->GetFPReturnSize(), &retval); // need to build a object based on the return type. if (!sig->HasRetBuffArg()) { BYTE *pRetVal = (BYTE*)&retval; #ifdef BIGENDIAN switch (sig->GetReturnTypeSize()) { case 1: pRetVal += sizeof(void*)-1; break; case 2: pRetVal += sizeof(void*)-2; break; default: // nothing to do break; } #endif GetObjectFromStack(pVarRet, pRetVal, sig->GetReturnType(), sig->GetRetEEClass()); } // extract the out args from the byrefs if (pByRefs) { do { // Always extract the data ptr every time we enter this loop because // calls to GetObjectFromStack below can cause a GC. // Even this is not enough, because that we are passing a pointer to GC heap // to GetObjectFromStack . If GC happens, nobody is protecting the passed in pointer. OBJECTREF pTmp = NULL; GetObjectFromStack(&pTmp, pByRefs->data, pByRefs->typ, pByRefs->pClass); (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp); pByRefs = pByRefs->pNext; } while (pByRefs); if (pProtectionFrame) pProtectionFrame->Pop(); } #ifdef PROFILING_SUPPORTED // If we're profiling, notify the profiler that we're about to invoke the remoting target if (CORProfilerTrackRemoting()) g_profControlBlock.pProfInterface->RemotingServerInvocationReturned( reinterpret_cast<ThreadID>(GetThread())); #endif // PROFILING_SUPPORTED LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n")); }