I have a recursive function emit : Map<string,LocalBuilder> -> exp -> unit, where it il : ILGeneratoris global for the function, and expthis is a discriminant union representing the type being analyzed with an argument InstanceCall of exp * MethodInfo * exp list * Typeand Typeis a property on exprepresenting the type of expression.
In the following snippet, I try to emit IL code codes to invoke an instance where it instance.Typemay or may not be ValueType. Therefore, I understand that I can use OpCodes.Constrainedflexible and efficiently create virtual calls by types of links, values and enumerations. I am new to Reflection.Emit and machine languages in general, so understanding the related documentation OpCodes.Constrainedis not very strong for me.
Here is my attempt, but this leads to VerificationException, "Operation can destabilize runtime."
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)
...
Looking at the docs, I think that the key could be "A managed pointer, ptr, is pushed onto the stack. The ptr type must be a managed pointer (&) to this type. Note that this is different from the case of an unprepared callvirt statement that expects a link to this type. "
Update
@Tomas @desco, , OpCodes.Constrained (instance.Type ValueType, methodInfo.DeclaringType ).
, , : 6 , , ( DLR , , ilasm.exe #, ).
:
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)
...