I did some benchmarks in the past on my own, and my experience was that native C++ was around a factor 2 faster than C++/CLI for my typical business case, without any relevant change in code - your mileage will vary. For me, a factor 2 was almost always fully acceptable to stick to C++/CLI side, because interaction with the .NET framework and other .NET code was much more important for me than this performance gain.
A machine, virtual or not, needs a model of computation which describes how computation is carried out on it. By definition, as soon as it computes, it implements some model of computation. The question then is: What model should we choose for our VM? Physical machines are constrained by what can be effectively and efficiently done in hardware. But, as you note, virtual machines have no such constraints, they are defined in software using arbitrarily high level languages.
There are, in fact, virtual machines that are high-level as you describe. They are called programming languages. The C standard for example dedicates the bulk of its pages to defining a model for the so-called "C abstract machine" which describes how C programs behave, and by extension (as-if rule) how a conforming C compiler (or interpreter) should behave.
Of course, we usually don't call that a virtual machine. A VM is usually takes to mean something lower-level, closer to hardware, not intended to be directly programmed, designed to be executed efficiently. This selection bias means that something that accepts high-level composable code (like what you describe) wouldn't be considered a VM because is executes high-level code.
But to get the to the point, here are some reasons to make a VM (as in, something targeted by a bytecode compiler) register-based or the like. Stack and register machines are extremely simple. There's a sequence of instructions, some state, and semantics for each instruction (a function State -> State). No complex tree reductions, no operator precedence. Parsing, analysing and executing it is very simple, because it's a minimal language (syntactic sugar is compiled away) and designed to be machine-read rather than human-read.
In contrast, parsing even the simplest C-like languages is quite hard, and executing it requires non-local analyses like checking and propagating types, resolving overloads, maintaining a symbol table, resolving string identifiers, turning linear text into a precedence-driven AST, and so on. It builds on concepts that come natural to humans but have to be painstakingly reverse engineered by machines.
JVM bytecode, for example, is emitted by javac
. It virtually never needs to be read or written by humans, so it's natural to gear it towards consumption by machines. If you optimized it for humans, the JVM would just on every startup read the code, parse it, analyze is, and then convert it into an intermediate representation resembling such a simplified machine model anyway. Might as well cut out the middle man.
Best Answer
"Windows" is not a synonym for "x86" - even back in the late-1990s Windows ran on DEC Alpha, MIPS, x86, and even PowerPC and by the early-2000s when .NET 1.1 was released Windows also supported IA-64 (Itanium) and AMD64 was on the horizon, while Windows CE (the then-dominant smart-device OS) ran on x86, ARM, SH-3 and MIPS. The case for a cross-platform, JIT-compiled runtime exclusively for Windows was (and remains) still quite convincing.
Granted, we can only speculate on the reasoning behind the CLR's development, but many strong reasons can be deduced from history:
Java was the first multiplatform VM (and library, complete with GUI and web-server packages) to take-off - but Microsoft didn't control it and their attempts at extending the platform for their benefit didn't work out (see "J++") - if Microsoft couldn't capture the new generation of Java programmers (who saw VB as below them, and who didn't want to mess-around with C/C++) then they would lose control of the desktop software ecosystem: why buy Windows if desktop software works fine on Mac, Solaris, etc?
On the server-side, "Classic" ASP 3.0 was getting upstaged by PHP and JSP - Microsoft could have invested time in improving ASP separately, but they decided to make ASP.NET (then called "ASP+") an integral part of the .NET Framework too: this was a boon for developers because it enabled object-level code-reuse, something that was previously impossible (e.g. using C++ classes in VB) or very difficult (using COM/DCOM).
So the CLR offers 3 main benefits over the contemporary status-quo:
And a number of proprietary advantages for Microsoft: