Note that the C# longs are mapped to 64-bit entities. Furthermore
the non-checked and checked long-long multiplication is mapped to
the following two different opcodes – mul and mul.ovf.

On my Intel 32-bit machine, the above 64-bit operation cannot be
directly mapped to a hardware instruction. As we shall see shortly,
the Mono runtime emulates these operations using 32-bit
arithmetic. The emulator is implemented in C and is embedded right
within the runtime (as opposed to an external library).

Note that OP_LMUL maps to the emulator itself while OP_LMUL _OVF gets
mapped to emulator via a wrapper.

This wrapping of ovf emulator is essential to do stack unwinding in
case an exception is raised from the emulated code.

5 Internals of ICall Wrapper (CIL)

The code down below lists the runtime generated IL code that wraps
around mono_llmult _ovf . This wrapper is generated as part of
mono_marshal _get _icall _wrapper () using the method builder
interface. The handle of the wrapper so generated is of type
MonoMethodWrapper *.

It is sufficient to note that a native call is translated to the
following sequence – CEE_LDARG *, CEE_MONO _LDPTR and
CEE_CALLI . CEE_CALLI is an indirect method call and requires that a
pointer to native method be pushed on the CIL stack
apriori. CEE_MONO _LDPTR is a mono-only opcode that does just
this. (It pushes mono_llmult _ovf in our case)

Furthermore note that the ‘ptr descriptor’ – ‘2 in mono_ldptr2’ and
‘call site descriptors’ – ‘0x00000003 in calli’ in the IL code down
below are method-specific tokens through which the actual entities –
the target native pointer and method signature could be
accessed. Refer mono_method _get _wrapper _data () for the specifics.

As seen from the definition above, MonoLMF stores machine state and
are chained together (just like any other stack frame)

A MonoLMF is pushed on to a thread stack whenever a thread
transitions from Managed-to-Native code. An entry so pushed is
popped back on the way out.

Under conditions of fault in the native code, the top entry of ‘LMF
stack’ is used by the runtime to unwind through all native frames in
a single go and jump straight to the topmost managed frame of which
it knows well enough to deconstruct.

7 Internals of ICall Wrapper (Native)

The code down below lists the native code for the icall wrapper. The
generated code is typical of a managed-to-native wrapper. The prolog
pushes an LMF frame on top of LMF Stack while the epilog pops it
out. Refer mono_arch _emit _prolog () and mono_arch _emit _epilog () for
additional details.

As an aside, an interested reader can note the following –

Variable that contains the current LMF is accessed through the GS
register – indicating thread specific storage.

The basic block containing mono_not _taken is offlined.

Components parts of all compiled methods – A prolog and a
matching epilog in addition to the method body.