Core CLR Host 源码分析(4)

当CLR实例化 PEAssembly 的时候,会调用  PEAssemblyHolder pFile(pDomain->BindAssemblySpec(this, fThrowOnFileNotFound, fRaisePrebindEvents, pCallerStackMark));

实际上分为三步:

1.通过   pSpec->Bind()获取到bindResult,然后调用PEAssembly::Open new 一个 PEAssembly实例,参数就是bindReuslt

2.pspec 的bind函数会返回pPrivAsm。代码为:   

   

   hr = pTPABinder->Bind(assemblyDisplayName,
                           m_wszCodeBase,
                           GetParentAssembly()? GetParentAssembly()->GetFile():NULL,
                           fNgenExplicitBind,
                           fExplicitBindToNativeImage,
                          &pPrivAsm);

当返回pprivasm之后, 会将pprivasm通过函数GetAssemblyFromPrivAssemblyFast,  result = BINDER_SPACE::GetAssemblyFromPrivAssemblyFast(pPrivAsm.Extract());

最后  pResult->Init(result,fIsInGAC, fIsOnTpaList);返回 上一步的bindResult

3.ptabinder->bind函数会调用获取pasm程序集句柄,这个句柄实际上为 首先调用 binderresult,然后通过binderresult获取到hostbinderresult,最后通过hostbinderresult返回程序pasm

4.当获取binderresult 的时候,他会实例化peimage 和 pasm,然后设置binderresult。

具体就是以上四个步骤:

部分代码如下:

 if (pSpec->HasUniqueIdentity())
    {
        HRESULT hrBindResult = S_OK;
        PEAssemblyHolder result;
        

        EX_TRY
        {
            if (!IsCached(pSpec))
            {

                {
                    bool fAddFileToCache = false;

                    BOOL fIsWellKnown = FALSE;

                    // Use CoreClr's fusion alternative
                    CoreBindResult bindResult;

                    pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
                    hrBindResult = bindResult.GetHRBindResult();

                    if (bindResult.Found()) 
                    {
                        if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
                        {
                            // Avoid rebinding to another copy of mscorlib
                            result = SystemDomain::SystemFile();
                            result.SuppressRelease(); // Didn't get a refcount
                        }
                        else
                        {
                            // IsSystem on the PEFile should be false, even for mscorlib satellites
                            result = PEAssembly::Open(&bindResult,
                                                      FALSE, pSpec->IsIntrospectionOnly());
                        }
                        fAddFileToCache = true;
                        
                        // Setup the reference to the binder, which performed the bind, into the AssemblySpec
                        ICLRPrivBinder* pBinder = result->GetBindingContext();
                        _ASSERTE(pBinder != NULL);
                        pSpec->SetBindingContext(pBinder);
                    }


                    if (fAddFileToCache)
                    {


                        if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
                        {
                            // Failure to add simply means someone else beat us to it. In that case
                            // the FindCachedFile call below (after catch block) will update result
                            // to the cached value.
                            AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
                        }
                    }
                    else if (!fIsWellKnown)
                    {
                        _ASSERTE(fThrowOnFileNotFound == FALSE);

                        // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
                        // return an assembly that does not match, and this can cause recursive resource lookups during error
                        // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
                        // AssemblySpec::Bind().
                        if (!pSpec->IsMscorlibSatellite())
                        {
                            // Trigger the resolve event also for non-throw situation.
                            // However, this code path will behave as if the resolve handler has thrown,
                            // that is, not trigger an MDA.

                            AssemblySpec NewSpec(this);
                            AssemblySpec *pFailedSpec = NULL;

                            fForceReThrow = TRUE; // Managed resolve event handler can throw

                            // Purposly ignore return value
                            PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
                        }
                    }
                }
            }
        }
        EX_CATCH
        {
            Exception *ex = GET_EXCEPTION();

            AssemblySpec NewSpec(this);
            AssemblySpec *pFailedSpec = NULL;

            // Let transient exceptions or managed resolve event handler exceptions propagate
            if (ex->IsTransient() || fForceReThrow)
            {
                EX_RETHROW;
            }

            {
                // This is not executed for SO exceptions so we need to disable the backout
                // stack validation to prevent false violations from being reported.
                DISABLE_BACKOUT_STACK_VALIDATION;

                BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
                if (fFailure)
                {
                    BOOL bFileNotFoundException =
                        (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
                
                    if (!bFileNotFoundException)
                    {
                        fFailure = AddExceptionToCache(pFailedSpec, ex);
                    } // else, fFailure stays TRUE
                    // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)

                    // Only throw this exception if we are the first in the cache
                    if (fFailure)
                    {
                        //
                        // If the BindingFailure MDA is enabled, trigger one for this failure
                        // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
                        //       and the MDA isn't sent in this case (or for transient failure cases)
                        //
#ifdef MDA_SUPPORTED
                        MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
                        if (pProbe)
                        {
                            // Transition to cooperative GC mode before using any OBJECTREFs.
                            GCX_COOP();

                            OBJECTREF exceptionObj = GET_THROWABLE();
                            GCPROTECT_BEGIN(exceptionObj)
                            {
                                pProbe->BindFailed(pFailedSpec, &exceptionObj);
                            }
                            GCPROTECT_END();
                        }
#endif

                        // In the same cases as for the MDA, store the failure information for DAC to read
                        if (IsDebuggerAttached()) {
                            FailedAssembly *pFailed = new FailedAssembly();
                            pFailed->Initialize(pFailedSpec, ex);
                            IfFailThrow(m_failedAssemblies.Append(pFailed));
                        }

                        if (!bFileNotFoundException || fThrowOnFileNotFound)
                        {

                            // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
                            //
                            // In Everett, if we failed to download an assembly because of a broken network cable,
                            // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
                            // (which would be exposed when marshaled to native.)
                            //
                            // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
                            // the online/offline switch code in VSTO for Everett hardcoded a check for
                            // COR_E_FILENOTFOUND. 
                            //
                            // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
                            // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
                            // the least number of callers.
                            
                            if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
                            {
                                EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
                            }

                            if (EEFileLoadException::CheckType(ex))
                            {
                                if (pFailedSpec == pSpec)
                                {
                                    EX_RETHROW; //preserve the information
                                }
                                else
                                {
                                    StackSString exceptionDisplayName, failedSpecDisplayName;

                                    ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
                                    pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);

                                    if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
                                    {
                                        EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
                                    }
                                }
                            }
                            
                            EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
                        }

                    }
                }
            }
        }
        EX_END_CATCH(RethrowTerminalExceptions);

        // Now, if it's a cacheable bind we need to re-fetch the result from the cache, as we may have been racing with another
        // thread to store our result.  Note that we may throw from here, if there is a cached exception.
        // This will release the refcount of the current result holder (if any), and will replace
        // it with a non-addref'ed result
        if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
        {
            result = FindCachedFile(pSpec);

            if (result != NULL)
                result->AddRef();
        }

        return result.Extract();
    }

猜你喜欢

转载自blog.csdn.net/tangyanzhi1111/article/details/89961905
CLR