1
1
// Evaluate opcodes
2
2
package vm
3
3
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
+
4
31
import (
5
32
"errors"
6
33
"fmt"
@@ -9,32 +36,32 @@ import (
9
36
)
10
37
11
38
// 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 ] }
26
53
27
54
// Pop from top of vm stack
28
55
func (vm * Vm ) POP () py.Object {
29
56
// 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 ]
32
59
return out
33
60
}
34
61
35
62
// Push to top of vm stack
36
63
func (vm * Vm ) PUSH (obj py.Object ) {
37
- vm .stack = append (vm .stack , obj )
64
+ vm .frame . Stack = append (vm .frame . Stack , obj )
38
65
}
39
66
40
67
// Illegal instruction
@@ -333,7 +360,7 @@ func do_BREAK_LOOP(vm *Vm, arg int32) {
333
360
// Jump
334
361
vm .frame .Lasti = vm .frame .Block .Handler
335
362
// Reset the stack (FIXME?)
336
- vm .stack = vm .stack [:vm .frame .Block .Level ]
363
+ vm .frame . Stack = vm .frame . Stack [:vm .frame .Block .Level ]
337
364
vm .frame .PopBlock ()
338
365
}
339
366
@@ -385,6 +412,11 @@ func do_MAP_ADD(vm *Vm, i int32) {
385
412
386
413
// Returns with TOS to the caller of the function.
387
414
func 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
+ }
388
420
vm .PopFrame ()
389
421
}
390
422
@@ -529,9 +561,9 @@ func do_LOAD_NAME(vm *Vm, namei int32) {
529
561
// the resulting tuple onto the stack.
530
562
func do_BUILD_TUPLE (vm * Vm , count int32 ) {
531
563
tuple := make (py.Tuple , count )
532
- p := len (vm .stack ) - int (count )
564
+ p := len (vm .frame . Stack ) - int (count )
533
565
for i := range tuple {
534
- tuple [i ] = vm .stack [p + i ]
566
+ tuple [i ] = vm .frame . Stack [p + i ]
535
567
}
536
568
vm .DROPN (int (count ))
537
569
vm .PUSH (tuple )
@@ -545,9 +577,9 @@ func do_BUILD_SET(vm *Vm, count int32) {
545
577
// Works as BUILD_TUPLE, but creates a list.
546
578
func do_BUILD_LIST (vm * Vm , count int32 ) {
547
579
list := make (py.List , count )
548
- p := len (vm .stack ) - int (count )
580
+ p := len (vm .frame . Stack ) - int (count )
549
581
for i := range list {
550
- list [i ] = vm .stack [p + i ]
582
+ list [i ] = vm .frame . Stack [p + i ]
551
583
}
552
584
vm .DROPN (int (count ))
553
585
vm .PUSH (list )
@@ -681,19 +713,19 @@ func do_LOAD_GLOBAL(vm *Vm, namei int32) {
681
713
// Pushes a block for a loop onto the block stack. The block spans
682
714
// from the current instruction with a size of delta bytes.
683
715
func 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 ))
685
717
}
686
718
687
719
// Pushes a try block from a try-except clause onto the block
688
720
// stack. delta points to the first except block.
689
721
func 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 ))
691
723
}
692
724
693
725
// Pushes a try block from a try-except clause onto the block
694
726
// stack. delta points to the finally block.
695
727
func 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 ))
697
729
}
698
730
699
731
// 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) {
769
801
// function arguments, and the function itself off the stack, and
770
802
// pushes the return value.
771
803
func do_CALL_FUNCTION (vm * Vm , argc int32 ) {
772
- // fmt.Printf("Stack: %v\n", vm.stack )
804
+ // fmt.Printf("Stack: %v\n", vm.frame.Stack )
773
805
// fmt.Printf("Locals: %v\n", vm.frame.Locals)
774
806
// fmt.Printf("Globals: %v\n", vm.frame.Globals)
775
807
nargs := int (argc & 0xFF )
776
808
nkwargs := 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 ]
779
811
p , q = p - nargs , p
780
- args := py .Tuple (vm .stack [p :q ])
812
+ args := py .Tuple (vm .frame . Stack [p :q ])
781
813
p , q = p - 1 , p
782
- fn := vm .stack [p ]
814
+ fn := vm .frame . Stack [p ]
783
815
// Drop everything off the stack
784
- vm .stack = vm .stack [:p ]
816
+ vm .frame . Stack = vm .frame . Stack [:p ]
785
817
vm .Call (fn , args , kwargs )
786
818
}
787
819
@@ -891,7 +923,7 @@ func do_CALL_FUNCTION_VAR_KW(vm *Vm, argc int32) {
891
923
// NotImplemented
892
924
func (vm * Vm ) NotImplemented (name string , arg int32 ) {
893
925
fmt .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 )
895
927
panic (fmt .Sprintf ("Opcode %s %d NOT IMPLEMENTED" , name , arg ))
896
928
}
897
929
@@ -922,20 +954,8 @@ func (vm *Vm) Call(fnObj py.Object, args []py.Object, kwargsTuple []py.Object) {
922
954
fnObj = vm .frame .Lookup (string (fn ))
923
955
}
924
956
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 ))
939
959
}
940
960
941
961
// 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) {
945
965
Locals : locals ,
946
966
Code : code ,
947
967
Builtins : py .Builtins .Globals ,
968
+ Stack : make ([]py.Object , 0 , code .Stacksize ),
948
969
}
949
970
vm .frames = append (vm .frames , frame )
950
971
vm .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
1013
1034
}
1014
1035
vm .extended = false
1015
1036
jumpTable [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
+ }
1026
1045
}
1027
- return vm .POP () , nil
1046
+ return vm .result , nil
1028
1047
}
0 commit comments