none
Managed to Native and Native to Managed Transition RRS feed

  • Question

  • Hello All,
    I am trying to understand CLR internals and a little confused about the transitions.
    I believe even in a pure managed code there exists transition from managed to native code and back. For example

    MessageBox.Show()

    would internally call unmanaged User32 MessageBox function and subsequent unmanaged code, so is the case with many other .NET API. So why is there a big cry about Managed to Native transitions and that such transitions are slow? Or is that in this case the CLR does some trick so that Managed to Native transitions and vice-versa itself do not happen?

    Thanks

    Tuesday, March 24, 2009 1:11 PM

Answers

  • A "transition" in C++ interop is not expensive, it costs about 10 CPU cycles.  All it has to do is write a special cookie on the stack to prevent the garbage collector from blundering into unmanaged stack frames.  Using P/Invoke is a bit more expensive, it has to setup an SEH exception handler so that unmanaged exceptions can be translated into managed exceptions.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Tuesday, March 24, 2009 1:48 PM
    Moderator
  • C++ Interop is a feature of the compiler, not the framework.  Only the compiler knows when unmanaged code is being called.  I never did find the P/Invoke marshaller in the Rotor source code.  I suspect it isn't there, Rotor is a watered-down version of the CLR.  Concurrent garbage collection isn't in there either.  And by definition, the marshaller is platform specific.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Tuesday, March 24, 2009 5:08 PM
    Moderator
  • I wrote some C++/CLI code that invoked unmanaged code, looked at it with the debugger in native mode.  Use __debugbreak() to get a breakpoint in managed code.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Thursday, March 26, 2009 10:41 AM
    Moderator
  • P/Invoke stuff is in ml.h/cpp, mlcache.h/cpp, dllimport.h/cpp, etc in the /clr/src/vm folder in rooter.  They use this marshal language stuff for making unmanaged calls I guess?  If you look at at ML.H they have a page+ of comments at the top that explains how it works.  

    If you look at a .net asembly in dependency walker or something you won't see anything in the import table.  In the clr method metadata table a p/invoke function will have 0 for rva and an entry in ImplMap table.  This ImplMap has the imported method name and index to module ref table for the library containing method.  I guess it uses the ML stuff to create a stub at runtime to invoke the method.  

    IJW works differently though.  I read somewhere that the entry in the method metadata table will have a rva and compiler will generate some machine specific code to invoke the unmanaged method.  The metadata table points to some machine code instead of IL.  


    • Marked as answer by RadiumBall Friday, March 27, 2009 5:32 PM
    Friday, March 27, 2009 8:24 AM

All replies

  • Well crossing the managed/native boundary certainly is more expensive than staying all in managed code. So you may not want to do it in a tight loop in performance critical code.

    But compared to all the work required to initialize and show a message box, that overhead is negligible.

    Mattias, C# MVP
    Tuesday, March 24, 2009 1:34 PM
    Moderator
  • A "transition" in C++ interop is not expensive, it costs about 10 CPU cycles.  All it has to do is write a special cookie on the stack to prevent the garbage collector from blundering into unmanaged stack frames.  Using P/Invoke is a bit more expensive, it has to setup an SEH exception handler so that unmanaged exceptions can be translated into managed exceptions.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Tuesday, March 24, 2009 1:48 PM
    Moderator
  • Thank Again Hans,
    So as I understand there seems to be some trick indeed in the way CLR implements unmanaged code for .NET API so that the transitions are faster.

    Could you please point out where exactly is such a cookie added in the ROTOR SSCLI 2.0 or where does the transition take place between the managed code and the unmanaged code ?

    Thanks Again
    Tuesday, March 24, 2009 4:40 PM
  • C++ Interop is a feature of the compiler, not the framework.  Only the compiler knows when unmanaged code is being called.  I never did find the P/Invoke marshaller in the Rotor source code.  I suspect it isn't there, Rotor is a watered-down version of the CLR.  Concurrent garbage collection isn't in there either.  And by definition, the marshaller is platform specific.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Tuesday, March 24, 2009 5:08 PM
    Moderator
  • Hello Hans,
    This is for my curiosity, how do you that the "transition in C++ interop is not expensive, that it costs about 10 CPU cycles" ?

    Thanks again.
    Thursday, March 26, 2009 10:37 AM
  • I wrote some C++/CLI code that invoked unmanaged code, looked at it with the debugger in native mode.  Use __debugbreak() to get a breakpoint in managed code.
    Hans Passant.
    • Marked as answer by RadiumBall Thursday, March 26, 2009 10:56 AM
    Thursday, March 26, 2009 10:41 AM
    Moderator
  • P/Invoke stuff is in ml.h/cpp, mlcache.h/cpp, dllimport.h/cpp, etc in the /clr/src/vm folder in rooter.  They use this marshal language stuff for making unmanaged calls I guess?  If you look at at ML.H they have a page+ of comments at the top that explains how it works.  

    If you look at a .net asembly in dependency walker or something you won't see anything in the import table.  In the clr method metadata table a p/invoke function will have 0 for rva and an entry in ImplMap table.  This ImplMap has the imported method name and index to module ref table for the library containing method.  I guess it uses the ML stuff to create a stub at runtime to invoke the method.  

    IJW works differently though.  I read somewhere that the entry in the method metadata table will have a rva and compiler will generate some machine specific code to invoke the unmanaged method.  The metadata table points to some machine code instead of IL.  


    • Marked as answer by RadiumBall Friday, March 27, 2009 5:32 PM
    Friday, March 27, 2009 8:24 AM