Пример #1
0
FCIMPLEND

// Return a method info for the method were the exception was thrown
FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE)
{
    FCALL_CONTRACT;
    
    I1ARRAYREF pArray(static_cast<I1Array *>(pStackTraceUNSAFE));
    StackTraceArray stackArray(pArray);

    if (!stackArray.Size())
        return NULL;

    // The managed stacktrace classes always returns typical method definition, so we don't need to bother providing exact instantiation.
    // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(pElements[0].pFunc, pElements[0].pExactGenericArgsToken, pTypeHandle, &pMD);

    MethodDesc* pFunc = stackArray[0].pFunc;

    // Strip the instantiation to make sure that the reflection never gets a bad method desc back.
    REFLECTMETHODREF refRet = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_0()
    pFunc = pFunc->LoadTypicalMethodDefinition();
    refRet = pFunc->GetStubMethodInfo();
    _ASSERTE(pFunc->IsRuntimeMethodHandle());

    HELPER_METHOD_FRAME_END();

    return (ReflectMethodObject*)OBJECTREFToObject(refRet);
}
Пример #2
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);
}
Пример #3
0
FCIMPLEND

FCIMPL0(StringObject*, SystemNative::GetRuntimeDirectory)
{
    FCALL_CONTRACT;

    STRINGREF   refRetVal   = NULL;
    DWORD dwFile = MAX_LONGPATH+1;

    HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
    SString wszFilePathString;

    WCHAR * wszFile = wszFilePathString.OpenUnicodeBuffer(dwFile);
    HRESULT hr = GetInternalSystemDirectory(wszFile, &dwFile);
    wszFilePathString.CloseBuffer(dwFile);
    
    if(FAILED(hr))
        COMPlusThrowHR(hr);

    dwFile--; // remove the trailing NULL

    if(dwFile)
        refRetVal = StringObject::NewString(wszFile, dwFile);

    HELPER_METHOD_FRAME_END();
    return (StringObject*)OBJECTREFToObject(refRetVal);
}
Пример #4
0
FCIMPLEND

FCIMPL0(StringObject*, SystemNative::_GetModuleFileName)
{
    FCALL_CONTRACT;

    STRINGREF   refRetVal = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
    if (g_pCachedModuleFileName)
    {
        refRetVal = StringObject::NewString(g_pCachedModuleFileName);
    }
    else
    {
        SString wszFilePathString;

        WCHAR * wszFile = wszFilePathString.OpenUnicodeBuffer(MAX_LONGPATH);
        DWORD lgth = WszGetModuleFileName(NULL, wszFile, MAX_LONGPATH);
        if (!lgth)
        {
            COMPlusThrowWin32();
        }
        wszFilePathString.CloseBuffer(lgth);

        refRetVal = StringObject::NewString(wszFilePathString.GetUnicode());
    }
    HELPER_METHOD_FRAME_END();

    return (StringObject*)OBJECTREFToObject(refRetVal);
}
Пример #5
0
FCIMPL0(Object*, SystemNative::GetCommandLineArgs)
{
    FCALL_CONTRACT;

    PTRARRAYREF strArray = NULL;

    HELPER_METHOD_FRAME_BEGIN_RET_1(strArray);

    LPWSTR commandLine;

    commandLine = WszGetCommandLine();
    if (commandLine==NULL)
        COMPlusThrowOM();

    DWORD numArgs = 0;
    LPWSTR* argv = SegmentCommandLine(commandLine, &numArgs);
    if (!argv)
        COMPlusThrowOM();

    _ASSERTE(numArgs > 0);

    strArray = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pStringClass);
    // Copy each argument into new Strings.
    for(unsigned int i=0; i<numArgs; i++)
    {
        STRINGREF str = StringObject::NewString(argv[i]);
        STRINGREF * destData = ((STRINGREF*)(strArray->GetDataPtr())) + i;
        SetObjectReference((OBJECTREF*)destData, (OBJECTREF)str, strArray->GetAppDomain());
    }
    delete [] argv;

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(strArray);
}
Пример #6
0
FCIMPLEND

// Note: Arguments checked in IL.
FCIMPL1(Object*, SystemNative::_GetEnvironmentVariable, StringObject* strVarUNSAFE)
{
    FCALL_CONTRACT;

    STRINGREF refRetVal;
    STRINGREF strVar;

    refRetVal   = NULL;
    strVar      = ObjectToSTRINGREF(strVarUNSAFE);

    HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, strVar);

    int len;

    // Get the length of the environment variable.
    PathString envPath;    // prefix complains if pass a null ptr in, so rely on the final length parm instead
    len = WszGetEnvironmentVariable(strVar->GetBuffer(), envPath);

    if (len != 0)
    {
        // Allocate the string.
        refRetVal = StringObject::NewString(len);
 
        wcscpy_s(refRetVal->GetBuffer(), len + 1, envPath);
        
    }

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(refRetVal);
}
Пример #7
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);
}
Пример #8
0
void FinalizerThread::FinalizeAllObjects_Wrapper(void *ptr)
{
    STATIC_CONTRACT_THROWS;
    STATIC_CONTRACT_GC_TRIGGERS;
    STATIC_CONTRACT_MODE_COOPERATIVE;

    FinalizeAllObjects_Args *args = (FinalizeAllObjects_Args *) ptr;
    _ASSERTE(args->fobj);
    Object *fobj = OBJECTREFToObject(args->fobj);
    args->fobj = NULL;      // don't want to do this guy again, if we take an exception here:
    args->fobj = ObjectToOBJECTREF(FinalizeAllObjects(fobj, args->bitToCheck));
}
Пример #9
0
FCIMPLEND

// Note: Arguments checked in IL.
FCIMPL1(Object*, SystemNative::_GetEnvironmentVariable, StringObject* strVarUNSAFE)
{
    FCALL_CONTRACT;

    STRINGREF refRetVal;
    STRINGREF strVar;

    refRetVal   = NULL;
    strVar      = ObjectToSTRINGREF(strVarUNSAFE);

    HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, strVar);

    // We loop round getting the length of the env var and then trying to copy
    // the value into a managed string. Usually we'll go through this loop
    // precisely once, but the caution is ncessary in case the variable mutates
    // beneath us.
    int len, newLen;

    // Get the length of the environment variable.
    WCHAR dummy;    // prefix complains if pass a null ptr in, so rely on the final length parm instead
    len = WszGetEnvironmentVariable(strVar->GetBuffer(), &dummy, 0);

    while (len != 0)
    {
        // Allocate the string.
        refRetVal = StringObject::NewString(len);

        // Get the value.
        newLen = WszGetEnvironmentVariable(strVar->GetBuffer(), refRetVal->GetBuffer(), len);
        if (newLen != (len - 1))
        {
            // The envvar changed, need to do this again. Let GC collect the
            // string we just allocated.
            refRetVal = NULL;

            // Go back and try again.
            len = newLen;
        }
        else
            break;
    }

    HELPER_METHOD_FRAME_END();

    return OBJECTREFToObject(refRetVal);
}
Пример #10
0
FCIMPLEND

#ifndef FEATURE_CORECLR
FCIMPL1(Object*, AssemblyNameNative::EscapeCodeBase, StringObject* filenameUNSAFE)
{
    FCALL_CONTRACT;

    STRINGREF rv        = NULL;
    STRINGREF filename  = (STRINGREF) filenameUNSAFE;
    HELPER_METHOD_FRAME_BEGIN_RET_1(filename);

    LPWSTR pCodeBase = NULL;
    DWORD  dwCodeBase = 0;
    CQuickBytes qb;

    if (filename != NULL) {
        WCHAR* pString;
        int    iString;
        filename->RefInterpretGetStringValuesDangerousForGC(&pString, &iString);
        dwCodeBase = (DWORD) iString;
        pCodeBase = (LPWSTR) qb.AllocThrows((++dwCodeBase) * sizeof(WCHAR));
        memcpy(pCodeBase, pString, dwCodeBase*sizeof(WCHAR));
    }

    if(pCodeBase) {
        CQuickBytes qb2;
        DWORD dwEscaped = 1;

        DWORD flags = 0;
        if (RunningOnWin7())
            flags |= URL_ESCAPE_AS_UTF8;

        UrlEscape(pCodeBase, (LPWSTR) qb2.Ptr(), &dwEscaped, flags);

        LPWSTR result = (LPWSTR)qb2.AllocThrows((++dwEscaped) * sizeof(WCHAR));
        HRESULT hr = UrlEscape(pCodeBase, result, &dwEscaped, flags);

        if (SUCCEEDED(hr))
            rv = StringObject::NewString(result);
        else
            COMPlusThrowHR(hr);
    }

    HELPER_METHOD_FRAME_END();
    return OBJECTREFToObject(rv);
}
Пример #11
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);
}
Пример #12
0
FCIMPLEND

FCIMPL0(StringObject*, SystemNative::GetDeveloperPath)
{
#ifdef FEATURE_FUSION
    FCALL_CONTRACT;

    STRINGREF   refDevPath  = NULL;
    LPWSTR pPath = NULL;
    DWORD lgth = 0;

    HELPER_METHOD_FRAME_BEGIN_RET_1(refDevPath);

    SystemDomain::System()->GetDevpathW(&pPath, &lgth);
    if(lgth) 
        refDevPath = StringObject::NewString(pPath, lgth);
    
    HELPER_METHOD_FRAME_END();
    return (StringObject*)OBJECTREFToObject(refDevPath);
#else
    return NULL;
#endif
}
Пример #13
0
Object * FinalizerThread::DoOneFinalization(Object* fobj, Thread* pThread,int bitToCheck,bool *pbTerminate)
{
    STATIC_CONTRACT_THROWS;
    STATIC_CONTRACT_GC_TRIGGERS;
    STATIC_CONTRACT_MODE_COOPERATIVE;

    bool fTerminate=false;
    Object *pReturnObject = NULL;
    

    AppDomain* targetAppDomain = fobj->GetAppDomain();
    AppDomain* currentDomain = pThread->GetDomain();
    if (! targetAppDomain || ! targetAppDomain->CanThreadEnter(pThread))
    {
        // if can't get into domain to finalize it, then it must be agile so finalize in current domain
        targetAppDomain = currentDomain;
#if CHECK_APP_DOMAIN_LEAKS
        {
        // object must be agile if can't get into it's domain
        if (g_pConfig->AppDomainLeaks() && !fobj->TrySetAppDomainAgile(FALSE))   
            _ASSERTE(!"Found non-agile GC object which should have been finalized during app domain unload.");
        }
#endif
    }

    if (targetAppDomain == currentDomain)
    {
        if (!targetAppDomain->IsRudeUnload() ||
            fobj->GetMethodTable()->HasCriticalFinalizer())
        {
            class ResetFinalizerStartTime
            {
            public:
                ResetFinalizerStartTime()
                {
                    if (CLRHosted())
                    {
                        g_ObjFinalizeStartTime = CLRGetTickCount64();
                    }                    
                }
                ~ResetFinalizerStartTime()
                {
                    if (g_ObjFinalizeStartTime)
                    {
                        g_ObjFinalizeStartTime = 0;
                    }
                }
            };
            {
                ThreadLocaleHolder localeHolder;

                {
                    ResetFinalizerStartTime resetTime;
                    CallFinalizer(fobj);
                }
            }
            pThread->InternalReset(FALSE);
        }
    } 
    else 
    {
        if (! targetAppDomain->GetDefaultContext())
        {
            // Can no longer enter domain becuase the handle containing the context has been
            // destroyed so just bail. Should only get this if are at the stage of nuking the
            // handles in the domain if it's still open.
            _ASSERTE(targetAppDomain->IsUnloading() && targetAppDomain->ShouldHaveFinalization());
        }
        else if (!currentDomain->IsDefaultDomain())
        {
            // this means we are in some other domain, so need to return back out through the DoADCallback
            // and handle the object from there in another domain.
            pReturnObject = fobj;
            fTerminate = true;
        } 
        else
        {
            // otherwise call back to ourselves to process as many as we can in that other domain
            FinalizeAllObjects_Args args;
            args.fobj = ObjectToOBJECTREF(fobj);
            args.bitToCheck = bitToCheck;
            GCPROTECT_BEGIN(args.fobj);
            {
                ThreadLocaleHolder localeHolder;

                _ASSERTE(pThreadTurnAround != NULL);
                ManagedThreadBase::FinalizerAppDomain(targetAppDomain,
                                                      FinalizeAllObjects_Wrapper,
                                                      &args,
                                                      pThreadTurnAround);
            }
            pThread->InternalReset(FALSE);
            // process the object we got back or be done if we got back null
            pReturnObject = OBJECTREFToObject(args.fobj);
            GCPROTECT_END();
        }
    }        
        
    *pbTerminate = fTerminate;
    return pReturnObject;
}
Пример #14
0
FCIMPLEND






// array is GC protected by caller
void ArrayInitializeWorker(ARRAYBASEREF * arrayRef,
                           MethodTable* pArrayMT,
                           MethodTable* pElemMT)
{
    STATIC_CONTRACT_MODE_COOPERATIVE;
    STATIC_CONTRACT_SO_INTOLERANT;

    // Ensure that the array element type is fully loaded before executing its code
    pElemMT->EnsureInstanceActive();

    //can not use contract here because of SEH
    _ASSERTE(IsProtectedByGCFrame (arrayRef));
    
    SIZE_T offset = ArrayBase::GetDataPtrOffset(pArrayMT);
    SIZE_T size = pArrayMT->GetComponentSize();
    SIZE_T cElements = (*arrayRef)->GetNumComponents();

    MethodTable * pCanonMT = pElemMT->GetCanonicalMethodTable();
    WORD slot = pCanonMT->GetDefaultConstructorSlot();

    PCODE ctorFtn = pCanonMT->GetSlot(slot);

#ifdef _X86_
    BEGIN_CALL_TO_MANAGED();

    typedef void (__fastcall * CtorFtnType)(BYTE*, BYTE*);

    for (SIZE_T i = 0; i < cElements; i++)
    {
        // Since GetSlot() is not idempotent and may have returned
        // a non-optimal entry-point the first time round.
        if (i == 1)
        {
            ctorFtn = pCanonMT->GetSlot(slot);
        }

        BYTE* thisPtr = (((BYTE*) OBJECTREFToObject (*arrayRef)) + offset);

#ifdef _DEBUG
        __asm {
            mov ECX, thisPtr
            mov EDX, pElemMT // Instantiation argument if the type is generic
            call    [ctorFtn]
            nop                // Mark the fact that we can call managed code
        }
#else // _DEBUG
        (*(CtorFtnType)ctorFtn)(thisPtr, (BYTE*)pElemMT);
#endif // _DEBUG

        offset += size;
    }

    END_CALL_TO_MANAGED();
#else // _X86_
    //
    // This is quite a bit slower, but it is portable.
    //

    for (SIZE_T i =0; i < cElements; i++)
    {
        // Since GetSlot() is not idempotent and may have returned
        // a non-optimal entry-point the first time round.
        if (i == 1)
        {
            ctorFtn = pCanonMT->GetSlot(slot);
        }

        BYTE* thisPtr = (((BYTE*) OBJECTREFToObject (*arrayRef)) + offset);

        PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(ctorFtn);
        DECLARE_ARGHOLDER_ARRAY(args, 2);
        args[ARGNUM_0] = PTR_TO_ARGHOLDER(thisPtr);
        args[ARGNUM_1] = PTR_TO_ARGHOLDER(pElemMT); // Instantiation argument if the type is generic
        CALL_MANAGED_METHOD_NORET(args);

        offset += size;
    }
#endif // _X86_
}
Пример #15
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);
}