Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDietmar Maurer <dietmar@mono-cvs.ximian.com>2002-03-14 12:52:53 +0300
committerDietmar Maurer <dietmar@mono-cvs.ximian.com>2002-03-14 12:52:53 +0300
commit7a8a86c3b9d6f74c61f3e6ec2435e6fc78eac5ab (patch)
tree45d04f3f239c4b69dbcea816f681f6bef5202e89 /docs/unmanaged-calls
parentd4b18d1e824129bb2b556eaa2ccaa5dc72b1b6f4 (diff)
2002-03-14 Dietmar Maurer <dietmar@ximian.com>
* emit-x86.c (arch_create_native_wrapper): new code to generate wrappers for calling native functions. * icall.c (ves_icall_InternalInvoke): impl. svn path=/trunk/mono/; revision=3103
Diffstat (limited to 'docs/unmanaged-calls')
-rw-r--r--docs/unmanaged-calls122
1 files changed, 122 insertions, 0 deletions
diff --git a/docs/unmanaged-calls b/docs/unmanaged-calls
new file mode 100644
index 00000000000..944abd7d19e
--- /dev/null
+++ b/docs/unmanaged-calls
@@ -0,0 +1,122 @@
+More about PInvoke and Internal calls
+=====================================
+
+1.) What is PInvoke
+
+PInvoke stands for Platform Invoke. It is possible to call functions contained
+in native shared libraries, for example you can declare:
+
+ [DllImport("cygwin1.dll", EntryPoint="puts", CharSet=CharSet.Ansi)]
+ public static extern int puts (string name);
+
+If you then call "puts(...)" it invokes the native "puts" functions in
+"cygwin1.dll"
+
+2.) What are internal calls
+
+Some class library functions are implemented in C, because it is either not
+possible to implement them in C# or because of performance gains. Internal
+functions are contained in the mono executable itself. Here is an example form
+our array implementation:
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern int GetRank ();
+
+If you call this GetRank() function it invokes
+ves_icall_System_Array_GetRank() inside the mono runtime.
+
+2.) Runtime considerations
+
+Invoking native (unmanaged) code has several implications:
+
+- We need to handle exceptions inside unmanaged code. The JIT simply saves some
+ informations at each transition from managed to unmanaged code (in a linked
+ list), called Last Managed Frame (LMF). If an exception occurs the runtime
+ first looks if the exception was inside managed code. If not there must be a
+ LMF entry which contains all necessary information to unwind the stack.
+
+ Creation of those LMF structure clearly involves some overhead, so calling
+ into unmanaged code is not as cheap as it looks like at first glance. Maybe
+ we can introduce a special attribute to avoid the creation of LMF on internal
+ call methods that cant raise exceptions.
+
+- PInvoke has the possibility to convert argument types. For example Strings
+ are marshalled as Char*. So each String argument is translated into a
+ char*. The encoding is specified in the CharSet of the DllImport attribute.
+
+
+3.) When/how does the runtime call unmanaged PInvoke code
+
+- LDFTN, CALLI, Delegate::Invoke, Delegate::BeginInvoke: We must generate
+ wrapper code when we load the function with LDFTN, so that all arguments are
+ marshalled in the right format. We also need to save/restore the LMF.
+
+- MethodBase::Invoke (runtime invoke): We need to marshal all arguments in
+ they right format and save/restore the LMF
+
+- CALL: We need to marshal all arguments in they right format and save/restore
+ the LMF
+
+The easiest way to implement this is to always create a wrapper function for
+PInvoke calls, which takes care of argument marshalling and LMF save/restore.
+
+3.) When/how does the runtime call unmanaged internal calls
+
+We don't need to convert and arguments, so we need only take care of the LMF
+structure.
+
+- LDFTN, CALLI, Delegate::Invoke, Delegate::BeginInvoke: We must generate
+ wrapper code when we load the function with LDFTN which saves/restores the
+ LMF.
+
+- MethodBase::Invoke (runtime invoke): We need to save/restore the LMF.
+
+- CALL: We need to save/restore the LMF.
+
+- CALLVIRT (through the vtable): We must generate wrapper code to save/restore
+ the LMF.
+
+Please notice that we can call internal function with CALLVIRT, i.e. we can
+call those function through a VTable. But we cant know in advance if a vtable
+slot contains an internal call or managed code. So again it is best to generate
+a wrapper functions for internal calls in order to save/restore the LMF.
+
+Unfortunately we need to push all arguments 2 times, because we have to save
+the LMF, and the LMF is currently allocated on the stack. So the stack looks
+like:
+
+ --------------------
+ | method arguments |
+ --------------------
+ | LMF |
+ --------------------
+ | copied arguments |
+ --------------------
+
+AFAIK this is the way ORP works. Another way is to allocate the LMF not on the
+stack, but then we have additional overhead to allocate/free LMF structures
+(and another call to arch_get_lmf_addr).
+
+Maybe it is possible to avoid this addiotional copy for internal calls by
+including the LMF in the C function signature. Lets say we hav a puts()
+function which is a internal call:
+
+ves_icall_puts (MonoString *string);
+
+If we simply modify that to include the LMF we can avoid to copy all arguments:
+
+ves_icall_puts (MonoLMF lmf, MonoString *string);
+
+But this depends somehow on the calling conventions, and I don't know if that
+works on all plattforms?
+
+4.) What is stored in the LMF
+
+- all caller saved registers (since we can trust unmanaged code)
+- the instruction pointer of the last managed instruction
+- a MonoMethod pointer for the unmanaged function
+- the address of the thread local lfm_addr pointer (to avoid another call to
+ arch_get_lmf_addr when restoring LMF
+
+The LMF is allocated on the stack, so we also know the stack position for
+stack unwinding.