Search code examples
.netmultithreadingatomiccil

Are MSIL opcodes atomic?


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?


Solution

  • No, not all opcodes are atomic. For example, if you use stloc or ldloc for 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:

    A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size (the size of type native int) is atomic (see §12.6.2) when all the write accesses to a location are the same size. Atomic writes shall alter no bits other than those written.

    ... but then there's a note:

    [Note: There is no guaranteed atomic access to 8-byte data when the size of a native int is 32 bits even though some implementations might perform atomic operations when the data is aligned on an 8-byte boundary. end note]

    So that means any op code storing or reading an Int64 isn't guaranteed to be atomic on x86, for example...