Example #1
0
/*=============================GetArrayMethodToken==============================
**Action:
**Returns:
**Arguments: REFLECTMODULEBASEREF refThis
**           U1ARRAYREF     sig
**           STRINGREF      methodName
**           int            tkTypeSpec
**Exceptions:
==============================================================================*/
INT32 QCALLTYPE COMModule::GetArrayMethodToken(QCall::ModuleHandle pModule,
                                               INT32 tkTypeSpec,
                                               LPCWSTR wszMethodName,
                                               LPCBYTE pSignature,
                                               INT32 sigLength)
{
    QCALL_CONTRACT;

    mdMemberRef memberRefE = mdTokenNil; 

    BEGIN_QCALL;

    if (!wszMethodName)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
    if (!tkTypeSpec) 
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_Type"));
    
    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); 
    _ASSERTE(pRCW); 

    HRESULT hr = pRCW->GetEmitter()->DefineMemberRef(tkTypeSpec, wszMethodName, (PCCOR_SIGNATURE)pSignature, sigLength, &memberRefE); 
    if (FAILED(hr)) 
    {
        _ASSERTE(!"Failed on DefineMemberRef");
        COMPlusThrowHR(hr);
    }

    END_QCALL;

    return (INT32)memberRefE;
}
Example #2
0
FCIMPL1(Object*, AssemblyNameNative::GetFileInformation, StringObject* filenameUNSAFE)
{
    FCALL_CONTRACT;

    struct _gc
    {
        ASSEMBLYNAMEREF result;
        STRINGREF       filename;
    } gc;

    gc.result   = NULL;
    gc.filename = (STRINGREF) filenameUNSAFE;

    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    if (gc.filename == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));

    if (gc.filename->GetStringLength() == 0)
        COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));

    gc.result = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));


    ///////////////////////////////////////////////
    SString sFileName(gc.filename->GetBuffer());
    PEImageHolder pImage = PEImage::OpenImage(sFileName, MDInternalImport_NoCache);

    EX_TRY
    {
#ifdef FEATURE_CORECLR
        // Allow AssemblyLoadContext.GetAssemblyName for native images on CoreCLR
        if (pImage->HasNTHeaders() && pImage->HasCorHeader() && pImage->HasNativeHeader())
            pImage->VerifyIsNIAssembly();
        else
            pImage->VerifyIsAssembly();
#else
        pImage->VerifyIsAssembly();
#endif
    }
    EX_CATCH
    {
        Exception *ex = GET_EXCEPTION();
        EEFileLoadException::Throw(sFileName,ex->GetHR(),ex);
    }
    EX_END_CATCH_UNREACHABLE;

    SString sUrl = sFileName;
    PEAssembly::PathToUrl(sUrl);

    AssemblySpec spec;
    spec.InitializeSpec(TokenFromRid(mdtAssembly,1),pImage->GetMDImport(),NULL,TRUE);
    spec.SetCodeBase(sUrl);
    spec.AssemblyNameInit(&gc.result, pImage);
    
    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(gc.result);
}
Example #3
0
FCIMPLEND

/// "parse" tells us to parse the simple name of the assembly as if it was the full name
/// almost never the right thing to do, but needed for compat
/* static */
FCIMPL3(FC_BOOL_RET, AssemblyNameNative::ReferenceMatchesDefinition, AssemblyNameBaseObject* refUNSAFE, AssemblyNameBaseObject* defUNSAFE, CLR_BOOL fParse)
{
    FCALL_CONTRACT;

    struct _gc
    {
        ASSEMBLYNAMEREF pRef;
        ASSEMBLYNAMEREF pDef;
    } gc;
    gc.pRef = (ASSEMBLYNAMEREF)ObjectToOBJECTREF (refUNSAFE);
    gc.pDef = (ASSEMBLYNAMEREF)ObjectToOBJECTREF (defUNSAFE);

    BOOL result = FALSE;
    HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);

    Thread *pThread = GetThread();

    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    if (gc.pRef == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName"));
    if (gc.pDef == NULL)
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName"));

    AssemblySpec refSpec;
    refSpec.InitializeSpec(&(pThread->m_MarshalAlloc), (ASSEMBLYNAMEREF*) &gc.pRef, fParse, FALSE);

    AssemblySpec defSpec;
    defSpec.InitializeSpec(&(pThread->m_MarshalAlloc), (ASSEMBLYNAMEREF*) &gc.pDef, fParse, FALSE);

#ifdef FEATURE_FUSION
    SafeComHolder<IAssemblyName> pRefName (NULL);
    IfFailThrow(refSpec.CreateFusionName(&pRefName, FALSE));

    SafeComHolder <IAssemblyName> pDefName (NULL);
    IfFailThrow(defSpec.CreateFusionName(&pDefName, FALSE));

    // Order matters: Ref->IsEqual(Def)
    result = (S_OK == pRefName->IsEqual(pDefName, ASM_CMPF_IL_ALL));
#else
    result=AssemblySpec::RefMatchesDef(&refSpec,&defSpec);
#endif
    HELPER_METHOD_FRAME_END();
    FC_RETURN_BOOL(result);
}
Example #4
0
FCIMPLEND

FCIMPL1(Object*, AssemblyNameNative::ToString, Object* refThisUNSAFE)
{
    FCALL_CONTRACT;

    OBJECTREF pObj          = NULL;
    ASSEMBLYNAMEREF pThis   = (ASSEMBLYNAMEREF) (OBJECTREF) refThisUNSAFE;
    HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);

    if (pThis == NULL)
        COMPlusThrow(kNullReferenceException, W("NullReference_This"));

    Thread *pThread = GetThread();

    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    AssemblySpec spec;
    spec.InitializeSpec(&(pThread->m_MarshalAlloc), (ASSEMBLYNAMEREF*) &pThis, FALSE, FALSE); 

    StackSString name;
#ifndef FEATURE_FUSION
    spec.GetFileOrDisplayName(ASM_DISPLAYF_VERSION |
                              ASM_DISPLAYF_CULTURE |
                              ASM_DISPLAYF_PUBLIC_KEY_TOKEN,
                              name);
#else
    spec.GetFileOrDisplayName(0, name);
#endif // FEATURE_FUSION

    pObj = (OBJECTREF) StringObject::NewString(name);

    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(pObj);
}
Example #5
0
TypeHandle Binder::LookupType(BinderTypeID id, BOOL fLoad)
{
    _ASSERTE(m_pModule != NULL);
    _ASSERTE(id != TYPE__NIL);
    _ASSERTE(id <= m_cTypeHandles);

    THROWSCOMPLUSEXCEPTION();

    TypeHandle th;

    const TypeDescription *d = m_typeDescriptions + id - 1;

    OBJECTREF pThrowable = NULL;
    GCPROTECT_BEGIN(pThrowable);

    NameHandle nh(d->type, TypeHandle(GetClass(d->classID)), d->rank);
    if (!fLoad)
        nh.SetTokenNotToLoad(tdAllTypes);
    th = m_pModule->GetClassLoader()->FindTypeHandle(&nh, &pThrowable);

    GCPROTECT_END();

    if (th.IsNull())
    {
        if (fLoad)
            COMPlusThrow(pThrowable);
        return TypeHandle();
    }

    m_pTypeHandles[id-1] = th;

    return th;
}
Example #6
0
INT32 QCALLTYPE COMDynamicWrite::DefineType(QCall::ModuleHandle pModule,
                                            LPCWSTR wszFullName, 
                                            INT32 tkParent,                               
                                            INT32 attributes,
                                            INT32 tkEnclosingType,
                                            INT32 * pInterfaceTokens)
{
    QCALL_CONTRACT;

    mdTypeDef           classE = mdTokenNil; 

    BEGIN_QCALL;

    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
    _ASSERTE(pRCW);

    HRESULT hr;

    if (RidFromToken(tkEnclosingType))
    {
        // defining nested type
        hr = pRCW->GetEmitter()->DefineNestedType(wszFullName, 
                                                  attributes, 
                                                  tkParent == 0 ? mdTypeRefNil : tkParent,
                                                  (mdToken *)pInterfaceTokens,
                                                  tkEnclosingType,
                                                  &classE);
    }
    else
    {
        // top level type
        hr = pRCW->GetEmitter()->DefineTypeDef(wszFullName,
                                               attributes,
                                               tkParent == 0 ? mdTypeRefNil : tkParent,
                                               (mdToken *)pInterfaceTokens,
                                               &classE);
    }

    if (hr == META_S_DUPLICATE) 
    {
        COMPlusThrow(kArgumentException, W("Argument_DuplicateTypeName"));
    } 

    if (FAILED(hr)) {
        _ASSERTE(hr == E_OUTOFMEMORY || !"DefineTypeDef Failed");
        COMPlusThrowHR(hr);    
    }

    AllocMemTracker amTracker;
    pModule->GetClassLoader()->AddAvailableClassDontHaveLock(pModule,
                                                    classE,
                                                    &amTracker);
    amTracker.SuppressRelease();

    END_QCALL;

    return (INT32)classE;
}
Example #7
0
void Binder::InitClass(MethodTable *pMT)
{
    THROWSCOMPLUSEXCEPTION();

    OBJECTREF throwable = NULL;
    GCPROTECT_BEGIN(throwable);

    if (!pMT->CheckRunClassInit(&throwable))
        COMPlusThrow(throwable);

    GCPROTECT_END();
}
Example #8
0
OBJECTREF ComCallWrapper::GetObjectRefFromComIP(IUnknown* pUnk)
{
    ComCallWrapper *pWrapper;

    THROWSCOMPLUSEXCEPTION();
    _ASSERTE(pUnk != NULL);
    
    // check whether the IUnknown* is comming from our wrapper
    if (*(PVOID*)pUnk != GetComCallWrapperVPtr())
        COMPlusThrow(kInvalidCastException);

    pWrapper = GetWrapperFromIP(pUnk);      
    return ObjectFromHandle(pWrapper->m_hThis);
}
Example #9
0
MethodTable *Binder::LookupClass(BinderClassID id, BOOL fLoad)
{
    _ASSERTE(m_pModule != NULL);
    _ASSERTE(id != CLASS__NIL);
    _ASSERTE(id <= m_cClassRIDs);

    MethodTable *pMT;

    const ClassDescription *d = m_classDescriptions + id - 1;

    NameHandle nh(d->name);

    if (!fLoad)
    {
        nh.SetTokenNotToLoad(tdAllTypes);
        pMT = m_pModule->GetClassLoader()->FindTypeHandle(&nh).AsMethodTable();
        if (pMT == NULL)
            return NULL;
    }
    else
    {
        THROWSCOMPLUSEXCEPTION();

        BEGIN_ENSURE_COOPERATIVE_GC();
        OBJECTREF pThrowable = NULL;
        GCPROTECT_BEGIN(pThrowable);

        pMT = m_pModule->GetClassLoader()->FindTypeHandle(&nh, &pThrowable).AsMethodTable();
        if (pMT == NULL)
        {
            _ASSERTE(!"EE expects class to exist");
            COMPlusThrow(pThrowable);
        }
        GCPROTECT_END();
        END_ENSURE_COOPERATIVE_GC();
    }

    _ASSERTE(pMT->GetModule() == m_pModule);

    mdTypeDef td = pMT->GetClass()->GetCl();

    _ASSERTE(!IsNilToken(td));

    _ASSERTE(RidFromToken(td) <= USHRT_MAX);
    m_pClassRIDs[id-1] = (USHORT) RidFromToken(td);

    m_pModule->StoreTypeDef(td, pMT);

    return pMT;
}
Example #10
0
FCIMPLEND

//**************************************************
// LoadInMemoryTypeByName
// Explicitly loading an in memory type
// <TODO>@todo: this function is not dealing with nested type correctly yet.
// We will need to parse the full name by finding "+" for enclosing type, etc.</TODO>
//**************************************************
void QCALLTYPE COMModule::LoadInMemoryTypeByName(QCall::ModuleHandle pModule, LPCWSTR wszFullName)
{
    QCALL_CONTRACT;
    
    TypeHandle      typeHnd;

    BEGIN_QCALL;

    if (!pModule->IsReflection())  
        COMPlusThrow(kNotSupportedException, W("NotSupported_NonReflectedType"));   

    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
    _ASSERTE(pRCW);

    // it is ok to use public import API because this is a dynamic module anyway. We are also receiving Unicode full name as
    // parameter.
    IMetaDataImport * pImport = pRCW->GetRWImporter();

    if (wszFullName == NULL)
        IfFailThrow( E_FAIL );

    // look up the handle
    mdTypeDef  td;
    HRESULT hr = pImport->FindTypeDefByName(wszFullName, mdTokenNil, &td);
    if (FAILED(hr))
    {
        if (hr != CLDB_E_RECORD_NOTFOUND)
            COMPlusThrowHR(hr);

        // Get the UTF8 version of strFullName
        MAKE_UTF8PTR_FROMWIDE(szFullName, wszFullName);
        pModule->GetAssembly()->ThrowTypeLoadException(szFullName, IDS_CLASSLOAD_GENERAL);
    }

    TypeKey typeKey(pModule, td);
    typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, TypeHandle());

    END_QCALL;

    return;
}
Example #11
0
/*============================SetConstantValue============================
**Action: Helper to set constant value to field or parameter
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
void QCALLTYPE COMDynamicWrite::SetConstantValue(QCall::ModuleHandle pModule, UINT32 tk, DWORD valueCorType, LPVOID pValue)
{
    QCALL_CONTRACT;

    BEGIN_QCALL;

    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); 
    _ASSERTE(pRCW);

    HRESULT hr;

    if (TypeFromToken(tk) == mdtFieldDef)
    {
        hr = pRCW->GetEmitter()->SetFieldProps( 
            tk,                         // [IN] The FieldDef.
            ULONG_MAX,                  // [IN] Field attributes.
            valueCorType,               // [IN] Flag for the value type, selected ELEMENT_TYPE_*
            pValue,                     // [IN] Constant value.
            (ULONG) -1);                // [IN] Optional length.
    }
    else if (TypeFromToken(tk) == mdtProperty)
    {
        hr = pRCW->GetEmitter()->SetPropertyProps( 
            tk,                         // [IN] The PropertyDef.
            ULONG_MAX,                  // [IN] Property attributes.
            valueCorType,               // [IN] Flag for the value type, selected ELEMENT_TYPE_*
            pValue,                     // [IN] Constant value.
            (ULONG) -1,                 // [IN] Optional length.
            mdMethodDefNil,             // [IN] Getter method.
            mdMethodDefNil,             // [IN] Setter method.
            NULL);                      // [IN] Other methods.
    }
    else
    {
        hr = pRCW->GetEmitter()->SetParamProps( 
            tk,                   // [IN] The ParamDef.
            NULL,
            ULONG_MAX,                  // [IN] Parameter attributes.
            valueCorType,               // [IN] Flag for the value type, selected ELEMENT_TYPE_*
            pValue,                     // [IN] Constant value.
            (ULONG) -1);                // [IN] Optional length.
    }
    if (FAILED(hr)) {   
        _ASSERTE(!"Set default value is failing"); 
        COMPlusThrow(kArgumentException, W("Argument_BadConstantValue"));    
    }   

    END_QCALL;
}
Example #12
0
FCIMPLEND
#endif // !FEATURE_CORECLR

FCIMPL4(void, AssemblyNameNative::Init, Object * refThisUNSAFE, OBJECTREF * pAssemblyRef, CLR_BOOL fForIntrospection, CLR_BOOL fRaiseResolveEvent)
{
    FCALL_CONTRACT;

    ASSEMBLYNAMEREF pThis = (ASSEMBLYNAMEREF) (OBJECTREF) refThisUNSAFE;
    HRESULT hr = S_OK;
    
    HELPER_METHOD_FRAME_BEGIN_1(pThis);
    
    *pAssemblyRef = NULL;

    if (pThis == NULL)
        COMPlusThrow(kNullReferenceException, W("NullReference_This"));

    Thread * pThread = GetThread();

    CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease

    AssemblySpec spec;
    hr = spec.InitializeSpec(&(pThread->m_MarshalAlloc), (ASSEMBLYNAMEREF *) &pThis, TRUE, FALSE); 

    if (SUCCEEDED(hr))
    {
        spec.AssemblyNameInit(&pThis,NULL);
    }
    else if ((hr == FUSION_E_INVALID_NAME) && fRaiseResolveEvent)
    {
        Assembly * pAssembly = GetAppDomain()->RaiseAssemblyResolveEvent(&spec, fForIntrospection, FALSE);

        if (pAssembly == NULL)
        {
            EEFileLoadException::Throw(&spec, hr);
        }
        else
        {
            *((OBJECTREF *) (&(*pAssemblyRef))) = pAssembly->GetExposedObject();
        }
    }
    else
    {
        ThrowHR(hr);
    }
    
    HELPER_METHOD_FRAME_END();
}
Example #13
0
FCIMPLEND


FCIMPL1(Object*, AssemblyNameNative::GetPublicKeyToken, Object* refThisUNSAFE)
{
    FCALL_CONTRACT;

    OBJECTREF orOutputArray = NULL;
    OBJECTREF refThis       = (OBJECTREF) refThisUNSAFE;
    HELPER_METHOD_FRAME_BEGIN_RET_1(refThis);

    if (refThis == NULL)
        COMPlusThrow(kNullReferenceException, W("NullReference_This"));

    ASSEMBLYNAMEREF orThis = (ASSEMBLYNAMEREF)refThis;
    U1ARRAYREF orPublicKey = orThis->GetPublicKey();

    if (orPublicKey != NULL) {
        DWORD cb = orPublicKey->GetNumComponents();
        StrongNameBufferHolder<BYTE> pbToken;

        if (cb) {    
            CQuickBytes qb;
            BYTE *pbKey = (BYTE*) qb.AllocThrows(cb);
            memcpy(pbKey, orPublicKey->GetDataPtr(), cb);

            {
                GCX_PREEMP();
                if (!StrongNameTokenFromPublicKey(pbKey, cb, &pbToken, &cb))
                    COMPlusThrowHR(StrongNameErrorInfo());
            }
        }

        Security::CopyEncodingToByteArray(pbToken, cb, &orOutputArray);
    }

    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(orOutputArray);
}
Example #14
0
FCIMPL2(void, COMCurrency::DoToDecimal, DECIMAL * result, CY c)
{
    FCALL_CONTRACT;

    // GC could only happen when exception is thrown, no need to protect result
    HELPER_METHOD_FRAME_BEGIN_0();

    _ASSERTE(result);
    HRESULT hr = VarDecFromCy(c, result);
    if (FAILED(hr))
    {
        // Didn't expect to get here.  Update code for this HR.
        _ASSERTE(S_OK == hr);
        COMPlusThrowHR(hr);
    }

    if (FAILED(DecimalCanonicalize(result)))
        COMPlusThrow(kOverflowException, W("Overflow_Currency"));
    
    result->wReserved = 0;

    HELPER_METHOD_FRAME_END();
}
Example #15
0
//+----------------------------------------------------------------------------
//
//  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"));
}
Example #16
0
//******************************************************************************
//
// GetMemberRefToken
// This function will return a MemberRef token given a MethodDef token and the module where the MethodDef/FieldDef is defined.
//
//******************************************************************************
INT32 QCALLTYPE COMModule::GetMemberRef(QCall::ModuleHandle pModule, QCall::ModuleHandle pRefedModule, INT32 tr, INT32 token)
{
    QCALL_CONTRACT;
    
    mdMemberRef             memberRefE      = 0; 

    BEGIN_QCALL;

    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); 
    _ASSERTE( pRCW );
    
    LPCUTF8         szName;
    ULONG           cbComSig;
    PCCOR_SIGNATURE pvComSig;
    
    if (TypeFromToken(token) == mdtMethodDef)
    {
        IfFailThrow(pRefedModule->GetMDImport()->GetNameOfMethodDef(token, &szName));
        IfFailThrow(pRefedModule->GetMDImport()->GetSigOfMethodDef(token, &cbComSig, &pvComSig));
    }
    else
    {
        IfFailThrow(pRefedModule->GetMDImport()->GetNameOfFieldDef(token, &szName));
        IfFailThrow(pRefedModule->GetMDImport()->GetSigOfFieldDef(token, &cbComSig, &pvComSig));
    }
    
    MAKE_WIDEPTR_FROMUTF8(wzName, szName);

    // Translate the method sig into this scope 
    //
    Assembly * pRefedAssembly = pRefedModule->GetAssembly();
    Assembly * pRefingAssembly = pModule->GetAssembly();

    if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly)
    {
        if (pRefingAssembly->IsCollectible())
            pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator());
        else
            COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
    }

    SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
    IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );

    CQuickBytes             qbNewSig; 
    ULONG                   cbNewSig;      

    IfFailThrow( pRefedModule->GetMDImport()->TranslateSigWithScope(
        pRefedAssembly->GetManifestImport(), 
        NULL, 0,        // hash value
        pvComSig, 
        cbComSig, 
        pAssemblyEmit,  // Emit assembly scope.
        pRCW->GetEmitter(), 
        &qbNewSig, 
        &cbNewSig) );  

    mdTypeRef               tref;

    if (TypeFromToken(tr) == mdtTypeDef)
    {
        // define a TypeRef using the TypeDef
        DefineTypeRefHelper(pRCW->GetEmitter(), tr, &tref);
    }
    else 
        tref = tr;

    // Define the memberRef
    IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tref, wzName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) ); 

    END_QCALL;

    // assign output parameter
    return (INT32)memberRefE;
}
Example #17
0
CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes)
: m_NativeSize(0)
, m_hndManagedType(hndManagedType)
, m_hndCustomMarshaler(NULL)
, m_pMarshalNativeToManagedMD(NULL)
, m_pMarshalManagedToNativeMD(NULL)
, m_pCleanUpNativeDataMD(NULL)
, m_pCleanUpManagedDataMD(NULL)
, m_bDataIsByValue(FALSE)
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_COOPERATIVE;
        PRECONDITION(CheckPointer(pDomain));
    }
    CONTRACTL_END;


    // Make sure the custom marshaller implements ICustomMarshaler.
    if (!hndCustomMarshalerType.GetMethodTable()->CanCastToNonVariantInterface(MscorlibBinder::GetClass(CLASS__ICUSTOM_MARSHALER)))
    {
        DefineFullyQualifiedNameForClassW()
        COMPlusThrow(kApplicationException,
                     IDS_EE_ICUSTOMMARSHALERNOTIMPL,
                     GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable()));
    }

    // Determine if this type is a value class.
    m_bDataIsByValue = m_hndManagedType.GetMethodTable()->IsValueType();

    // Custom marshalling of value classes is not currently supported.
    if (m_bDataIsByValue)
        COMPlusThrow(kNotSupportedException, W("NotSupported_ValueClassCM"));

#ifndef CROSSGEN_COMPILE
    // Run the <clinit> on the marshaler since it might not have run yet.
    hndCustomMarshalerType.GetMethodTable()->EnsureInstanceActive();
    hndCustomMarshalerType.GetMethodTable()->CheckRunClassInitThrowing();

    // Create a COM+ string that will contain the string cookie.
    STRINGREF CookieStringObj = StringObject::NewString(strCookie, cCookieStrBytes);
    GCPROTECT_BEGIN(CookieStringObj);
#endif

    // Load the method desc's for all the methods in the ICustomMarshaler interface.
    m_pMarshalNativeToManagedMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalNativeToManaged, hndCustomMarshalerType);
    m_pMarshalManagedToNativeMD = GetCustomMarshalerMD(CustomMarshalerMethods_MarshalManagedToNative, hndCustomMarshalerType);
    m_pCleanUpNativeDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpNativeData, hndCustomMarshalerType);
    m_pCleanUpManagedDataMD = GetCustomMarshalerMD(CustomMarshalerMethods_CleanUpManagedData, hndCustomMarshalerType);

    // Load the method desc for the static method to retrieve the instance.
    MethodDesc *pGetCustomMarshalerMD = GetCustomMarshalerMD(CustomMarshalerMethods_GetInstance, hndCustomMarshalerType);

    // If the GetInstance method is generic, get an instantiating stub for it -
    // the CallDescr infrastructure doesn't know how to pass secret generic arguments.
    if (pGetCustomMarshalerMD->RequiresInstMethodTableArg())
    {
        pGetCustomMarshalerMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
            pGetCustomMarshalerMD,
            hndCustomMarshalerType.GetMethodTable(), 
            FALSE,           // forceBoxedEntryPoint
            Instantiation(), // methodInst
            FALSE,           // allowInstParam
            FALSE);          // forceRemotableMethod

        _ASSERTE(!pGetCustomMarshalerMD->RequiresInstMethodTableArg());
    }

#ifndef CROSSGEN_COMPILE
    MethodDescCallSite getCustomMarshaler(pGetCustomMarshalerMD, (OBJECTREF*)&CookieStringObj);

    pGetCustomMarshalerMD->EnsureActive();

    // Prepare the arguments that will be passed to GetCustomMarshaler.
    ARG_SLOT GetCustomMarshalerArgs[] = { 
        ObjToArgSlot(CookieStringObj)
    };

    // Call the GetCustomMarshaler method to retrieve the custom marshaler to use.
    OBJECTREF CustomMarshalerObj = getCustomMarshaler.Call_RetOBJECTREF(GetCustomMarshalerArgs);
    if (!CustomMarshalerObj)
    {
        DefineFullyQualifiedNameForClassW()
        COMPlusThrow(kApplicationException,
                     IDS_EE_NOCUSTOMMARSHALER,
                     GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable()));
    }
    m_hndCustomMarshaler = pDomain->CreateHandle(CustomMarshalerObj);

    // Retrieve the size of the native data.
    if (m_bDataIsByValue)
    {
        // <TODO>@TODO(DM): Call GetNativeDataSize() to retrieve the size of the native data.</TODO>
        _ASSERTE(!"Value classes are not yet supported by the custom marshaler!");
    }
    else
    {
        m_NativeSize = sizeof(void *);
    }

    GCPROTECT_END();
#endif
}
Example #18
0
//**************************************************
// GetTypeRef
// This function will return the type token given full qual name. If the type
// is defined locally, we will return the TypeDef token. Or we will return a TypeRef token 
// with proper resolution scope calculated.
// wszFullName is escaped (TYPE_NAME_RESERVED_CHAR). It should not be byref or contain enclosing type name, 
// assembly name, and generic argument list.
//**************************************************
mdTypeRef QCALLTYPE COMModule::GetTypeRef(QCall::ModuleHandle pModule,
                                          LPCWSTR wszFullName,
                                          QCall::ModuleHandle pRefedModule,
                                          LPCWSTR wszRefedModuleFileName,
                                          INT32 tkResolutionArg)
{
    QCALL_CONTRACT;

    mdTypeRef tr = 0;

    BEGIN_QCALL;
        
    RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
    _ASSERTE(pRCW); 
    
    IMetaDataEmit * pEmit = pRCW->GetEmitter(); 
    IMetaDataImport * pImport = pRCW->GetRWImporter();

    if (wszFullName == NULL) {
        COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
    }    

    InlineSString<128> ssNameUnescaped;
    LPCWSTR wszTemp = wszFullName;

    WCHAR c;
    while(0 != (c = *wszTemp++))
    {
        if ( c == W('\\') && 
             IsTypeNameReservedChar(*wszTemp) )
        {
            ssNameUnescaped.Append(*wszTemp++);
        }
        else
        {
            _ASSERTE( ! IsTypeNameReservedChar(c) );
            ssNameUnescaped.Append(c);
        }
    }

    LPCWSTR wszFullNameUnescaped = ssNameUnescaped.GetUnicode();

    Assembly * pThisAssembly = pModule->GetClassLoader()->GetAssembly();
    Assembly * pRefedAssembly = pRefedModule->GetClassLoader()->GetAssembly();

    if (pModule == pRefedModule)
    {
        // referenced type is from the same module so we must be able to find a TypeDef.
        IfFailThrow(pImport->FindTypeDefByName(
            wszFullNameUnescaped,
            RidFromToken(tkResolutionArg) ? tkResolutionArg : mdTypeDefNil,
            &tr)); 
    }
    else
    {
        mdToken tkResolution = mdTokenNil;
        if (RidFromToken(tkResolutionArg))
        {
            // reference to nested type
            tkResolution = tkResolutionArg;
        }
        else
        {
            // reference to top level type
            if ( pThisAssembly != pRefedAssembly )
            {
                SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;  

                // Generate AssemblyRef
                IfFailThrow( pEmit->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
                tkResolution = pThisAssembly->AddAssemblyRef(pRefedAssembly, pAssemblyEmit);

                // Add the assembly ref token and the manifest module it is referring to this module's rid map.
                // This is needed regardless of whether the dynamic assembly has run access. Even in Save-only
                // or Refleciton-only mode, CreateType() of the referencing type may still need the referenced 
                // type to be resolved and loaded, e.g. if the referencing type is a subclass of the referenced type.
                //
                // Don't cache if there is assembly associated with the token already. The assembly ref resolution
                // can be ambiguous because of reflection emit does not require unique assembly names.
                // We always let the first association win. Ideally, we would disallow this situation by throwing 
                // exception, but that would be a breaking change.
                if(pModule->LookupAssemblyRef(tkResolution) == NULL)
                {
                    pModule->ForceStoreAssemblyRef(tkResolution, pRefedAssembly);
                }
            }
            else
            {
                _ASSERTE(pModule != pRefedModule);                
                _ASSERTE(wszRefedModuleFileName != NULL);

                // Generate ModuleRef
                IfFailThrow(pEmit->DefineModuleRef(wszRefedModuleFileName, &tkResolution));
            }
        }

        IfFailThrow( pEmit->DefineTypeRefByName(tkResolution, wszFullNameUnescaped, &tr) );  
    }

    END_QCALL;

    return tr;
}
Example #19
0
//+----------------------------------------------------------------------------
//
//  Method:     CStackBuilderSink::PrivateProcessMessage, public
//
//  Synopsis:   Builds the stack and calls an object
//
//+----------------------------------------------------------------------------
FCIMPL7(Object*, CStackBuilderSink::PrivateProcessMessage, Object* pSBSinkUNSAFE, ReflectBaseObject* pMethodBaseUNSAFE, PTRArray* pArgsUNSAFE, Object* pServerUNSAFE, void* iMethodPtr, BOOL fContext, PTRARRAYREF* ppVarOutParams)
{
    OBJECTREF ret = NULL;
    struct _gc
    {
        REFLECTBASEREF pMethodBase;
        PTRARRAYREF pArgs;
        OBJECTREF pServer;
        OBJECTREF pSBSink;
    } gc;
    gc.pMethodBase = (REFLECTBASEREF) pMethodBaseUNSAFE;
    gc.pArgs = (PTRARRAYREF) pArgsUNSAFE;
    gc.pServer = (OBJECTREF) pServerUNSAFE;
    gc.pSBSink = (OBJECTREF) pSBSinkUNSAFE;
    HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_NOPOLL(Frame::FRAME_ATTR_RETURNOBJ);
    GCPROTECT_BEGIN(gc);
    HELPER_METHOD_POLL();
    //-[autocvtpro]-------------------------------------------------------

    THROWSCOMPLUSEXCEPTION();

    TRIGGERSGC();

    LOG((LF_REMOTING, LL_INFO10,
         "CStackBuilderSink::PrivateProcessMessage\n"));
    
    _ASSERTE(gc.pMethodBase != NULL);
    ReflectMethod *pRM = (ReflectMethod *)gc.pMethodBase->GetData();
    MethodDesc *pMD = pRM->pMethod;    

	// Either pServer is non-null or the method is static (but not both)
    _ASSERTE((gc.pServer!=NULL) == !(pMD->IsStatic()));

    // Check if this is an interface invoke, if yes, then we have to find the
    // real method descriptor on the class of the server object.
    if(pMD->GetMethodTable()->IsInterface())
    {
        _ASSERTE(gc.pServer != NULL);

        MethodDesc* pTemp = pMD;
        // NOTE: This method can trigger GC
        pMD = gc.pServer->GetMethodTable()->GetMethodDescForInterfaceMethod(pMD, gc.pServer);
        if(NULL == pMD)
        {
            MAKE_WIDEPTR_FROMUTF8(wName, pTemp->GetName())
            COMPlusThrow(kMissingMethodException, IDS_EE_MISSING_METHOD, NULL, wName);
        }
    }

    MetaSig mSig(pMD->GetSig(), pMD->GetModule());
    
    // get the target depending on whether the method is virtual or non-virtual
    // like a constructor, private or final method
    const BYTE* pTarget = NULL;
     
    if (iMethodPtr) 
    {
        pTarget = (const BYTE*) iMethodPtr;
    }
    else
    {
        // Get the address of the code
        pTarget = MethodTable::GetTargetFromMethodDescAndServer(pMD, &(gc.pServer), fContext);    
    }
    

    VASigCookie *pCookie = NULL;
    _ASSERTE(NULL != pTarget);
    GCPROTECT_BEGIN (ret);
            // this function does the work
    ::CallDescrWithObjectArray(
            gc.pServer, 
            pRM, 
            pTarget, 
            &mSig, 
            pCookie, 
            gc.pServer==NULL?TRUE:FALSE, //fIsStatic
            gc.pArgs, 
            &ret,
            ppVarOutParams);
    GCPROTECT_END ();

    LOG((LF_REMOTING, LL_INFO10,
         "CStackBuilderSink::PrivateProcessMessage OUT\n"));

        //-[autocvtepi]-------------------------------------------------------
    GCPROTECT_END();
    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(ret);
}