11// Evaluate opcodes
22package vm
33
4+ /* FIXME
5+
6+ cpython has one stack per frame, not one stack in total
7+
8+ We know how big each frame needs to be from
9+
10+ code->co_stacksize
11+
12+ The frame then becomes the important thing
13+
14+ cpython keeps a zombie frame on each code object to speed up execution
15+ of a code object so a frame doesn't have to be allocated and
16+ deallocated each time which seems like a good idea. If we want to
17+ work with go routines then it might have to be more sophisticated.
18+
19+ To implmenent generators need to check Code.Flags & CO_GENERATOR at
20+ the start of vmRum and if so wrap the created frame into a generator
21+ object.
22+
23+ FIXME could make the stack be permanently allocated and just keep a
24+ pointer into it rather than using append etc...
25+
26+ If we are caching the frames need to make sure we clear the stack
27+ objects so they can be GCed
28+
29+ */
30+
431import (
532"errors"
633"fmt"
@@ -9,32 +36,32 @@ import (
936)
1037
1138// Stack operations
12- func (vm * Vm ) STACK_LEVEL () int {return len (vm .stack ) }
13- func (vm * Vm ) EMPTY () bool {return len (vm .stack ) == 0 }
14- func (vm * Vm ) TOP () py.Object {return vm .stack [len (vm .stack )- 1 ] }
15- func (vm * Vm ) SECOND () py.Object {return vm .stack [len (vm .stack )- 2 ] }
16- func (vm * Vm ) THIRD () py.Object {return vm .stack [len (vm .stack )- 3 ] }
17- func (vm * Vm ) FOURTH () py.Object {return vm .stack [len (vm .stack )- 4 ] }
18- func (vm * Vm ) PEEK (n int ) py.Object {return vm .stack [len (vm .stack )- n ] }
19- func (vm * Vm ) SET_TOP (v py.Object ){vm .stack [len (vm .stack )- 1 ] = v }
20- func (vm * Vm ) SET_SECOND (v py.Object ){vm .stack [len (vm .stack )- 2 ] = v }
21- func (vm * Vm ) SET_THIRD (v py.Object ){vm .stack [len (vm .stack )- 3 ] = v }
22- func (vm * Vm ) SET_FOURTH (v py.Object ){vm .stack [len (vm .stack )- 4 ] = v }
23- func (vm * Vm ) SET_VALUE (n int , v py.Object ){vm .stack [len (vm .stack )- (n )] = (v ) }
24- func (vm * Vm ) DROP (){vm .stack = vm .stack [:len (vm .stack )- 1 ] }
25- func (vm * Vm ) DROPN (n int ){vm .stack = vm .stack [:len (vm .stack )- n ] }
39+ func (vm * Vm ) STACK_LEVEL () int {return len (vm .frame . Stack ) }
40+ func (vm * Vm ) EMPTY () bool {return len (vm .frame . Stack ) == 0 }
41+ func (vm * Vm ) TOP () py.Object {return vm .frame . Stack [len (vm .frame . Stack )- 1 ] }
42+ func (vm * Vm ) SECOND () py.Object {return vm .frame . Stack [len (vm .frame . Stack )- 2 ] }
43+ func (vm * Vm ) THIRD () py.Object {return vm .frame . Stack [len (vm .frame . Stack )- 3 ] }
44+ func (vm * Vm ) FOURTH () py.Object {return vm .frame . Stack [len (vm .frame . Stack )- 4 ] }
45+ func (vm * Vm ) PEEK (n int ) py.Object {return vm .frame . Stack [len (vm .frame . Stack )- n ] }
46+ func (vm * Vm ) SET_TOP (v py.Object ){vm .frame . Stack [len (vm .frame . Stack )- 1 ] = v }
47+ func (vm * Vm ) SET_SECOND (v py.Object ){vm .frame . Stack [len (vm .frame . Stack )- 2 ] = v }
48+ func (vm * Vm ) SET_THIRD (v py.Object ){vm .frame . Stack [len (vm .frame . Stack )- 3 ] = v }
49+ func (vm * Vm ) SET_FOURTH (v py.Object ){vm .frame . Stack [len (vm .frame . Stack )- 4 ] = v }
50+ func (vm * Vm ) SET_VALUE (n int , v py.Object ){vm .frame . Stack [len (vm .frame . Stack )- (n )] = (v ) }
51+ func (vm * Vm ) DROP (){vm .frame . Stack = vm .frame . Stack [:len (vm .frame . Stack )- 1 ] }
52+ func (vm * Vm ) DROPN (n int ){vm .frame . Stack = vm .frame . Stack [:len (vm .frame . Stack )- n ] }
2653
2754// Pop from top of vm stack
2855func (vm * Vm ) POP () py.Object {
2956// FIXME what if empty?
30- out := vm .stack [len (vm .stack )- 1 ]
31- vm .stack = vm .stack [:len (vm .stack )- 1 ]
57+ out := vm .frame . Stack [len (vm .frame . Stack )- 1 ]
58+ vm .frame . Stack = vm .frame . Stack [:len (vm .frame . Stack )- 1 ]
3259return out
3360}
3461
3562// Push to top of vm stack
3663func (vm * Vm ) PUSH (obj py.Object ){
37- vm .stack = append (vm .stack , obj )
64+ vm .frame . Stack = append (vm .frame . Stack , obj )
3865}
3966
4067// Illegal instruction
@@ -333,7 +360,7 @@ func do_BREAK_LOOP(vm *Vm, arg int32){
333360// Jump
334361vm .frame .Lasti = vm .frame .Block .Handler
335362// Reset the stack (FIXME?)
336- vm .stack = vm .stack [:vm .frame .Block .Level ]
363+ vm .frame . Stack = vm .frame . Stack [:vm .frame .Block .Level ]
337364vm .frame .PopBlock ()
338365}
339366
@@ -385,6 +412,11 @@ func do_MAP_ADD(vm *Vm, i int32){
385412
386413// Returns with TOS to the caller of the function.
387414func do_RETURN_VALUE (vm * Vm , arg int32 ){
415+ vm .result = vm .POP ()
416+ if len (vm .frame .Stack ) != 0 {
417+ fmt .Printf ("vmstack = %#v\n " , vm .frame .Stack )
418+ panic ("vm stack should be empty at this point" )
419+ }
388420vm .PopFrame ()
389421}
390422
@@ -529,9 +561,9 @@ func do_LOAD_NAME(vm *Vm, namei int32){
529561// the resulting tuple onto the stack.
530562func do_BUILD_TUPLE (vm * Vm , count int32 ){
531563tuple := make (py.Tuple , count )
532- p := len (vm .stack ) - int (count )
564+ p := len (vm .frame . Stack ) - int (count )
533565for i := range tuple {
534- tuple [i ] = vm .stack [p + i ]
566+ tuple [i ] = vm .frame . Stack [p + i ]
535567 }
536568vm .DROPN (int (count ))
537569vm .PUSH (tuple )
@@ -545,9 +577,9 @@ func do_BUILD_SET(vm *Vm, count int32){
545577// Works as BUILD_TUPLE, but creates a list.
546578func do_BUILD_LIST (vm * Vm , count int32 ){
547579list := make (py.List , count )
548- p := len (vm .stack ) - int (count )
580+ p := len (vm .frame . Stack ) - int (count )
549581for i := range list {
550- list [i ] = vm .stack [p + i ]
582+ list [i ] = vm .frame . Stack [p + i ]
551583 }
552584vm .DROPN (int (count ))
553585vm .PUSH (list )
@@ -681,19 +713,19 @@ func do_LOAD_GLOBAL(vm *Vm, namei int32){
681713// Pushes a block for a loop onto the block stack. The block spans
682714// from the current instruction with a size of delta bytes.
683715func do_SETUP_LOOP (vm * Vm , delta int32 ){
684- vm .frame .PushBlock (SETUP_LOOP , vm .frame .Lasti + delta , len (vm .stack ))
716+ vm .frame .PushBlock (SETUP_LOOP , vm .frame .Lasti + delta , len (vm .frame . Stack ))
685717}
686718
687719// Pushes a try block from a try-except clause onto the block
688720// stack. delta points to the first except block.
689721func do_SETUP_EXCEPT (vm * Vm , delta int32 ){
690- vm .frame .PushBlock (SETUP_EXCEPT , vm .frame .Lasti + delta , len (vm .stack ))
722+ vm .frame .PushBlock (SETUP_EXCEPT , vm .frame .Lasti + delta , len (vm .frame . Stack ))
691723}
692724
693725// Pushes a try block from a try-except clause onto the block
694726// stack. delta points to the finally block.
695727func do_SETUP_FINALLY (vm * Vm , delta int32 ){
696- vm .frame .PushBlock (SETUP_FINALLY , vm .frame .Lasti + delta , len (vm .stack ))
728+ vm .frame .PushBlock (SETUP_FINALLY , vm .frame .Lasti + delta , len (vm .frame . Stack ))
697729}
698730
699731// Store a key and value pair in a dictionary. Pops the key and value
@@ -769,19 +801,19 @@ func do_RAISE_VARARGS(vm *Vm, argc int32){
769801// function arguments, and the function itself off the stack, and
770802// pushes the return value.
771803func do_CALL_FUNCTION (vm * Vm , argc int32 ){
772- // fmt.Printf("Stack: %v\n", vm.stack )
804+ // fmt.Printf("Stack: %v\n", vm.frame.Stack )
773805// fmt.Printf("Locals: %v\n", vm.frame.Locals)
774806// fmt.Printf("Globals: %v\n", vm.frame.Globals)
775807nargs := int (argc & 0xFF )
776808nkwargs := int ((argc >> 8 ) & 0xFF )
777- p , q := len (vm .stack )- 2 * nkwargs , len (vm .stack )
778- kwargs := vm .stack [p :q ]
809+ p , q := len (vm .frame . Stack )- 2 * nkwargs , len (vm .frame . Stack )
810+ kwargs := vm .frame . Stack [p :q ]
779811p , q = p - nargs , p
780- args := py .Tuple (vm .stack [p :q ])
812+ args := py .Tuple (vm .frame . Stack [p :q ])
781813p , q = p - 1 , p
782- fn := vm .stack [p ]
814+ fn := vm .frame . Stack [p ]
783815// Drop everything off the stack
784- vm .stack = vm .stack [:p ]
816+ vm .frame . Stack = vm .frame . Stack [:p ]
785817vm .Call (fn , args , kwargs )
786818}
787819
@@ -891,7 +923,7 @@ func do_CALL_FUNCTION_VAR_KW(vm *Vm, argc int32){
891923// NotImplemented
892924func (vm * Vm ) NotImplemented (name string , arg int32 ){
893925fmt .Printf ("%s %d NOT IMPLEMENTED\n " , name , arg )
894- fmt .Printf ("vmstack = %#v\n " , vm .stack )
926+ fmt .Printf ("vmstack = %#v\n " , vm .frame . Stack )
895927panic (fmt .Sprintf ("Opcode %s %d NOT IMPLEMENTED" , name , arg ))
896928}
897929
@@ -922,20 +954,8 @@ func (vm *Vm) Call(fnObj py.Object, args []py.Object, kwargsTuple []py.Object){
922954fnObj = vm .frame .Lookup (string (fn ))
923955 }
924956
925- // Call py.Functions in this vm
926- // FIXME make this an interface? LocalsForCall ?
927- if fn , ok := fnObj .(* py.Function ); ok {
928- var locals py.StringDict
929- if kwargs != nil {
930- locals = fn .LocalsForCallWithKeywords (args , kwargs )
931- } else {
932- locals = fn .LocalsForCall (args )
933- }
934- vm .PushFrame (fn .Globals , locals , fn .Code )
935- } else {
936- // Call everything else directly
937- vm .PUSH (py .Call (fnObj , args , kwargs ))
938- }
957+ // Call the function pushing the return on the stack
958+ vm .PUSH (py .Call (fnObj , args , kwargs ))
939959}
940960
941961// Make a new Frame with globals, locals and Code on the frames stack
@@ -945,6 +965,7 @@ func (vm *Vm) PushFrame(globals, locals py.StringDict, code *py.Code){
945965Locals : locals ,
946966Code : code ,
947967Builtins : py .Builtins .Globals ,
968+ Stack : make ([]py.Object , 0 , code .Stacksize ),
948969 }
949970vm .frames = append (vm .frames , frame )
950971vm .frame = & vm .frames [len (vm .frames )- 1 ]
@@ -1013,16 +1034,14 @@ func Run(globals, locals py.StringDict, code *py.Code) (res py.Object, err error
10131034 }
10141035vm .extended = false
10151036jumpTable [opcode ](vm , arg )
1016- fmt .Printf ("* Stack = %#v\n " , vm .stack )
1017- // if len(vm.stack) > 0{
1018- // if t, ok := vm.TOP().(*py.Type); ok{
1019- // fmt.Printf(" * TOP = %#v\n", t)
1020- // }
1021- // }
1022- }
1023- if len (vm .stack ) != 1 {
1024- fmt .Printf ("vmstack = %#v\n " , vm .stack )
1025- panic ("vm stack should only have 1 entry on at this point" )
1037+ if vm .frame != nil {
1038+ fmt .Printf ("* Stack = %#v\n " , vm .frame .Stack )
1039+ // if len(vm.frame.Stack) > 0{
1040+ // if t, ok := vm.TOP().(*py.Type); ok{
1041+ // fmt.Printf(" * TOP = %#v\n", t)
1042+ // }
1043+ // }
1044+ }
10261045 }
1027- return vm .POP () , nil
1046+ return vm .result , nil
10281047}
0 commit comments