I was playing a bit with the MSIL decompiler – ILDASM and I tried to decompile a simple .NET method.
The opcodes looked somehow like this:
.method private hidebysig static int32 Add(int32 a,
int32 b) cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init ([0] int32 c,
[1] int32 d,
[2] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.5
IL_0003: add
IL_0004: stloc.0
IL_0005: ldarg.1
IL_0006: ldc.i4.s 10
IL_0008: add
IL_0009: stloc.1
IL_000a: ldloc.0
IL_000b: ldloc.1
IL_000c: add
IL_000d: stloc.2
IL_000e: br.s IL_0010
IL_0010: ldloc.2
IL_0011: ret
}
What I’m wondering is – are these opcodes atomic? i.e In a preemptive scheduling kernel, is it possible for a single opcode to be preempted before it finishes execution? The opcode in here could be easily mapped to asm instructions pretty much 1:1, as they have separate opcodes for loads, stores, add, etc.
But what in case of a more complex opcodes? like “call”, when the operand is a method-reference token that should first be followed to resolve the method and then called? is that atomic too?
No, not all opcodes are atomic. For example, if you use
stlocorldlocfor value types which are larger than the native pointer size, that’s not guaranteed to be atomic.Section 12.6.6 of ECMA 335 guarantees this much:
… but then there’s a note:
So that means any op code storing or reading an
Int64isn’t guaranteed to be atomic on x86, for example…