Marking a class sealed
should have no performance impact.
There are cases where csc
might have to emit a callvirt
opcode instead of a call
opcode. However, it seems those cases are rare.
And it seems to me that the JIT should be able to emit the same non-virtual function call for callvirt
that it would for call
, if it knows that the class doesn't have any subclasses (yet). If only one implementation of the method exists, there's no point loading its address from a vtable—just call the one implementation directly. For that matter, the JIT can even inline the function.
It's a bit of a gamble on the JIT's part, because if a subclass is later loaded, the JIT will have to throw away that machine code and compile the code again, emitting a real virtual call. My guess is this doesn't happen often in practice.
(And yes, VM designers really do aggressively pursue these tiny performance wins.)