GC source code analysis in sscli (1)-call interface between EE and bcl fcall

Source: Internet
Author: User

First, place a breakpoint on the collectgeneration method of the gcinterface class in the \ CLR \ SRC \ VM \ comutilnative. cpp file of sscli2.0 source code. This macro method mainly implements a call conversion:

/*==============================CollectGeneration===============================**Action: Collects all generations <= args->generation**Returns: void**Arguments: args->generation:  The maximum generation to collect**Exceptions: Argument exception if args->generation is < 0 or > GetMaxGeneration();==============================================================================*/FCIMPL1(void, GCInterface::CollectGeneration, INT32 generation){    CONTRACTL    {        MODE_COOPERATIVE;        DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.        THROWS;        SO_TOLERANT;    }    CONTRACTL_END;    //We've already checked this in GC.cs, so we'll just assert it here.    _ASSERTE(generation >= -1);    //We don't need to check the top end because the GC will take care of that.    HELPER_METHOD_FRAME_BEGIN_0();    GCHeap::GetGCHeap()->GarbageCollect(generation);    if (g_TrapReturningThreads)    {        GetThread()->PulseGCMode();    }    HELPER_METHOD_FRAME_END();}FCIMPLEND

This method provides an interface for calling the internal functions of the sscli virtual execution engine from the BCl. In the sscli implementation version, this call conversion method is called fcall.

In jit-free code, for example, some helper code snippets or stubs, some components that call conversions to coordinate different functions are often used. In this way, a heap with all functions is not displayed in runtime.

Using this very effective call conversion enables hosting of advanced languages, such as C #, to call internal functions in runtime in user code. To use this call, you only need to add the methodimploptions. internalcall attribute to the implemented method.

Fcall will use the ecfunc struct in sscli20 \ CLR \ SRC \ VM \ eCall. cpp to complete the conversion of the C ++ method implemented from the hosting Method to the runtime:

struct ECFunc {    UINT_PTR            m_dwFlags;#ifndef DACCESS_COMPILE    LPVOID              m_pImplementation;#else    TADDR               m_pImplementation;#endif    PTR_MethodDesc      m_pMD;               // for reverse mapping    PTR_ECFunc          m_pNext;             // linked list for hash table    LPCUTF8             m_wszMethodName;    LPHARDCODEDMETASIG  m_wszMethodSig;      // Optional field. It is valid only if HasSignature() is set.    bool                IsEndOfArray()  { LEAF_CONTRACT; return !!(m_dwFlags & FCFuncFlag_EndOfArray); }    bool                HasSignature()  { LEAF_CONTRACT; return !!(m_dwFlags & FCFuncFlag_HasSignature); }    bool                IsUnreferenced(){ LEAF_CONTRACT; return !!(m_dwFlags & FCFuncFlag_Unreferenced); }    CorInfoIntrinsics   IntrinsicID()   { LEAF_CONTRACT; return (CorInfoIntrinsics)((INT8)(m_dwFlags >> 16)); }    int                 DynamicID()     { LEAF_CONTRACT; return (int)              ((INT8)(m_dwFlags >> 24)); }    ECFunc*             NextInArray()    {         LEAF_CONTRACT;                 return (ECFunc*)((BYTE*)this +             (HasSignature() ? sizeof(ECFunc) : offsetof(ECFunc, m_wszMethodSig)));    }};

M_wszmethodname indicates the corresponding method in BCl. M_pimplementation indicates the corresponding method in runtime. As you can see, this conversion does not involve any logic such as parameter passing or type check, because the methods called by fcall are fully implemented within runtime.

The methodclassification Enumeration type in the method. cpp file also lists the method categories in other sscli execution engines:

// Used in MethodDescenum MethodClassification{    mcIL        = 0, // IL    mcFCall     = 1, // FCall (also includes tlbimped ctor, Delegate ctor)    mcNDirect   = 2, // N/Direct    mcEEImpl    = 3, // special method; implementation provided by EE (like Delegate Invoke)    mcArray     = 4, // Array ECall    mcInstantiated = 5, // Instantiated generic methods, including descriptors                        // for both shared and unshared code (see InstantiatedMethodDesc)    mcDynamic       = 7, // for method dewsc with no metadata behind    mcCount,};

In the sscli Object Memory layout, because the methoddesc structure is a few different types of aggregates, here we use a three-bit flag to indicate that methoddesc is the type used. In methodclassfication, the method is neither jited nor non-jited. Whether the method has been JIT or not is known only when the method is executed for the first time. At the same time, because all threads in the hosting process need to modify these three bit bits, This identifier is placed on the memory address that can be synchronized by the thread.

Methodclassification is used in methoddesc to identify a method type. In addition, methoddesc has a 16-bit flag (methodclassification) to indicate all attributes of a methoddesc. You can refer to the introduction to methoddesc in the previous chapter.

Note that the following code installs a stack frame in the stack before calling the garbagecollect method in the gcheap class:

//We don't need to check the top end because the GC will take care of that.HELPER_METHOD_FRAME_BEGIN_0();GCHeap::GetGCHeap()->GarbageCollect(generation);if (g_TrapReturningThreads){    GetThread()->PulseGCMode();}HELPER_METHOD_FRAME_END();

In the preceding method, the helper_method_frame_begin_0 () method helper_method_frame_end () is used in pairs to place helpermethodframe stack frames in gcheap. The main function of this stack frame is to allow the JIT helper or fcall information to be added to the stack to facilitate the program's traversal of the stack. The following is the constructor of the frame:

// Lazy initialization of HelperMethodFrame.  Need to// call InsureInit to complete initialization// If this is an FCall, the second param is the entry point for the FCALL.// The MethodDesc will be looked up form this (lazily), and this method// will be used in stack reporting, if this is not an FCall pass a 0HelperMethodFrame(void* fCallFtnEntry, struct LazyMachState* ms, unsigned attribs = 0){    WRAPPER_CONTRACT;     INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)     m_Attribs = attribs;     LazyInit(fCallFtnEntry, ms);}

By the way, lazy initialization technology is used here. Lazy Initialization is a method for delaying object initialization, for example, calculating a value, or, if the computing cost of a process is relatively high and is not frequently used, it is initialized during the first use. The implementation method mainly uses a flag to identify whether the process has started. This is also a design model. You can find a detailed description of this technology in Wikipedia:

Http://en.wikipedia.org/wiki/Lazy_initialization

Finally, in the comutilnative. cpp file, many other classes and methods called between Bcl and runtime are implemented, including:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.