- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个递归函数 emit : Map<string,LocalBuilder> -> exp -> unit
哪里il : ILGenerator
对函数来说是全局的,并且 exp
是一个判别联合,表示带有大小写 InstanceCall of exp * MethodInfo * exp list * Type
的类型检查的解析语言和 Type
是 exp
上的属性(property)表示表达式的类型。
在下面的片段中,我试图为一个实例调用发出 IL 操作码,其中 instance.Type
可能是也可能不是 ValueType
.所以我知道我可以使用 OpCodes.Constrained
灵活高效地对引用、值和枚举类型进行虚拟调用。我是 Reflection.Emit 和机器语言的新手,所以了解 OpCodes.Constrained
的链接文档对我来说不强。
这是我的尝试,但结果是 VerificationException
, "操作可能会破坏运行时的稳定性。":
let rec emit lenv ast =
match ast with
...
| InstanceCall(instance,methodInfo,args,_) ->
instance::args |> List.iter (emit lenv)
il.Emit(OpCodes.Constrained, instance.Type)
il.Emit(OpCodes.Callvirt, methodInfo)
...
OpCodes.Constrained
(
instance.Type
是 ValueType,但
methodInfo.DeclaringType
是引用类型)。
let rec emit lenv ast =
match ast with
| Int32(x,_) ->
il.Emit(OpCodes.Ldc_I4, x)
...
| InstanceCall(instance,methodInfo,args,_) ->
emit lenv instance
//if value type, pop, put in field, then load the field address
if instance.Type.IsValueType then
let loc = il.DeclareLocal(instance.Type)
il.Emit(OpCodes.Stloc, loc)
il.Emit(OpCodes.Ldloca, loc)
for arg in args do emit lenv arg
if instance.Type.IsValueType then
il.Emit(OpCodes.Call, methodInfo)
else
il.Emit(OpCodes.Callvirt, methodInfo)
...
最佳答案
基本上我同意 Tomas:如果您在编译时知道确切的类型,那么您可以自己发出正确的调用指令。约束前缀通常用于泛型代码
但文档也说:
The constrained opcode allows IL compilers to make a call to a virtual function in a uniform way independent of whether ptr is a value type or a reference type. Although it is intended for the case where thisType is a generic type variable, the constrained prefix also works for nongeneric types and can reduce the complexity of generating virtual calls in languages that hide the distinction between value types and reference types. ...
Using the constrained prefix also avoids potential versioning problems with value types. If the constrained prefix is not used, different IL must be emitted depending on whether or not a value type overrides a method of System.Object. For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. A versioning problem can arise in the former case if the override is later removed, and in the latter case if an override is later added.
using System;
using System.Reflection;
using System.Reflection.Emit;
public struct EvilMutableStruct
{
int i;
public override string ToString()
{
i++;
return i.ToString();
}
}
class Program
{
public static void Main()
{
var intToString = Make<int>();
var stringToString = Make<string>();
var structToString = Make<EvilMutableStruct>();
Console.WriteLine(intToString(5));
Console.WriteLine(stringToString("!!!"));
Console.WriteLine(structToString (new EvilMutableStruct()));
}
static MethodInfo ToStringMethod = new Func<string>(new object().ToString).Method;
static MethodInfo ConcatMethod = new Func<string, string, string>(String.Concat).Method;
// x => x.ToString() + x.ToString()
private static Func<T, string> Make<T>()
{
var dynamicMethod = new DynamicMethod("ToString", typeof(string), new[] {typeof(T)});
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Constrained, typeof(T));
il.Emit(OpCodes.Callvirt, ToStringMethod);
il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Constrained, typeof(T));
il.Emit(OpCodes.Callvirt, ToStringMethod);
il.Emit(OpCodes.Call, ConcatMethod);
il.Emit(OpCodes.Ret);
return (Func<T, string>)dynamicMethod.CreateDelegate(typeof(Func<T, string>));
}
}
55
!!!!!!
12
关于.net - 鉴于我手头有所需的 MethodInfo 和实例类型,如何使用 OpCodes.Callvirt 发出 OpCodes.Constrained,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6884149/
我试图了解 CLR 如何实现引用类型和多态性。我提到了 Don Box 的 Essential .Net Vol 1,它对校准大部分内容有很大帮助。但是当我尝试使用一些 IL 代码以更好地理解时,我被
CIL 指令“Call”和“Callvirt”有什么区别? 最佳答案 当运行时执行call指令时,它会调用一段确切的代码(方法)。毫无疑问它存在于何处。 IL 经过 JIT 处理后,调用站点生成的机器
是 il.EmitCall(OpCodes.Callvirt, getter, null); 等同于: 到 il.Emit(OpCodes.Callvirt,getter); 我不确定如何检查动态生成
如何确定一个方法是否需要使用“Call”或“Callvirt”来调用? 最佳答案 您可以一一遵循这些简单的规则来确定您应该使用哪一个: 方法是静态的吗?然后使用调用。 您正在调用的类型是值类型吗?然后
这个问题链接到How CLR calls methods correctly hidden by derived class when reference is stored in a base cl
在这种情况下,IL 并不总是对 virtual 方法使用 callvirt 指令: class MakeMeASandwich{ public override string ToString()
向某人解释虚拟调度很容易:每个对象都有一个指向表的指针作为其数据的一部分。类上有N个虚方法。每次调用特定方法时,我都会在对象到达时对其进行索引,并调用表中的第 i 个方法。每个实现方法 X() 的类都
在 IL 的一些实验中,我试图将程序集中的 callvirt 调用更改为 call 方法。基本上发生的事情是我有一个继承链,其中包含我正在调用的成员函数。 基本上调用与此类似: ((MyDerived
给定两种方法: static void M1(Person p) { if (p != null) { var p1 = p.N
对于下面的代码片段: struct Test { public override string ToString() { return ""; } } publ
我在其基类中标记为抽象的库类上调用属性集访问器。现在在运行时我 force应用程序针对另一个版本的库运行,其中类仅实现基类的底层接口(interface),但不是从它派生的。 有趣的是,.NET 将运
为什么编译器生成一个 callvirt 指令用于调用显式实现的接口(interface)方法和一个 call 用于调用 implicilty 在以下代码中实现了接口(interface)方法? 编译器
我有几个月前编写的这个框架,它生成一个类来调用此性能服务。框架的消费者使用方法创建一个接口(interface),使用属性进行注释,并调用一个工厂方法来创建他们可以用来调用此性能服务的接口(inter
我很想知道为什么会这样。请阅读下面的代码示例以及在每个部分下面的注释中发出的相应 IL: using System; class Program { static void Main()
我有一个类: public class SomeClass { public int I; public SomeClass(int input) { I = inpu
IL 提供了两种调用函数的语句,即 call 和 callvirt。 Call 用于调用非虚拟或静态函数或编译器不想对引用进行空检查的任何函数。 callvirt 用于调用虚函数,非虚函数也被调用,因
我有一个递归函数 emit : Map -> exp -> unit哪里il : ILGenerator对函数来说是全局的,并且 exp是一个判别联合,表示带有大小写 InstanceCall of
我是一名优秀的程序员,十分优秀!