Durante el desarrollo del generador de código para la máquina virtual, me di cuenta de que la máquina virtual no está lista para llamadas de funciones completas, con el paso de argumentos y el almacenamiento de variables locales de funciones. Por lo tanto, es necesario finalizarlo. Es decir, debe decidir la convención de llamada (convención de llamada). Hay muchas opciones diferentes, pero la elección final depende del desarrollador. Lo principal es garantizar la integridad de la pila después de la llamada.
La convención de llamada son las reglas por las cuales cuando se llama a una función, los argumentos se pasan a la función llamada (pila / registros, orden), quién y cómo borra la pila después de la llamada (llamador / destinatario) y cómo se obtiene el resultado de la función. devuelto al punto de llamada (pila / registro). Además, las funciones llamadas pueden crear variables locales que se almacenarán en la pila, las cuales también deben tenerse en cuenta, especialmente para que funcione la recursividad.
Hoy en día, las convenciones de llamadas más familiares que gobiernan las reglas para pasar argumentos de función, limpiar la pila después de una llamada y la lógica para almacenar variables locales son la declaración de C ( cdecl, x86 / 64 ) y pascal . Intentaré aplicar este conocimiento con modificaciones menores, es decir, sin acceso directo del programa a los registros de la máquina virtual (sigue siendo pila, no registro). Entonces, la lógica será la siguiente:
. main() sum() - i 10. ( pascal). call, - 2.
call :
IP (Instruction Pointer + 1)
Frame Pointer ( , )
Locals Pointer ( )
Frame Pointer ,
Locals Pointer IP, FP, LP.
ret :
IP, FP, LP.
.
SP = FP ( ).
.
, , , CALL / RET, LOAD ( ), STORE ( ), ARG ( ), DROP - . DROP , .
case OP_CALL:
a = memory[ip++]; // get call address and increment address
b = memory[ip++]; // get arguments count (argc)
b = sp + b; // calculate new frame pointer
memory[--sp] = ip; // push return address to the stack
memory[--sp] = fp; // push old Frame pointer to stack
memory[--sp] = lp; // push old Local variables pointer to stack
fp = b; // set Frame pointer to arguments pointer
lp = sp - 1; // set Local variables pointer after top of a stack
ip = a; // jump to call address
break;
case OP_RET:
a = memory[sp++]; // read function return value on top of a stack
b = lp; // save Local variables pointer
sp = fp; // set stack pointer to Frame pointer (drop locals)
lp = memory[b + 1]; // restore old Local variables pointer
fp = memory[b + 2]; // restore old Frame pointer
ip = memory[b + 3]; // set IP to return address
memory[--sp] = a; // save return value on top of a stack
break;
case OP_LOAD:
a = memory[ip++]; // read local variable index
b = lp - a; // calculate local variable address
memory[--sp] = memory[b]; // push local variable to stack
break;
case OP_STORE:
a = memory[ip++]; // read local variable index
b = lp - a; // calculate local variable address
memory[b] = memory[sp++]; // pop top of stack to local variable
break;
case OP_ARG:
a = memory[ip++]; // read parameter index
b = fp - a - 1; // calculate parameter address
memory[--sp] = memory[b]; // push parameter to stack
break;
case OP_DROP: // pop and drop value from stack
sp++;
break;
CALL, RET, LOAD, STORE, ARG (: syscall 0x21 - ):
:
[ 0] iconst 5 IP=2 FP=65535 LP=65534 SP=65534 STACK=[5] -> TOP
[ 2] iload #0 IP=4 FP=65535 LP=65534 SP=65533 STACK=[5,5] -> TOP
[ 4] idec IP=5 FP=65535 LP=65534 SP=65533 STACK=[5,4] -> TOP
[ 5] idup IP=6 FP=65535 LP=65534 SP=65532 STACK=[5,4,4] -> TOP
[ 6] istore #0 IP=8 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP
[ 8] idup IP=9 FP=65535 LP=65534 SP=65532 STACK=[4,4,4] -> TOP
[ 9] iconst 10 IP=11 FP=65535 LP=65534 SP=65531 STACK=[4,4,4,10] -> TOP
[ 11] call [32], 2 IP=32 FP=65533 LP=65527 SP=65528 STACK=[4,4,4,10,14,65535,65534] -> TOP
[ 32] iconst 10 IP=34 FP=65533 LP=65527 SP=65527 STACK=[4,4,4,10,14,65535,65534,10] -> TOP
[ 34] iarg #0 IP=36 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,4] -> TOP
[ 36] iarg #1 IP=38 FP=65533 LP=65527 SP=65525 STACK=[4,4,4,10,14,65535,65534,10,4,10] -> TOP
[ 38] iadd IP=39 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,14] -> TOP
[ 39] iload #0 IP=41 FP=65533 LP=65527 SP=65525 STACK=[4,4,4,10,14,65535,65534,10,14,10] -> TOP
[ 41] isub IP=42 FP=65533 LP=65527 SP=65526 STACK=[4,4,4,10,14,65535,65534,10,4] -> TOP
[ 42] ret IP=14 FP=65535 LP=65534 SP=65532 STACK=[4,4,4] -> TOP
[ 14] syscall 0x21 IP=16 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP
[ 16] iconst 0 IP=18 FP=65535 LP=65534 SP=65532 STACK=[4,4,0] -> TOP
[ 18] icmpjg [2] IP=2 FP=65535 LP=65534 SP=65534 STACK=[4] -> TOP
[ 2] iload #0 IP=4 FP=65535 LP=65534 SP=65533 STACK=[4,4] -> TOP
[ 4] idec IP=5 FP=65535 LP=65534 SP=65533 STACK=[4,3] -> TOP
[ 5] idup IP=6 FP=65535 LP=65534 SP=65532 STACK=[4,3,3] -> TOP
[ 6] istore #0 IP=8 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP
[ 8] idup IP=9 FP=65535 LP=65534 SP=65532 STACK=[3,3,3] -> TOP
[ 9] iconst 10 IP=11 FP=65535 LP=65534 SP=65531 STACK=[3,3,3,10] -> TOP
[ 11] call [32], 2 IP=32 FP=65533 LP=65527 SP=65528 STACK=[3,3,3,10,14,65535,65534] -> TOP
[ 32] iconst 10 IP=34 FP=65533 LP=65527 SP=65527 STACK=[3,3,3,10,14,65535,65534,10] -> TOP
[ 34] iarg #0 IP=36 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,3] -> TOP
[ 36] iarg #1 IP=38 FP=65533 LP=65527 SP=65525 STACK=[3,3,3,10,14,65535,65534,10,3,10] -> TOP
[ 38] iadd IP=39 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,13] -> TOP
[ 39] iload #0 IP=41 FP=65533 LP=65527 SP=65525 STACK=[3,3,3,10,14,65535,65534,10,13,10] -> TOP
[ 41] isub IP=42 FP=65533 LP=65527 SP=65526 STACK=[3,3,3,10,14,65535,65534,10,3] -> TOP
[ 42] ret IP=14 FP=65535 LP=65534 SP=65532 STACK=[3,3,3] -> TOP
[ 14] syscall 0x21 IP=16 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP
[ 16] iconst 0 IP=18 FP=65535 LP=65534 SP=65532 STACK=[3,3,0] -> TOP
[ 18] icmpjg [2] IP=2 FP=65535 LP=65534 SP=65534 STACK=[3] -> TOP
[ 2] iload #0 IP=4 FP=65535 LP=65534 SP=65533 STACK=[3,3] -> TOP
[ 4] idec IP=5 FP=65535 LP=65534 SP=65533 STACK=[3,2] -> TOP
[ 5] idup IP=6 FP=65535 LP=65534 SP=65532 STACK=[3,2,2] -> TOP
[ 6] istore #0 IP=8 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP
[ 8] idup IP=9 FP=65535 LP=65534 SP=65532 STACK=[2,2,2] -> TOP
[ 9] iconst 10 IP=11 FP=65535 LP=65534 SP=65531 STACK=[2,2,2,10] -> TOP
[ 11] call [32], 2 IP=32 FP=65533 LP=65527 SP=65528 STACK=[2,2,2,10,14,65535,65534] -> TOP
[ 32] iconst 10 IP=34 FP=65533 LP=65527 SP=65527 STACK=[2,2,2,10,14,65535,65534,10] -> TOP
[ 34] iarg #0 IP=36 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,2] -> TOP
[ 36] iarg #1 IP=38 FP=65533 LP=65527 SP=65525 STACK=[2,2,2,10,14,65535,65534,10,2,10] -> TOP
[ 38] iadd IP=39 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,12] -> TOP
[ 39] iload #0 IP=41 FP=65533 LP=65527 SP=65525 STACK=[2,2,2,10,14,65535,65534,10,12,10] -> TOP
[ 41] isub IP=42 FP=65533 LP=65527 SP=65526 STACK=[2,2,2,10,14,65535,65534,10,2] -> TOP
[ 42] ret IP=14 FP=65535 LP=65534 SP=65532 STACK=[2,2,2] -> TOP
[ 14] syscall 0x21 IP=16 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP
[ 16] iconst 0 IP=18 FP=65535 LP=65534 SP=65532 STACK=[2,2,0] -> TOP
[ 18] icmpjg [2] IP=2 FP=65535 LP=65534 SP=65534 STACK=[2] -> TOP
[ 2] iload #0 IP=4 FP=65535 LP=65534 SP=65533 STACK=[2,2] -> TOP
[ 4] idec IP=5 FP=65535 LP=65534 SP=65533 STACK=[2,1] -> TOP
[ 5] idup IP=6 FP=65535 LP=65534 SP=65532 STACK=[2,1,1] -> TOP
[ 6] istore #0 IP=8 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP
[ 8] idup IP=9 FP=65535 LP=65534 SP=65532 STACK=[1,1,1] -> TOP
[ 9] iconst 10 IP=11 FP=65535 LP=65534 SP=65531 STACK=[1,1,1,10] -> TOP
[ 11] call [32], 2 IP=32 FP=65533 LP=65527 SP=65528 STACK=[1,1,1,10,14,65535,65534] -> TOP
[ 32] iconst 10 IP=34 FP=65533 LP=65527 SP=65527 STACK=[1,1,1,10,14,65535,65534,10] -> TOP
[ 34] iarg #0 IP=36 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,1] -> TOP
[ 36] iarg #1 IP=38 FP=65533 LP=65527 SP=65525 STACK=[1,1,1,10,14,65535,65534,10,1,10] -> TOP
[ 38] iadd IP=39 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,11] -> TOP
[ 39] iload #0 IP=41 FP=65533 LP=65527 SP=65525 STACK=[1,1,1,10,14,65535,65534,10,11,10] -> TOP
[ 41] isub IP=42 FP=65533 LP=65527 SP=65526 STACK=[1,1,1,10,14,65535,65534,10,1] -> TOP
[ 42] ret IP=14 FP=65535 LP=65534 SP=65532 STACK=[1,1,1] -> TOP
[ 14] syscall 0x21 IP=16 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP
[ 16] iconst 0 IP=18 FP=65535 LP=65534 SP=65532 STACK=[1,1,0] -> TOP
[ 18] icmpjg [2] IP=2 FP=65535 LP=65534 SP=65534 STACK=[1] -> TOP
[ 2] iload #0 IP=4 FP=65535 LP=65534 SP=65533 STACK=[1,1] -> TOP
[ 4] idec IP=5 FP=65535 LP=65534 SP=65533 STACK=[1,0] -> TOP
[ 5] idup IP=6 FP=65535 LP=65534 SP=65532 STACK=[1,0,0] -> TOP
[ 6] istore #0 IP=8 FP=65535 LP=65534 SP=65533 STACK=[0,0] -> TOP
[ 8] idup IP=9 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP
[ 9] iconst 10 IP=11 FP=65535 LP=65534 SP=65531 STACK=[0,0,0,10] -> TOP
[ 11] call [32], 2 IP=32 FP=65533 LP=65527 SP=65528 STACK=[0,0,0,10,14,65535,65534] -> TOP
[ 32] iconst 10 IP=34 FP=65533 LP=65527 SP=65527 STACK=[0,0,0,10,14,65535,65534,10] -> TOP
[ 34] iarg #0 IP=36 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,0] -> TOP
[ 36] iarg #1 IP=38 FP=65533 LP=65527 SP=65525 STACK=[0,0,0,10,14,65535,65534,10,0,10] -> TOP
[ 38] iadd IP=39 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,10] -> TOP
[ 39] iload #0 IP=41 FP=65533 LP=65527 SP=65525 STACK=[0,0,0,10,14,65535,65534,10,10,10] -> TOP
[ 41] isub IP=42 FP=65533 LP=65527 SP=65526 STACK=[0,0,0,10,14,65535,65534,10,0] -> TOP
[ 42] ret IP=14 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP
[ 14] syscall 0x21 IP=16 FP=65535 LP=65534 SP=65533 STACK=[0,0] -> TOP
[ 16] iconst 0 IP=18 FP=65535 LP=65534 SP=65532 STACK=[0,0,0] -> TOP
[ 18] icmpjg [2] IP=20 FP=65535 LP=65534 SP=65534 STACK=[0] -> TOP
[ 20] ---- halt ----IP=21 FP=65535 LP=65534 SP=65534 STACK=[0] -> TOP
EXECUTION TIME: 0.620997s
, , , , . (AST ). .
! !