-
-
Save mletterle/2177221 to your computer and use it in GitHub Desktop.
.assembly Test { } | |
.class public TestClass | |
extends [mscorlib]System.Object | |
{ | |
.method specialname static public void Main() cil managed | |
{ | |
.entrypoint | |
newobj instance void AnotherClass2::.ctor() | |
dup | |
callvirt instance void AnotherClass::Method(class AnotherClass) | |
ret | |
} | |
} | |
.class public AnotherClass | |
extends [mscorlib]System.Object | |
{ | |
.method specialname rtspecialname public instance void .ctor() cil managed | |
{ | |
ldarg.0 | |
call instance void [mscorlib]System.Object::.ctor() | |
ret | |
} | |
.method public void Method(class AnotherClass a) cil managed | |
{ | |
ldarg.1 | |
call instance string AnotherClass::Something() | |
call void [mscorlib]System.Console::WriteLine(string) | |
ret | |
} | |
.method public instance string Something() cil managed | |
{ | |
ldstr "AnotherClass" | |
ret | |
} | |
} | |
.class public AnotherClass2 | |
extends [mscorlib]System.Object | |
{ | |
.method specialname rtspecialname public instance void .ctor() cil managed | |
{ | |
ldarg.0 | |
call instance void [mscorlib]System.Object::.ctor() | |
ret | |
} | |
} | |
Being an instance method, shouldn't it be using the instance on the top of the stack? This object has a different type then the method signature being called. And the object being passed in is also AnotherClass2, which doesn't match the type of the parameter. I'd expect that the CLR would actually refuse to load the assembly with an Invalid Program exception since it violates the spec for callvirt calls (Correct CIL should have the types matching).
I see your point now. I don't know the specifications of .NET CLR for such a case, but it would make sense if it terminates with error. It could also let it flow and check the method table and then terminate when it can't find the implementation on the object's method table. Did you try to compile it?
Oh yes. It doesn't peverify, of course, but it's quite happy to run. It outputs "AnotherClass". It actually does this on both .NET and Mono, which kind of surprised me. Luckily it does sanely break down if you try to save the result of Something() to an instance field. So there's that...
Then it looks like it's following an approach similar to the second case I wrote above. As long as they can pass the method table, they continue flowing.
Did you generate it by hand, or it's a part of a program you're writing. I'm curious to know what scenario this is representing.
It's written by hand. Kinda stumbled over the fact that the runtime doesn't actually seem to enforce the type correctness of arguments being passed to methods, and just eventually got here.
Yes, in most languages most of the type checking usually occurs in previous steps of compilation before generating the IL code, so for efficiency reasons of compilation, it's not redone. .NET would be the same.
It's a virtual method dispatch on AnotherClass so it goes on the method table for AnotherClass and finds the corresponding method implementation and executes that. I still don't know what exactly you meant by your original question since AnotherClass2 is totally independent of AnotherClass. dup, of course, duplicates the top item on stack, but again, I don't know what you're exactly looking for.