Compact Framework OpCode Support in a Nutshell
While the stated goal of this blog is to address issues that affect the day-to-day work of most developers, from time to time I'll publish something for the propeller-heads in the audience. This is one of those times.
Introduction
The instruction set for a CLI compliant execution engine is described by ECMA's CLI Partition III (CIL Instruction Set). The Compact Framework execution engine implementation supports most, but not all, of these instructions. In general, the decision to support an opcode was based on whether it could be generated by one of the compilers supported by CF (C# and Visual Basic, at this time).
Unsupported instructions for v2
An unsupported instruction or prefix is one that will cause an InvalidProgramException if it is encountered by the execution engine. This is in contrast to an instruction or prefix that is simply ignored by the execution engine. CF 1.x had 7 unsupported instructions and 3 unsupported prefixes. CF 2.0 has 7 unsupported instructions and 2 unsupported prefixes. In addition, CF 2.0 has 1 new instruction and 3 new prefixes.
The unsupported instructions in CF 2.0 fall into four categories:
[Edited to fix table layout]
Category | Instructions |
---|---|
indirect function calls |
|
variable-length argument list support |
|
local dynamic memory allocation |
|
prefixes |
|
The calli
, arglist
, mkrefany
, refanyval
, and refanytype
instructions are used to support features of Managed C++. calli
supports the closely coupled native/managed interop done by managed C++. The other four instructions are primarily used in the MC++ varargs implementation. Since CF doesn't support MC++, these instructions were left out.
The localloc
instruction is used to allocate bytes from the local memory pool. It's use is similar to that of the standard C runtime alloca()
function. It wasn't implemented because, while it can be generated by the C# compiler, it isn't widely used and can be easily avoided.
The unaligned.
and tail.
prefixes were omitted because CF doesn't have any customer scenarios that require them.
New instructions for v2
The unbox.any
instruction and the constrained.
and readonly.
prefixes were added to support generics. unbox.any
extracts the value contained in a boxed type and is the equivalent of an unbox
followed by ldobj
. readonly.
optimizes access to elements of a generic array by avoiding a type check when fetching an array element by guaranteeing that the element has not been modified. constrained.
was introduced to allow the callvirt
instruction to work in a uniform way with both value types and references types.
The no.
prefix indicates that the execution engine need not check for type, range, and/or null exceptions when the next instruction is executed. CF 2.0 ignores this instruction because it is designated as optional in the ECMA specification.
Conclusion
A quick trip through any subject must naturally leave out a lot of information. If you have questions about opcode specifications, the ECMA spec is the place to start. If you want to see how the compiler translates high-level code into IL opcodes, use ILDasm.exe to disassemble your executable. You can find a tutorial here. Most of what I know about IL, I've learned from ILDasm. If you still have questions, feel free to ask.
~Dan
- Legend
- yes: instruction is supported in given version
- no: instruction is not supported in given version
- X: instruction did not exist in given version
Opcode | Instruction | V1 Support | V2 Support | Opcode | Instruction | V1 Support | V2 Support | Opcode | Instruction | V1 Support | V2 Support | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x00 |
nop |
yes | yes | 0x50 |
ldind.ref |
yes | yes | 0xA0 |
stelem.r4 |
yes | yes | ||
0x01 |
break |
yes | yes | 0x51 |
stind.ref |
yes | yes | 0xA1 |
stelem.r8 |
yes | yes | ||
0x02 |
ldarg.0 |
yes | yes | 0x52 |
stind.i1 |
yes | yes | 0xA2 |
stelem.ref |
yes | yes | ||
0x03 |
ldarg.1 |
yes | yes | 0x53 |
stind.i2 |
yes | yes | 0xA3 |
ldelem |
yes | yes | ||
0x04 |
ldarg.2 |
yes | yes | 0x54 |
stind.i4 |
yes | yes | 0xA4 |
stelem |
yes | yes | ||
0x05 |
ldarg.3 |
yes | yes | 0x55 |
stind.i8 |
yes | yes | 0xA5 |
unbox.any |
X | yes | ||
0x06 |
ldloc.0 |
yes | yes | 0x56 |
stind.r4 |
yes | yes | 0xB3 |
conv.ovf.i1 |
yes | yes | ||
0x07 |
ldloc.1 |
yes | yes | 0x57 |
stind.r8 |
yes | yes | 0xB4 |
conv.ovf.u1 |
yes | yes | ||
0x08 |
ldloc.2 |
yes | yes | 0x58 |
add |
yes | yes | 0xB5 |
conv.ovf.i2 |
yes | yes | ||
0x09 |
ldloc.3 |
yes | yes | 0x59 |
sub |
yes | yes | 0xB6 |
conv.ovf.u2 |
yes | yes | ||
0x0A |
stloc.0 |
yes | yes | 0x5A |
mul |
yes | yes | 0xB7 |
conv.ovf.i4 |
yes | yes | ||
0x0B |
stloc.1 |
yes | yes | 0x5B |
div |
yes | yes | 0xB8 |
conv.ovf.u4 |
yes | yes | ||
0x0C |
stloc.2 |
yes | yes | 0x5C |
div.un |
yes | yes | 0xB9 |
conv.ovf.i8 |
yes | yes | ||
0x0D |
stloc.3 |
yes | yes | 0x5D |
rem |
yes | yes | 0xBA |
conv.ovf.u8 |
yes | yes | ||
0x0E |
ldarg.s |
yes | yes | 0x5E |
rem.un |
yes | yes | 0xC2 |
refanyval |
no | no | ||
0x0F |
ldarga.s |
yes | yes | 0x5F |
and |
yes | yes | 0xC3 |
ckfinite |
yes | yes | ||
0x10 |
starg.s |
yes | yes | 0x60 |
or |
yes | yes | 0xC6 |
mkrefany |
no | no | ||
0x11 |
ldloc.s |
yes | yes | 0x61 |
xor |
yes | yes | 0xD0 |
ldtoken |
yes | yes | ||
0x12 |
ldloca.s |
yes | yes | 0x62 |
shl |
yes | yes | 0xD1 |
conv.u2 |
yes | yes | ||
0x13 |
stloc.s |
yes | yes | 0x63 |
shr |
yes | yes | 0xD2 |
conv.u1 |
yes | yes | ||
0x14 |
ldnull |
yes | yes | 0x64 |
shr.un |
yes | yes | 0xD3 |
conv.i |
yes | yes | ||
0x15 |
ldc.i4.m1 |
yes | yes | 0x65 |
neg |
yes | yes | 0xD4 |
conv.ovf.i |
yes | yes | ||
0x16 |
ldc.i4.0 |
yes | yes | 0x66 |
not |
yes | yes | 0xD5 |
conv.ovf.u |
yes | yes | ||
0x17 |
ldc.i4.1 |
yes | yes | 0x67 |
conv.i1 |
yes | yes | 0xD6 |
add.ovf |
yes | yes | ||
0x18 |
ldc.i4.2 |
yes | yes | 0x68 |
conv.i2 |
yes | yes | 0xD7 |
add.ovf.un |
yes | yes | ||
0x19 |
ldc.i4.3 |
yes | yes | 0x69 |
conv.i4 |
yes | yes | 0xD8 |
mul.ovf |
yes | yes | ||
0x1A |
ldc.i4.4 |
yes | yes | 0x6A |
conv.i8 |
yes | yes | 0xD9 |
mul.ovf.un |
yes | yes | ||
0x1B |
ldc.i4.5 |
yes | yes | 0x6B |
conv.r4 |
yes | yes | 0xDA |
sub.ovf |
yes | yes | ||
0x1C |
ldc.i4.6 |
yes | yes | 0x6C |
conv.r8 |
yes | yes | 0xDB |
sub.ovf.un |
yes | yes | ||
0x1D |
ldc.i4.7 |
yes | yes | 0x6D |
conv.u4 |
yes | yes | 0xDC |
endfinally |
yes | yes | ||
0x1E |
ldc.i4.8 |
yes | yes | 0x6E |
conv.u8 |
yes | yes | 0xDD |
leave |
yes | yes | ||
0x1F |
ldc.i4.s |
yes | yes | 0x6F |
callvirt |
yes | yes | 0xDE |
leave.s |
yes | yes | ||
0x20 |
ldc.i4 |
yes | yes | 0x70 |
cpobj |
yes | yes | 0xDF |
stind.i |
yes | yes | ||
0x21 |
ldc.i8 |
yes | yes | 0x71 |
ldobj |
yes | yes | 0xE0 |
conv.u |
yes | yes | ||
0x22 |
ldc.r4 |
yes | yes | 0x72 |
ldstr |
yes | yes | 0xFE 0x00 |
arglist |
no | no | ||
0x23 |
ldc.r8 |
yes | yes | 0x73 |
newobj |
yes | yes | 0xFE 0x01 |
ceq |
yes | yes | ||
0x25 |
dup |
yes | yes | 0x74 |
castclass |
yes | yes | 0xFE 0x02 |
cgt |
yes | yes | ||
0x26 |
pop |
yes | yes | 0x75 |
isinst |
yes | yes | 0xFE 0x03 |
cgt.un |
yes | yes | ||
0x27 |
jmp |
no | no | 0x76 |
conv.r.un |
yes | yes | 0xFE 0x04 |
clt |
yes | yes | ||
0x28 |
call |
yes | yes | 0x79 |
unbox |
yes | yes | 0xFE 0x05 |
clt.un |
yes | yes | ||
0x29 |
calli |
no | no | 0x7A |
throw |
yes | yes | 0xFE 0x06 |
ldftn |
yes | yes | ||
0x2A |
ret |
yes | yes | 0x7B |
ldfld |
yes | yes | 0xFE 0x07 |
ldvirtftn |
yes | yes | ||
0x2B |
br.s |
yes | yes | 0x7C |
ldflda |
yes | yes | 0xFE 0x09 |
ldarg |
yes | yes | ||
0x2C |
brfalse.s |
yes | yes | 0x7D |
stfld |
yes | yes | 0xFE 0x0A |
ldarga |
yes | yes | ||
0x2D |
brtrue.s |
yes | yes | 0x7E |
ldsfld |
yes | yes | 0xFE 0x0B |
starg |
yes | yes | ||
0x2E |
beq.s |
yes | yes | 0x7F |
ldsflda |
yes | yes | 0xFE 0x0C |
ldloc |
yes | yes | ||
0x2F |
bge.s |
yes | yes | 0x80 |
stsfld |
yes | yes | 0xFE 0x0D |
ldloca |
yes | yes | ||
0x30 |
bgt.s |
yes | yes | 0x81 |
stobj |
yes | yes | 0xFE 0x0E |
stloc |
yes | yes | ||
0x31 |
ble.s |
yes | yes | 0x82 |
conv.ovf.i1.un |
yes | yes | 0xFE 0x0F |
localloc |
no | no | ||
0x32 |
blt.s |
yes | yes | 0x83 |
conv.ovf.i2.un |
yes | yes | 0xFE 0x11 |
endfilter |
yes | yes | ||
0x33 |
bne.un.s |
yes | yes | 0x84 |
conv.ovf.i4.un |
yes | yes | 0xFE 0x12 |
unaligned. |
no | no | ||
0x34 |
bge.un.s |
yes | yes | 0x85 |
conv.ovf.i8.un |
yes | yes | 0xFE 0x13 |
volatile. |
no | yes | ||
0x35 |
bgt.un.s |
yes | yes | 0x86 |
conv.ovf.u1.un |
yes | yes | 0xFE 0x14 |
tail. |
no | no | ||
0x36 |
ble.un.s |
yes | yes | 0x87 |
conv.ovf.u2.un |
yes | yes | 0xFE 0x15 |
initobj |
yes | yes | ||
0x37 |
blt.un.s |
yes | yes | 0x88 |
conv.ovf.u4.un |
yes | yes | 0xFE 0x16 |
constrained. |
X | yes | ||
0x38 |
br |
yes | yes | 0x89 |
conv.ovf.u8.un |
yes | yes | 0xFE 0x17 |
cpblk |
yes | yes | ||
0x39 |
brfalse |
yes | yes | 0x8A |
conv.ovf.i.un |
yes | yes | 0xFE 0x18 |
initblk |
yes | yes | ||
0x3A |
brtrue |
yes | yes | 0x8B |
conv.ovf.u.un |
yes | yes | 0xFE 0x19 |
no. |
X | yes | ||
0x3B |
beq |
yes | yes | 0x8C |
box |
yes | yes | 0xFE 0x1A |
rethrow |
yes | yes | ||
0x3C |
bge |
yes | yes | 0x8D |
newarr |
yes | yes | 0xFE 0x1C |
sizeof |
yes | yes | ||
0x3D |
bgt |
yes | yes | 0x8E |
ldlen |
yes | yes | 0xFE 0x1D |
refanytype |
no | no | ||
0x3E |
ble |
yes | yes | 0x8F |
ldelema |
yes | yes | 0xFE 0x1E |
readonly. |
X | yes | ||
0x3F |
blt |
yes | yes | 0x90 |
ldelem.i1 |
yes | yes | ||||||
0x40 |
bne.un |
yes | yes | 0x91 |
ldelem.u1 |
yes | yes | ||||||
0x41 |
bge.un |
yes | yes | 0x92 |
ldelem.i2 |
yes | yes | ||||||
0x42 |
bgt.un |
yes | yes | 0x93 |
ldelem.u2 |
yes | yes | ||||||
0x43 |
ble.un |
yes | yes | 0x94 |
ldelem.i4 |
yes | yes | ||||||
0x44 |
blt.un |
yes | yes | 0x95 |
ldelem.u4 |
yes | yes | ||||||
0x45 |
switch |
yes | yes | 0x96 |
ldelem.i8 |
yes | yes | ||||||
0x46 |
ldind.i1 |
yes | yes | 0x97 |
ldelem.i |
yes | yes | ||||||
0x47 |
ldind.u1 |
yes | yes | 0x98 |
ldelem.r4 |
yes | yes | ||||||
0x48 |
ldind.i2 |
yes | yes | 0x99 |
ldelem.r8 |
yes | yes | ||||||
0x49 |
ldind.u2 |
yes | yes | 0x9A |
ldelem.ref |
yes | yes | ||||||
0x4A |
ldind.i4 |
yes | yes | 0x9B |
stelem.i |
yes | yes | ||||||
0x4B |
ldind.u4 |
yes | yes | 0x9C |
stelem.i1 |
yes | yes | ||||||
0x4C |
ldind.i8 |
yes | yes | 0x9D |
stelem.i2 |
yes | yes | ||||||
0x4D |
ldind.i |
yes | yes | 0x9E |
stelem.i4 |
yes | yes | ||||||
0x4E |
ldind.r4 |
yes | yes | 0x9F |
stelem.i8 |
yes | yes | ||||||
0x4F |
ldind.r8 |
yes | yes |
[Edited to fix table layout]
Comments
- Anonymous
September 27, 2006
Dan Elliott recently posted about the IL OpCodes supported by the .NET Compact Framework.  This... - Anonymous
October 05, 2006
The comment has been removed - Anonymous
October 05, 2006
Dan Elliott recently posted about the IL OpCodes supported by the .NET Compact Framework . This got me - Anonymous
February 07, 2007
PingBack from http://blog.deanoc.com/?p=72