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.)