Is it possible to use Reflection.Emit for the opcodes stelem.any and ldelem.any?
Asked Answered
D

2

8

So, I recently did some experimenting and discovered that it appears that Reflection.Emit doesn't support all of the opcodes in the ECMA spec. There are 3 opcodes missing:

  • ldelem.any
  • stelem.any
  • no. (prefix)

Are these opcodes just not supported in the Reflection API, or is there some way to generate them or something?

Day answered 21/11, 2012 at 16:23 Comment(10)
I am pretty sure it is. Let me check ;pUppermost
@Uppermost those opcodes aren't in the OpCodes collectionDay
Unbox_Any is there ;p Edit: In v4 at leastUppermost
BTW, it would be impossible to create an open generic method with DynamicMethod.Uppermost
@Uppermost oh wow. Well, the only opcodes that appear to be missing then are stelem_any and ldelem_any... Oh and the no. prefixDay
I rephrased the question to better reflect what I want to knowDay
The obvious solution would be to use Mono.Cecil for code generation then ;p Not sure how well it can integrate with dynamic assemblies though (assumption due to dynamicmethod tag).Uppermost
I'm still intrigued by the actual problem. The best way to go would be to add your own instance of OpCode. However, when I spy in the code, I see there is an internal constructor. However, when I try to reflect to that constructor from the type, it doesn't show op...Janycejanyte
@RenéWolferink it's not possible. It's a struct as well as all of it's (modifiable) members being internal. I tried using reflection to inject my own values into it, but I could never get it to actually behave as expectedDay
Just in case you were wondering stelem translates to stelem.any, and any doesn't mean store anything you like. It means that I can specify the type I'm sending in and it might be a struct or it might be a reference, hence any.Frowzy
C
1

Actually, you can.

There is a wonderful walkthrough at http://msdn.microsoft.com/en-us/library/4xxf1410.aspx

Two essential parts are:

Create the generic parameters:

string[] typeParamNames = {"TFirst", "TSecond"};
GenericTypeParameterBuilder[] typeParams = 
    myType.DefineGenericParameters(typeParamNames);

GenericTypeParameterBuilder TFirst = typeParams[0];
GenericTypeParameterBuilder TSecond = typeParams[1];

Then create the method:

Type listOf = typeof(List<>);
Type listOfTFirst = listOf.MakeGenericType(TFirst);
Type[] mParamTypes = {TFirst.MakeArrayType()};

MethodBuilder exMethod = 
    myType.DefineMethod("ExampleMethod", 
        MethodAttributes.Public | MethodAttributes.Static, 
        listOfTFirst, 
        mParamTypes);

However, you should go through it entirely, as the generic parameters are used in so many different ways and sections (on the method, on the parameters, as result types, when invoking, ...).

-update- and if you want the .NET 2 specific version: http://msdn.microsoft.com/en-us/library/4xxf1410%28v=vs.80%29.aspx

The dropdown on the page lets you select many versions of the framework in which you can do it.

Cowes answered 21/11, 2012 at 16:31 Comment(1)
@IllidanS4 I answered this question before the edit. It probably doesn't quite answer the question as it stands now, but hopefully it's still useful for some people, so I'm not keen to remove it. Given I answered it more than 3 years ago, I have no idea what my thought process was at that time.Janycejanyte
F
0

I placed a comment about this but the OpCode.Stelem instruction at least in .net 4 translate sto a stelem.any

See it use to be the case that you had to encode the type you were storing in the array and for the primitives there was the various stelem.* opcodes. If you were storing a reference type (something which declared as a delegate or a class) you would use stelem.Ref and you would use Stelem (myType) for value types (something which is declared as a struct or an enum).

However, with the advent of generics there came the type parameter and it could be anything it wanted. T could be a reference type or it could be a value type. So stelem.any is born to handle this unusual case. But you might say, I can only store an unboxed T into a T array so its entirely pointless, can't we just rely on the type of the array?

Well the array's type might also be generic, which would make things rather difficult. But more importantly its converse operation also helps verify the next operation.

ldarg.0
ldc.i4.0
ldelem.any !!T

Tells the verifier that the next instruction after this stack transition should be operated upon an unboxed T which is the generic methods parameter.

Frowzy answered 12/1, 2013 at 19:14 Comment(1)
None of this tells me if you can do this with reflection.emit, you explained why ldelem.any was added, but not how does one do this with reflection.emit.Mortification

© 2022 - 2024 — McMap. All rights reserved.