Reflection.Emit 中的短格式操作码错误

Posted

技术标签:

【中文标题】Reflection.Emit 中的短格式操作码错误【英文标题】:Error with short form opcodes in Reflection.Emit 【发布时间】:2010-08-12 16:12:03 【问题描述】:

我正在制作一种与hlsl 非常相似但仅支持像素着色器的小型语言。该语言使用reflection.emit 构建实现相同功能的.NET 程序集。我目前正在测试我的分支指令if 的实现,并且在我的一个单元测试(一个大的if 和内部if/elses)中失败并出现以下错误消息:

System.NotSupportedException : 在位置非法的一字节分支:32。请求的分支是:132。

在我的案例OpCodes.Br_S 中,我已将问题追溯到使用短格式指令。解决方案很简单,我已将 OpCodes.Br_S 替换为 OpCodes.Br 但是我对此解决方案有几个问题:

这个解决方案对生成代码的性能有影响吗?

如果我想为单字节正确生成Br_S,为其他情况正确生成Br,我该怎么做?这里的问题是我正在使用访问者模式,对于像if 这样的分支指令,我必须首先输出BrBr_s,此时,我无法知道剩余的代码是否会需要多个字节才能跳转到标签。为了更好地说明我的问题,这是我为以下语句生成的代码:

我的语言:

int a = -1; if (1>1)  a=1;  else if (2>2)  a=2; 

IL:

.method public virtual final instance int32 Main() cil managed


    .maxstack 4
    .locals init (
        [0] int32 num)
    L_0000: ldc.i4.m1 
    L_0001: stloc.0 
    L_0002: ldc.i4.1 
    L_0003: ldc.i4.1 
    L_0004: ble.s L_000a
    L_0006: ldc.i4.1 
    L_0007: stloc.0 
    L_0008: br.s L_0010
    L_000a: ldc.i4.2 
    L_000b: ldc.i4.2 
    L_000c: ble.s L_0010
    L_000e: ldc.i4.2 
    L_000f: stloc.0 
    L_0010: ldloc.0 
    L_0011: ret 

在这种情况下,我使用两个简短的指令 ble.sbr.s 来实现 ifs,就像 .NET 编译器所做的那样。但是.NET编译器可以根据情况选择br.sbr,我的问题是我该怎么做类似的事情?

Tnk

【问题讨论】:

你的 IL 有点大,没什么大不了的。相信 JIT 编译器可以做到这一点。这些微优化不值得你花时间。 我想这样做,但我需要自己生成 IL,因为例如 silverlight 中没有 c# 编译器。我想在 silverlight 以及其他没有可用编译器的环境中使用它...... 我相信 Hans 建议您不要使用短格式(您遇到问题)并使用标准的长格式,因为这种优化将自动发生在 JIT(其中Silverlight 有,就像任何其他 CLR impl) 嗯?这很奇怪......如果是这样的话,为什么会有两个不同的操作码?如果 Jit 编译器足够聪明,可以进行这种优化,我就无法真正理解操作码的简短版本。任何人都知道它们为什么存在吗?还有很多库明确地处理类似的情况,例如他们做这样的事情 if (index 【参考方案1】:

如果您想这样做,您需要在生成分支本身之前计算到分支目标的偏移量,然后确定偏移量是否小到足以让短格式指令达到。我认为使用Reflection.Emit 库没有特别简单的方法。

【讨论】:

拜托,我有兴趣了解此回复。我有一个类似的问题。你在说什么节日?你能用某种插图解释一下吗?您还可以向我指出我可以从中受益的其他资源。提前致谢。 @ColourBlend - 分支指令有一个目标,该目标在 IL 代码中指定为偏移量,即使 ILGenerator API 允许您只传入一个标签(并且框架会根据标签所在的位置)。 Br_S(和其他短指令)要求偏移量可以放入一个字节(即指令流中的偏移量不超过 127 个字节)。这有帮助吗? 谢谢。这很有帮助。不过,在你回复之前,我调查了一下。 DynamicMethod 的运行速度是否比等效的静态方法(设计时方法)快?将设计时方法转换为 MSIL 会提高性能吗? 我目前正在为存储过程开发小型数据访问映射器。我有一个具有大部分基本功能的工作版本。我想优化它的性能,我想知道您是否可以提供帮助。 @ColourBlend - 我的建议是以两种方式实现事物并分析它们以查看哪个更快。如果您有具体问题,最好在这里提出一个新问题,而不是在 cmets 中提问。

以上是关于Reflection.Emit 中的短格式操作码错误的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Reflection.Emit 注入文字表达式?

System.Reflection.Emit 动态实现接口

[1]System.Reflection.Emit

Protobuf-net & IL2CPP - System.Reflection.Emit 不受支持

反射-Emit

Matlab - 情节标题中数字变量的短格式