En realidad tanto la JVM como el CLR tienen también registros... lo que pasa es que les llaman "variables locales" y para referirse a ellas en lugar de hacerlo mediante un campo de cada instrucción se hace mediante una instrucción separada: ldloc.* en el CLR y iload, lload, aload, etc en la JVM.
Pero en el fondo es lo mismo (salvo que en CLR y en la JVM el número de "registros" es casi ilimitado y las convenciones de llamada a función son más sencillas), y el código ensamblador que se ejecuta al final (después del JIT) va a usar los registros de la máquina real.
Es simplemente una forma diferente de representar la misma información. Para un código que se supone que va a ser (re)compilado justo antes de ejecutarse (y por tanto es entonces cuando hay que optimizar y asignar registros) la diferencia es mínima.
Por ejemplo, en el CLR para sumar dos números (en los registros 0 y 1) y almacenar el resultado (en el registro 2) sería algo así como (no recuerdo la sintaxis exacta):
ldloc.i4 0 ldloc.i4 1 add stloc.i4 2
y en la LLVM (otra MV basada en registros, debe ser parecido a Parrot (el cual no conozco mucho)):
%r2 = add i32 %r0, %r1
El código generado puede ser perfectamente el mismo. Qué representación es más compacta y adecuada depende de muchos factores...
Pero el que una MV diga ser "de registros" o "de pila" no es una diferencia tan importante como lo pintan.
Re:La VM de Parrot
(Puntos:3, Informativo)( http://barrapunto.com/ )
Pero en el fondo es lo mismo (salvo que en CLR y en la JVM el número de "registros" es casi ilimitado y las convenciones de llamada a función son más sencillas), y el código ensamblador que se ejecuta al final (después del JIT) va a usar los registros de la máquina real.
Es simplemente una forma diferente de representar la misma información. Para un código que se supone que va a ser (re)compilado justo antes de ejecutarse (y por tanto es entonces cuando hay que optimizar y asignar registros) la diferencia es mínima.
Por ejemplo, en el CLR para sumar dos números (en los registros 0 y 1) y almacenar el resultado (en el registro 2) sería algo así como (no recuerdo la sintaxis exacta):
ldloc.i4 0
ldloc.i4 1
add
stloc.i4 2
y en la LLVM (otra MV basada en registros, debe ser parecido a Parrot (el cual no conozco mucho)):
%r2 = add i32 %r0, %r1
El código generado puede ser perfectamente el mismo. Qué representación es más compacta y adecuada depende de muchos factores...
Pero el que una MV diga ser "de registros" o "de pila" no es una diferencia tan importante como lo pintan.