.Net RuntimeExplorer开发日志(十一) IL to C# - yield

   首先是删除了对LINQ的特殊支持,因为LINQ与普通的扩展方法没有什么不同,并将lambda的功能扩展到支持所有方法的参数中。同时有发现了一个lambda的变形,它将方法的局部参数变为内联类型的字段,然后在构造lambda时直接用内联类型的方法代替匿名方法,例如List.RemoveAll(),对策就是像dynamic那样通通做上标记,然后在writer时将field变为var来处理,当然这里说起来简单,实际上至少要增加三百行代码。

  进入正题,yield并不复杂,但要想恢复被编译器编译过的语法糖还是需要些步骤的。首先要弄清状态机中的实例字段的意义,至少会有三个字段,一个状态一个当前线程一个当前返回值,必须要分清这三个。这里的应对方法是过对类型的唯一的构造函数进行分析,得到了状态与线程的字段,通过对Current属性的set方法分析得到当前返回值的字段,还有其它参数字段则通过构造函数的成员赋值中取得,缓存这些字段的token。

  第二步则要分析MoveNext方法,此时方法已经被解析为Block集合的形态了,如果未经混淆的话,其中是有规可寻的。说的详细些,先是要弄明白迭代器的工作原理,它是通过一个状态值来工作的,初始值为-2表示尚未使用,-1表示没有下一个值了并返回false,而其它正值则表示迭代器运行的次数,那么再来看看代码则是以这个状态值为中心进行了几种操作,状态比较、更改、循环、退出等等,而与之对应的则是yield return的各个值,还有yield break。考虑了很久,打算在此处增加一个类似行为树的结构,用以标榜迭代器中各个块的形态,但经过了春节的这些日子,构思的内容又忘了个干净,无奈只能取消了。

  第三步则是要制定输出规则,就要筛出状态值,对每个基本块做上标记,再根据标记将整个IL块进行重新整理并输出。这一步实际上要简单的多,要处理的结构块只有if和switch,而表达式则只需要处理返回返回值和保存返回值两种。注意这里在处理if块时有两种情况,有效块与无效块、首次赋值与再赋值,而后者会出现再赋值出现在首值前面的状况,需要颠倒输出。

 

  修正了枚举类型的返回值没有被转换对应类型的问题

  修正了枚举类型操作后没有传递operand类型导致无法自动类型转换

  修正了关键字块前无法显示goto标签的问题

posted @ 2021-03-15 10:01  ccddnet  阅读(87)  评论(1)    收藏  举报