Manu, Jaime,
> No me refiero a la ventaja (dices que es la velocidad), sino a qué
> diferencia
> a ese "código nativo" del que genera actualmente Harbour. Gracias

No nos dejemos llevar por la euforia... estoy de acuerdo que lo que ha hecho
Przemek es un gran avance, pero todavía queda mucho por delante para que sea
algo verdaderamente atractivo. En mi humilde opinión, la (todavía) pequeña
ganancia de velocidad no justifica el (gran) aumento de código generado.
Aunque también es cierto que en determinados casos podría ser necesario.
Hay un buen artículo de Walter Negro sobre el pcode en
http://www.puertosur.org, que por desgracia está ahora mismo hackeada. Por
mi parte, intentaré explicar de forma lo más sencilla posible en qué
consiste todo esto (Walter, si ves esto, tú eres mucho más experto que yo en
este tema; si hay algo incorrecto, por favor, corrígeme; y si quieres
aclarar algo más, adelante):
Hasta ahora, cuando compilamos un prg con [x]Harbour, se genera un fuente en
C. Pongamos un ejemplo muy simple:
PROCEDURE Ejemplo()
LOCAL n
Ejemplo2( @n )
RETURN
produce esta función en C:
HB_FUNC( EJEMPLO )
{
static const BYTE pcode[] =
{
HB_P_FRAME, 1, 0, /* locals, params */
HB_P_PUSHSYMNEAR, 1, /* EJEMPLO2 */
HB_P_PUSHNIL,
HB_P_PUSHLOCALREF, 1, 0, /* N */
HB_P_DOSHORT, 1,
HB_P_ENDPROC
};
hb_vmExecute( pcode, symbols, NULL );
}
Si os fijais bien, es algo tan simple como una variable (pcode) que contiene
toda la cadena de pcodes y sus argumentos. A continuación se llama a la
función hb_vmExecute(), que es el punto de entrada de la VM, pasándole esa
variable, es decir, la cadena de pcode.
Posteriormente, dentro de la VM, se va cogiendo byte a byte cada pcode y sus
argumentos, y se van procesando. En muchos casos, la forma de procesar un
pcode es simplemente llamando a un función. P.ej., el pcode
HB_P_PUSHLOCALREF se trata así dentro de la VM:
case HB_P_PUSHLOCALREF:
HB_TRACE( HB_TR_DEBUG, ("HB_P_PUSHLOCALREF") );
hb_vmPushLocalByRef( HB_PCODE_MKSHORT( &( pCode[ w + 1 ] ) ) );
w += 3;
break;
por lo tanto, hay una función hb_vmPushLocalByRef() que es quien realmente
hace el trabajo.
Pues bien, lo que ha hecho Przemek en Harbour es que ahora, desde la
funciones en C generadas al compilar se llama directamente a las funciones
que corresponda de la VM. P.ej., la función anterior sería más o menos así
(ojo, que no he visto todavía como se genera, y esto es sólo una
especulación):
HB_FUNC( EJEMPLO )
{
hb_vmFrame( 1, 0 );
hb_vmPushSymbol( 1 );
hb_vmPushNil();
hb_vmPushLocalByRef( 1 );
hb_vmDo( 1 );
hb_vmEndProc();
}
Lógicamente, esto es más rápido que en el caso anterior, ya que esta función
llama directamente a las funciones que tienen que hacer el trabajo. Antes,
solamante llamaba a una, pero esta tenía que ir procesando uno por uno los
pcode (dentro de un switch enorme), y llamando a las funciones finales.
Pero a cambio, ocupa mucha más memoria. El ejemplo con pcode ocupaba
solamente 12 bytes + la llamada a hb_vmExecute(); si no me equivoco, son en
total 32 bytes. Por otro lado, la nueva función tiene 6 llamadas a
funciones, con sus respectivos parámetros, que si no me equivoco son 46
bytes, es decir, un 44% más. Esto es un ejemplo muy muy simple, pero nos
puede dar una idea que por donde van los tiros. Por cierto, un pcode sin
argumentos ocupa sólo 1 byte, mientras que una llamada a función sin
parámetros ocupa 5 bytes. Por lo tanto, en funciones más grandes que el
ejemplo la diferencia será bastante mayor.
Como curiosidad... Alaska xBase genera el código más o menos de esta forma.
Los que lo conozcais sabreis lo grandes que pueden llegar a ser los
ejecutables.
Por otro lado, el objetivo que se persigue finalmente no es convertir el
pcode actual en llamadas a las funciones correspondientes sin más; el
objetivo final es que el compilador genere una especie de metacode que
después se pueda optimizar según el código final que se vaya a generar. Esto
sí daría mejores resultados, tanto en tamaño de ejecutable como en
velocidad, ya que se podría optimizar el uso de C, e incluso disponer de
variables nativas en C dentro del código generado, lo que hasta ahora no se
está haciendo.
--
Un saludo,
José F. Giménez