Click here to Skip to main content
15,892,005 members
Home / Discussions / C#
   

C#

 
AnswerRe: Sending mail from yahoo thru application Pin
Bernhard Hiller26-Feb-10 2:22
Bernhard Hiller26-Feb-10 2:22 
QuestionGeneric List Pin
spankyleo12325-Feb-10 23:51
spankyleo12325-Feb-10 23:51 
AnswerRe: Generic List Pin
Pete O'Hanlon25-Feb-10 23:57
mvePete O'Hanlon25-Feb-10 23:57 
GeneralRe: Generic List [modified] Pin
spankyleo12326-Feb-10 0:12
spankyleo12326-Feb-10 0:12 
GeneralRe: Generic List Pin
Paulo Zemek26-Feb-10 1:47
mvaPaulo Zemek26-Feb-10 1:47 
GeneralRe: Generic List Pin
Pete O'Hanlon26-Feb-10 1:56
mvePete O'Hanlon26-Feb-10 1:56 
GeneralRe: Generic List Pin
Searril26-Feb-10 4:38
Searril26-Feb-10 4:38 
Question[SOLVED] I can't figure out EmitCalli of ILGenerator [modified] Pin
blackblizzard25-Feb-10 23:24
blackblizzard25-Feb-10 23:24 
Hi everyone.
I'm having serious trouble with method EmitCalli of ILGenerator. I've created a simple class to illustrate what I'd like to do:

class TestClass {

    public delegate Object DirectReadAccessor(TestClass firstArgument);
    
    DirectReadAccessor[] directReadAccessors;

    public Object directRead(int index) {
        return directReadAccessors[index](this);
    }

}


As you can see, I have an array of delegates, and by calling directRead(i) I call the the i-th delegate with this as a parameter. Fairly simple.
I'd like to generate the method directRead with Emit. I compile this and see the following IL code:

.method public hidebysig instance object directRead(int32 fieldIndex) cil managed
{
    .maxstack 2
    .locals init (
        [0] object CS$1$0000)
--> L_0000: nop
    L_0001: ldarg.0
    L_0002: ldfld class TestClass.TestClass/DirectReadAccessor[] TestClass.TestClass::directReadAccessors
    L_0007: ldarg.1
    L_0008: ldelem.ref
    L_0009: ldarg.0
    L_000a: callvirt instance object TestClass.TestClass/DirectReadAccessor::Invoke(class TestClass.TestClass)
--> L_000f: stloc.0
--> L_0010: br.s L_0012
--> L_0012: ldloc.0
    L_0013: ret
}

(where you can just ignore the lines pointed with -->)
I see that it uses callvirt on method Invoke, instead of using calli as was my first instinct. I have the notion that calli would be more efficient, though I may be wrong (please let me know what you think about that). So I try to use calli instead.

I read that Calli follows this process:
1. Method arguments arg1 through argN are pushed onto the stack.
2. The method entry pointer is pushed onto the stack.
3. Method arguments arg1 through argN and the method entry pointer are popped from the stack; the call to the method is performed. When complete, a return value is generated by the callee method and sent to the caller.
4. The return value is pushed onto the stack.

So here was my first attempt:

// Push <this> onto the stack, as an argument for directReadAccessors[fieldIndex].
ilGenerator.Emit(OpCodes.Ldarg_0);
// Push <this> onto the stack.
ilGenerator.Emit(OpCodes.Ldarg_0);
// Pop <this> and push field directReadAccessors.
ilGenerator.Emit(OpCodes.Ldfld, directReadAccField);
// Push fieldIndex.
ilGenerator.Emit(OpCodes.Ldarg_1);
// Pop directReadAccessors and fieldIndex and push directReadAccessors[fieldIndex].
ilGenerator.Emit(OpCodes.Ldelem, typeof(DirectReadAccessor));
// Call the method currently on the top of the stack (directReadAccessors[fieldIndex]).
ilGenerator.EmitCalli(OpCodes.Calli,
    CallingConventions.Standard | CallingConventions.HasThis,
    typeof(Object),
    new Type[] { typeof(TestClass) },
    null);
// Return.
ilGenerator.Emit(OpCodes.Ret);


This generates the following IL, which apparently isn't valid and can't even be translated back to C#:
.method public instance object directRead(int32) cil managed
{
    .maxstack 3
    L_0000: ldarg.0
    L_0001: ldarg.0
    L_0002: ldfld class [TestClass]TestClass/DirectReadAccessor[] EXT_IdPoolImpl::directReadAccessors
    L_0007: ldarg.1
    L_0008: ldelem.any [TestClass]TestClass/DirectReadAccessor
    L_000d: calli method instance object *(class [TestClass]TestClass)
    L_0012: ret
}


Seeing that the generated code used ldelem.ref instead of ldelem.any, as I had done with Emit, I changed to ldelem.ref as well:

// Push <this> onto the stack, as an argument for directReadAccessors[fieldIndex].
ilGenerator.Emit(OpCodes.Ldarg_0);
// Push <this> onto the stack.
ilGenerator.Emit(OpCodes.Ldarg_0);
// Pop <this> and push field directReadAccessors.
ilGenerator.Emit(OpCodes.Ldfld, directReadAccField);
// Push fieldIndex.
ilGenerator.Emit(OpCodes.Ldarg_1);
// Pop directReadAccessors and fieldIndex and push directReadAccessors[fieldIndex].
ilGenerator.Emit(OpCodes.Ldelem_Ref);
// Call the method currently on the top of the stack (directReadAccessors[fieldIndex]).
ilGenerator.EmitCalli(OpCodes.Calli,
    CallingConventions.Standard | CallingConventions.HasThis,
    typeof(Object),
    new Type[] { typeof(TestClass) },
    null);
// Return.
ilGenerator.Emit(OpCodes.Ret);


I get this:

.method public instance object directRead(int32) cil managed
{
    .maxstack 3
    L_0000: ldarg.0
    L_0001: ldarg.0
    L_0002: ldfld class [TestClass]TestClass/DirectReadAccessor[] EXT_IdPoolImpl::directReadAccessors
    L_0007: ldarg.1
    L_0008: ldelem.ref
    L_0009: calli method instance object *(class [TestClass]TestClass)
    L_000e: ret
}


But still no luck.
Then, although it seems to contradict the instructions above (the steps followed by calli) I tried moving my first Ldarg_0 to just before calli, to mimic what is done with callvirt:

.method public instance object directRead(int32) cil managed
{
    .maxstack 2
    L_0000: ldarg.0
    L_0001: ldfld class [TestClass]TestClass/DirectReadAccessor[] EXT_IdPoolImpl::directReadAccessors
    L_0006: ldarg.1
    L_0007: ldelem.ref
    L_0008: ldarg.0
    L_0009: calli method instance object *(class [TestClass]TestClass)
    L_000e: ret
}


But nothing.
I can use callvirt and the code works, but I'd like to know how to use calli, if not for performance just for the sake of knowledge Wink | ;)
Can anyone explain?
Thanks a lot, and sorry for the lengthy post.
modified on Friday, March 5, 2010 3:23 AM

AnswerRe: I can't figure out EmitCalli of ILGenerator Pin
Kythen26-Feb-10 13:08
Kythen26-Feb-10 13:08 
Question[SOLVED] How can I emit a call to a delegate whose type is unfinished at the time of the emit? [modified] Pin
blackblizzard28-Feb-10 6:28
blackblizzard28-Feb-10 6:28 
AnswerRe: How can I emit a call to a delegate whose type is unfinished at the time of the emit? Pin
blackblizzard4-Mar-10 21:23
blackblizzard4-Mar-10 21:23 
QuestionWebbrowser Control - selected Image Pin
hoernchenmeister25-Feb-10 21:25
hoernchenmeister25-Feb-10 21:25 
QuestionHow to Read a .doc in C# Pin
gouthami chintala25-Feb-10 20:48
gouthami chintala25-Feb-10 20:48 
AnswerMessage Removed Pin
25-Feb-10 20:50
stancrm25-Feb-10 20:50 
GeneralMessage Removed Pin
26-Feb-10 2:34
gouthami chintala26-Feb-10 2:34 
GeneralRe: How to Read a .doc in C# Pin
Dave Kreskowiak26-Feb-10 3:26
mveDave Kreskowiak26-Feb-10 3:26 
AnswerRe: How to Read a .doc in C# Pin
Mohammad Dayyan25-Feb-10 20:53
Mohammad Dayyan25-Feb-10 20:53 
AnswerRe: How to Read a .doc in C# Pin
Saksida Bojan25-Feb-10 21:03
Saksida Bojan25-Feb-10 21:03 
AnswerRe: How to Read a .doc in C# Pin
Kythen26-Feb-10 12:34
Kythen26-Feb-10 12:34 
QuestionCrystal Report XI issue Pin
Raza Hussain25-Feb-10 20:47
Raza Hussain25-Feb-10 20:47 
AnswerRe: Crystal Report XI issue Pin
Mohammad Dayyan25-Feb-10 20:57
Mohammad Dayyan25-Feb-10 20:57 
GeneralRe: Crystal Report XI issue Pin
Raza Hussain28-Feb-10 23:11
Raza Hussain28-Feb-10 23:11 
Questionblood Pressure Pin
Jassim Rahma25-Feb-10 20:44
Jassim Rahma25-Feb-10 20:44 
AnswerMessage Closed Pin
25-Feb-10 20:53
stancrm25-Feb-10 20:53 
GeneralRe: blood Pressure Pin
Jassim Rahma25-Feb-10 20:56
Jassim Rahma25-Feb-10 20:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.