首先在SSCLI2.0源代码的\clr\src\vm\comutilnative.cpp文件中的GCInterface类的CollectGeneration方法上下个断点,该宏方法主要实现了一个调用转换:

/*==============================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

这个方法提供了从BCL中调用SSCLI虚拟执行引擎内部功能的一个接口。在SSCLI实现版本中,这种调用转换的方式叫做FCall。

在不会被JIT的代码中,譬如一些Helper代码片段或者stubs中,经常会使用一些调用转换来协调不同功能的组件。这样在Runtime中,就不会出现是一个非常大的、包含了所有功能的Heap。

使用这种非常有效的调用转换,可以让托管高级语言,譬如C#,在用户代码中调用Runtime中的内部功能。使用这种调用,只需要给实现的方法加上MethodImplOptions.InternalCall的属性即可。

而FCall会使用sscli20\clr\src\vm\ecall.cpp中的ECFunc结构体,来完成从托管方法到Runtime内部实现的C++方法的转换:

struct ECFunc {UINT_PTR            m_dwFlags;#ifndef DACCESS_COMPILELPVOID              m_pImplementation;
#elseTADDR               m_pImplementation;
#endifPTR_MethodDesc      m_pMD;               // for reverse mappingPTR_ECFunc          m_pNext;             // linked list for hash tableLPCUTF8             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表示的是BCL中对应的方法。m_pImplementation表示的是Runtime中对应的方法。可以看到,在这种转换中,不涉及到任何关于参数传递或者是类型检查之类的逻辑,因为FCall调用的方法,完全是Runtime内部实现的。

在Method.cpp文件中的MethodClassification枚举类型中,还列出了其他SSCLI执行引擎中对Method分类的:

// Used in MethodDesc
enum MethodClassification
{mcIL        = 0, // ILmcFCall     = 1, // FCall (also includes tlbimped ctor, Delegate ctor)mcNDirect   = 2, // N/DirectmcEEImpl    = 3, // special method; implementation provided by EE (like Delegate Invoke)mcArray     = 4, // Array ECallmcInstantiated = 5, // Instantiated generic methods, including descriptors// for both shared and unshared code (see InstantiatedMethodDesc)mcDynamic       = 7, // for method dewsc with no metadata behindmcCount,
};

在SSCLI的对象内存布局中,由于MethodDesc结构是几个不同的类型的聚合体,所以这里使用一个三个bit位的flag来表示MethodDesc是使用的那种类型。在MethodClassfication中,并不表示方法是JITed或者是NON-JITed。因为是否被JIT过,只有在方法第一次被执行的时候才能够知道。同时,由于托管进程中的线程都需要修改这三个BIT位,所以这个标识被放在可以被线程同步范围的内存地址上。

MethodClassification这个结构会在MethodDesc中被使用到,来标识一个Method类型。同时,MethodDesc中有一个16bit的flag(MethodClassification)来表示一个MethodDesc所有的属性。可以参考前面章节中关于MethodDesc的介绍。

这里,还有一点需要注意的是,在调用GCHeap类中的GarbageCollect方法之前,下面的代码会在Stack中安装一个栈帧:

//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();

在上面的方法中,HELPER_METHOD_FRAME_BEGIN_0()方法HELPER_METHOD_FRAME_END()成对使用,用来在GCHeap中放置HelperMethodFrame栈帧。这个栈帧的主要功能,是允许加入Jit Helper或者是标识FCall的相关信息到栈中,来方便程序对Stack的遍历。下面是这个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 0
HelperMethodFrame(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);
}

顺便提一下,这个地方使用了Lazy initialization技术,Lazy initialization是一种延迟初始化对象的策略,譬如说计算一个值,或者是一个Process的计算代价比较昂贵而且也不是经常使用的情况下,就在第一次使用的时候初始化。实现的方式,主要是用一个Flag来标识这个过程是否已经开始。这也算是一种设计模式。可以在Wikipedia找到关于这个技术的比较详细的说明:

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

最后,在comutilnative.cpp文件中,还是实现了许多其他的BCL和Runtime之间调用的类和方法,主要包括一下类:

转载于:https://www.cnblogs.com/lbq1221119/archive/2009/09/11/1564640.html

SSCLI中GC源码分析(1) - EE与BCL之间的调用接口FCall相关推荐

  1. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

  2. Android多媒体框架(3)—— libstagefright中MediaCodec源码分析

    libstagefright中MediaCodec源码分析 和前两篇一样,我们按照MediaCodec的各个状态来分析libstagefright中MediaCodec的源代码. configure ...

  3. zipline中TradingCalendar源码分析

    zipline中TradingCalendar源码分析 1 TradingCalendar 交易日历 2 依赖项 3 canonicalize_datetime 时间进行格式化转换 4 get_non ...

  4. JDK7中HashMap源码分析

    文章目录 JDK7中的HashMap 一.JDK7中HashMap源码中重要的参数 二.JDK7中HashMap的构造方法 三.JDK7中创建一个HashMap的步骤 四.JDK7中HashMap的p ...

  5. Spark源码分析:多种部署方式之间的区别与联系

    作者:过往记忆 从官方的文档我们可以知道, Spark 的部署方式有很多种:local.Standalone.Mesos.YARN-..不同部署方式的后台处理进程是不一样的,但是如果我们从代码的角度来 ...

  6. 深入理解 Node.js 中 EventEmitter源码分析(3.0.0版本)

    events模块对外提供了一个 EventEmitter 对象,即:events.EventEmitter. EventEmitter 是NodeJS的核心模块events中的类,用于对NodeJS中 ...

  7. 动态代理以及对应Spring中AOP源码分析

    AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...

  8. Spring中Scope源码分析

    目录 概述 Spring中内置的Scope Scope实现原理分析 Scope接口 Scope注解 ConfigurableBeanFactory接口 BeanDefinition接口 Abstrac ...

  9. 【原】Spark中Master源码分析(一)

    Master作为集群的Manager,对于集群的健壮运行发挥着十分重要的作用.下面,我们一起了解一下Master是听从Client(Leader)的号召,如何管理好Worker的吧. 1.家当(静态属 ...

最新文章

  1. python 遍历_python中使用iterrows()对dataframe进行遍历的示例
  2. ABAP动态生成内表的三种方法
  3. java反射机制详解_Java反射机制详解
  4. 如何将因果干预用于提升模型公平性?
  5. JS打开新窗口的代码window.showModalDialog()
  6. 【渝粤题库】广东开放大学 互联网营销 形成性考核
  7. 数据 正则化 python_python3.6怎么单独正则化/标准化DataFrame中的指定列数据
  8. Java中所有锁介绍
  9. Java核心类库——内部类那点事儿
  10. Matplotlib 命令总结
  11. nginx访问502,日志报错:connect() to 127.0.0.1:180 failed (13: Permission denied)解决
  12. 浙江大华 研发类试题
  13. 智能优化算法:郊狼优化算法-附代码
  14. 基于VAR模型出国留学人数增加的影响因素分析
  15. 魔兽地图编辑器插件YDWE的使用与基本设置4 物体编辑器、启动游戏测试、查找物品
  16. 【问题解决】Linux服务器免密信任 远程执行
  17. 袁国宝:董明珠的小倔强!
  18. 分享一些可以调研B端产品的网站,建议收藏
  19. 微信开发者工具官方版
  20. 方向导数(Directional derivatives)

热门文章

  1. 贝叶斯集锦:从MC、MC到MCMC
  2. 存到mysql的中文乱码_web项目存数据到数据库,中文乱码,解决过程
  3. java中引用类型作形参_阿花宝宝 Java基础笔记 之 引用类型作为参数
  4. git 公钥提交代码_gitlab上传公钥和项目代码
  5. linux 烧录树莓派镜像,Linux命令行烧录树莓派镜像至SD卡
  6. Spring Boot入口类
  7. Azkaban入门简介
  8. 一次函数(正比例函数)公式的解析式与C语言代码实现
  9. Linux内核学习之路_1_编译Linux内核
  10. Windows核心编程_注册表操作和小练习程序关联