What are these opcodes for?
Asked Answered
N

2

6

Using reflector I get the following output:

.method private hidebysig static class myModelTestarea.Foo Method() cil managed
{
  .maxstack 1
  .locals init ([0] class myModelTestarea.Foo CS$1$0000)
  L_0000: nop 
  L_0001: ldc.i4.0 
  L_0002: newarr object
  L_0007: call object myModelTestarea.Program::Resolve(object[])
  L_000c: castclass myModelTestarea.Foo
  L_0011: stloc.0 
  L_0012: br.s L_0014
  L_0014: ldloc.0 
  L_0015: ret 
}

for

private static Foo Method()
{
  return (Foo)Resolve();
}

private static object Resolve( params object[] args )
{
  return new Foo();
}

What do the lines 11-14 do? I call a function and get a result (line 7). I cast the result to the right returntype (line c) - why not return right now?

Somehow, the casted result is stored as a local variable - then there is an uncoditional jump to the next line, where the local variable is loaded again. Why?

In my opinion line 11-14 and the local variable can be omitted ... ?

None answered 3/6, 2009 at 12:28 Comment(3)
FYI, my blog article on this will go up on the 11th.Saturnian
Thanks for the info ... I'll have a lookNone
Here's the link: blogs.msdn.com/ericlippert/archive/2009/06/11/…Saturnian
C
13

That looks like a DEBUG build, which leaves in extra IL to help the debugger. Try it again in RELEASE and it should look cleaner, with optimization etc.

.method private hidebysig static class program/Foo Method() cil managed
{
    .maxstack 8
    L_0000: ldc.i4.0 
    L_0001: newarr object
    L_0006: call object program::Resolve(object[])
    L_000b: castclass program/Foo
    L_0010: ret 
}
Catechu answered 3/6, 2009 at 12:29 Comment(3)
Yes, it makes perfectly sense to store the result locally for a debug build - thanksNone
Just to be clear, this is happens when building with the optimize- option, not debug+, although the default Debug build sets both.Terminable
I wish Eric's blog had come sooner ;-pCatechu
P
4

Is this a debug build? It's possible that it's there for the sake of the debugger.

I've seen similar things in other places - it's almost always harmless though. Don't forget that most of the optimisation is done by the JIT, which can notice things like this easily enough. The only downside is that more IL hints to the JIT that the method shouldn't be inlined.

Patrizius answered 3/6, 2009 at 12:31 Comment(3)
I wonder, @Jon, if you happen to know: how are these extras useful for debug? I can maybe understand storing the return value in a local variable - it allows inspecting it and possibly changing it before returning, though even that is not obvious: why would a debugger be able to work with a local variable but not with a value on the stack? And what I don't understand at all are no-ops and branching to the very next instruction: how are those useful to anything?Unhappy
@Tom: I believe no-ops allow debuggers to add breakpoints more easily, but that's only somewhat vague "knowledge" - and the fact that this isn't the JIT-compiled code obviously makes things more obscure. I'm afraid my knowledge isn't very deep on all of this.Patrizius
Thanks, @Jon. Yeah, everywhere we hear that it's for debuggers to add breakpoints, but I never understood why placing a breakpoint should be easier on a nop than on any other thing... (Now what's left is finding the answer to the ultimate question of life, the universe and everything: whom to ask when Jon Skeet doesn't know the answer...)Unhappy

© 2022 - 2024 — McMap. All rights reserved.