On 30.03.2011 09:47, Mort wrote:
> Not sure if this is related to mono-cecil as I may be trying to do
> something that can't be done in IL.
> ...
> I can't get it to work. I think this is because the address was loaded
> using 'ldloca 0' and I can't actually store this address to a
> VariableDefinition. I've look in Cecil and can't see anyway to create
> a local variable for an address type. So is this possible? I suspect
> I'm trying to do something that is not possible in IL. I guess
> parameters can be passed by ref but VariableDefinitions can't do this.
The result of an address-loading instruction is a managed pointer (e.g.
int&). Cecil represents those using "ByReferenceType". And yes, it is
perfectly valid IL to store managed pointers in local variables. I think
C++/CLI does this for interior_ptr<T>. C# uses them for "ref" and "out"
parameters.
> By the way the reason I'm doing this is to make in-lining the method
> easier. To replace a 'call' it pops each parameter from the evaluation
> stack into a new temporary local, then maps each 'ldarg' instruction
> in the call method to 'ldloc' instructions. It also handles any
> 'ldarga' instructions as well.
>
> However this technique doesn't work with structures as these are
> loaded via their address and accessed in the method using 'ldarg'. So
> I need to a better way to do this.
The above will work fine with structs. You just need to use a managed
pointer (ByReferenceType) for the variable representing the this argument.
> Is what I'm doing valid in terms of IL. I think I need an instructions
> such as 'stloca' which would store the address of an item into a local
> but that doesn't exist so I guessing this is not the way IL should be
> used. I did find 'cpobj', 'ldobj' which I'm wondering if they could be
> used. Alternatively do I need to 'box' the type first?
I'm not aware that cpobj is used by the C# compiler, but 'ldobj',
'stobj' etc. are definitely being used (mostly for accessing by-ref
arguments - including the 'this' parameter on structs).
> Its strange that an address can be loaded using 'ldloca' and then used
> inside a method by calling 'ldarg' so there must be some internal
> mechanic that allows a load instruction to use an address but is there
> a way to store an address to a local var rather than an argument.
No, it's not strange at all. Compare with C:
void someMethod(int* ptr) {
   doSomething(ptr);
}
void test() {
   int local = 1;
   someMethod(&ptr);
}
Only when loading the address of the local (&ptr), there's an
address-loading instruction (&-operator in C, ldloca in IL). The
parameter then holds the address, and loading it with ldarg will return
the address. If the IL code used ldarga, you would get a "int**" pointer
in the C analogy (I think it would be an "int&&" managed pointer in IL).
> So mono.cecil has the 'ThisParameter' on the method body, but I can't
> find any properties that show the parameter will be passed by address.
> Can I assume that IL only every loads the address of structures for
> the 'this' parameter (which would make sense)?
Yes, I think the "this" argument for value types is always passed by
reference.
You should be able to handle it exactly as for reference types: ldarg
becomes ldloc, starg becomes stloc, and ldarga becomes ldloca. Only when
declaring the local variable, you need to take care to use a
ByReferenceType of the method's declaring type, if the declaring type is
a value type.

Basically, for reference types, "void M()" is the same as "static void
M(DeclaringType _this)".
And for value types, "void M()" is the same as "static void M(ref
DeclaringType _this)".

Daniel

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to