11// Evaluate opcodes
22package vm
33
4+ // FIXME make opcode its own type so can stringer
5+
46// FIXME use LocalVars instead of storing everything in the Locals dict
57// see frameobject.c dict_to_map and LocalsToFast
68
@@ -34,6 +36,7 @@ objects so they can be GCed
3436*/
3537
3638import (
39+ "fmt"
3740 "runtime/debug"
3841 "strings"
3942
@@ -48,9 +51,13 @@ const (
4851 cannotCatchMsg = "catching '%s' that does not inherit from BaseException is not allowed"
4952)
5053
54+ const debugging = false
55+
5156// Debug print
5257func debugf (format string , a ... interface {}) {
53- // fmt.Printf(format, a...)
58+ if debugging {
59+ fmt .Printf (format , a ... )
60+ }
5461}
5562
5663// Stack operations
@@ -108,43 +115,33 @@ func (vm *Vm) AddTraceback(exc *py.ExceptionInfo) {
108115// The exception must be a valid exception instance (eg as returned by
109116// py.MakeException)
110117//
111- // It sets vm.exc .* and sets vm.exit to exitException
118+ // It sets vm.curexc .* and sets vm.exit to exitException
112119func (vm * Vm ) SetException (exception py.Object ) {
113- vm .old_exc = vm .exc
114- vm .exc .Value = exception
115- vm .exc .Type = exception .Type ()
116- vm .exc .Traceback = nil
117- vm .AddTraceback (& vm .exc )
120+ vm .curexc .Value = exception
121+ vm .curexc .Type = exception .Type ()
122+ vm .curexc .Traceback = nil
123+ vm .AddTraceback (& vm .curexc )
118124 vm .exit = exitException
119125}
120126
121- // Clears the current exception
122- //
123- // Doesn't adjust the exit code
124- func (vm * Vm ) ClearException () {
125- // Clear the exception
126- vm .exc .Type = nil
127- vm .exc .Value = nil
128- vm .exc .Traceback = nil
129- }
130-
131127// Check for an exception (panic)
132128//
133129// Should be called with the result of recover
134130func (vm * Vm ) CheckExceptionRecover (r interface {}) {
135131 // If what was raised was an ExceptionInfo the stuff this into the current vm
136132 if exc , ok := r .(py.ExceptionInfo ); ok {
137- vm .old_exc = vm .exc
138- vm .exc = exc
139- vm .AddTraceback (& vm .exc )
133+ vm .curexc = exc
134+ vm .AddTraceback (& vm .curexc )
140135 vm .exit = exitException
141136 debugf ("*** Propagating exception: %s\n " , exc .Error ())
142137 } else {
143138 // Coerce whatever was raised into a *Exception
144139 vm .SetException (py .MakeException (r ))
145140 debugf ("*** Exception raised %v\n " , r )
146141 // Dump the goroutine stack
147- debug .PrintStack ()
142+ if debugging {
143+ debug .PrintStack ()
144+ }
148145 }
149146}
150147
@@ -153,24 +150,11 @@ func (vm *Vm) CheckExceptionRecover(r interface{}) {
153150// Must be called as a defer function
154151func (vm * Vm ) CheckException () {
155152 if r := recover (); r != nil {
153+ debugf ("*** Panic recovered %v\n " , r )
156154 vm .CheckExceptionRecover (r )
157155 }
158156}
159157
160- // Checks if r is StopIteration and if so returns true
161- //
162- // Otherwise deals with the as per vm.CheckException and returns false
163- func (vm * Vm ) catchStopIteration (r interface {}) bool {
164- if py .IsException (py .StopIteration , r ) {
165- // StopIteration or subclass raises
166- return true
167- } else {
168- // Deal with the exception as normal
169- vm .CheckExceptionRecover (r )
170- }
171- return false
172- }
173-
174158// Illegal instruction
175159func do_ILLEGAL (vm * Vm , arg int32 ) {
176160 defer vm .CheckException ()
@@ -722,9 +706,13 @@ func do_POP_EXCEPT(vm *Vm, arg int32) {
722706func do_END_FINALLY (vm * Vm , arg int32 ) {
723707 defer vm .CheckException ()
724708 v := vm .POP ()
725- debugf ("END_FINALLY v=%v\n " , v )
726- if vInt , ok := v .(py.Int ); ok {
709+ debugf ("END_FINALLY v=%#v\n " , v )
710+ if v == py .None {
711+ // None exception
712+ debugf (" END_FINALLY: None\n " )
713+ } else if vInt , ok := v .(py.Int ); ok {
727714 vm .exit = vmExit (vInt )
715+ debugf (" END_FINALLY: Int %v\n " , vm .exit )
728716 switch vm .exit {
729717 case exitYield :
730718 panic ("Unexpected exitYield in END_FINALLY" )
@@ -749,15 +737,14 @@ func do_END_FINALLY(vm *Vm, arg int32) {
749737 } else if py .ExceptionClassCheck (v ) {
750738 w := vm .POP ()
751739 u := vm .POP ()
740+ debugf (" END_FINALLY: Exc %v, Type %v, Traceback %v\n " , v , w , u )
752741 // FIXME PyErr_Restore(v, w, u)
753- vm .exc .Type = v .(* py.Type )
754- vm .exc .Value = w
755- vm .exc .Traceback = u .(* py.Traceback )
756- vm .exit = exitReraise
757- } else if v != py .None {
758- vm .SetException (py .ExceptionNewf (py .SystemError , "'finally' pops bad exception %#v" , v ))
742+ vm .curexc .Type , _ = v .(* py.Type )
743+ vm .curexc .Value = w
744+ vm .curexc .Traceback , _ = u .(* py.Traceback )
745+ vm .exit = exitException
759746 } else {
760- vm .ClearException ( )
747+ vm .SetException ( py . ExceptionNewf ( py . SystemError , "'finally' pops bad exception %#v" , v ) )
761748 }
762749 debugf ("END_FINALLY: vm.exit = %v\n " , vm .exit )
763750}
@@ -1269,8 +1256,11 @@ func (vm *Vm) raise(exc, cause py.Object) {
12691256 if ! vm .exc .IsSet () {
12701257 vm .SetException (py .ExceptionNewf (py .RuntimeError , "No active exception to reraise" ))
12711258 } else {
1259+ // Resignal the exception
1260+ vm .curexc = vm .exc
12721261 // Signal the existing exception again
1273- vm .exit = exitReraise
1262+ vm .exit = exitException
1263+
12741264 }
12751265 } else {
12761266 // raise <instance>
@@ -1504,9 +1494,9 @@ func (vm *Vm) UnwindExceptHandler(frame *py.Frame, block *py.TryBlock) {
15041494 frame .Stack = frame .Stack [:block .Level + 3 ]
15051495 }
15061496 debugf ("** UnwindExceptHandler stack depth now %v\n " , vm .STACK_LEVEL ())
1507- vm .exc .Type = vm .POP ().(* py.Type )
1497+ vm .exc .Type , _ = vm .POP ().(* py.Type )
15081498 vm .exc .Value = vm .POP ()
1509- vm .exc .Traceback = vm .POP ().(* py.Traceback )
1499+ vm .exc .Traceback , _ = vm .POP ().(* py.Traceback )
15101500 debugf ("** UnwindExceptHandler exc = (type: %v, value: %v, traceback: %v)\n " , vm .exc .Type , vm .exc .Value , vm .exc .Traceback )
15111501}
15121502
@@ -1565,6 +1555,9 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
15651555 // }
15661556 // }
15671557 }
1558+ if vm .exit == exitYield {
1559+ goto fast_yield
1560+ }
15681561
15691562 // Something exceptional has happened - unwind the block stack
15701563 // and find out what
@@ -1574,8 +1567,11 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
15741567 b := frame .Block
15751568 debugf ("*** Unwinding %#v vm %#v\n " , b , vm )
15761569
1577- if vm .exit == exitYield {
1578- return vm .result , nil
1570+ if b .Type == SETUP_LOOP && vm .exit == exitContinue {
1571+ vm .exit = exitNot
1572+ dest := vm .result .(py.Int )
1573+ frame .Lasti = int32 (dest )
1574+ break
15791575 }
15801576
15811577 // Now we have to pop the block.
@@ -1593,18 +1589,25 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
15931589 frame .Lasti = b .Handler
15941590 break
15951591 }
1596- if ( vm .exit == exitException || vm . exit == exitReraise ) && (b .Type == SETUP_EXCEPT || b .Type == SETUP_FINALLY ) {
1592+ if vm .exit == exitException && (b .Type == SETUP_EXCEPT || b .Type == SETUP_FINALLY ) {
15971593 debugf ("*** Exception\n " )
15981594 handler := b .Handler
15991595 // This invalidates b
16001596 frame .PushBlock (EXCEPT_HANDLER , - 1 , vm .STACK_LEVEL ())
16011597 vm .PUSH (vm .exc .Traceback )
16021598 vm .PUSH (vm .exc .Value )
1603- vm .PUSH (vm .exc .Type ) // can be nil
1599+ if vm .exc .Type == nil {
1600+ vm .PUSH (py .None )
1601+ } else {
1602+ vm .PUSH (vm .exc .Type ) // can be nil
1603+ }
16041604 // FIXME PyErr_Fetch(&exc, &val, &tb)
1605- exc := vm .exc .Type
1606- val := vm .exc .Value
1607- tb := vm .exc .Traceback
1605+ exc := vm .curexc .Type
1606+ val := vm .curexc .Value
1607+ tb := vm .curexc .Traceback
1608+ vm .curexc .Type = nil
1609+ vm .curexc .Value = nil
1610+ vm .curexc .Traceback = nil
16081611 // Make the raw exception data
16091612 // available to the handler,
16101613 // so a program can emulate the
@@ -1616,7 +1619,11 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
16161619 vm .exc .Traceback = tb
16171620 vm .PUSH (tb )
16181621 vm .PUSH (val )
1619- vm .PUSH (exc )
1622+ if exc == nil {
1623+ vm .PUSH (py .None )
1624+ } else {
1625+ vm .PUSH (exc )
1626+ }
16201627 vm .exit = exitNot
16211628 frame .Lasti = handler
16221629 break
@@ -1632,8 +1639,41 @@ func RunFrame(frame *py.Frame) (res py.Object, err error) {
16321639 }
16331640 }
16341641 }
1635- if vm .exc .IsSet () {
1636- return vm .result , vm .exc
1642+ debugf ("EXIT with %v\n " , vm .exit )
1643+ if vm .exit != exitReturn {
1644+ vm .result = nil
1645+ }
1646+ if vm .result == nil && ! vm .curexc .IsSet () {
1647+ panic ("vm: no result or exception" )
1648+ }
1649+ if vm .result != nil && vm .curexc .IsSet () {
1650+ panic ("vm: result and exception" )
1651+ }
1652+
1653+ fast_yield:
1654+ // FIXME
1655+ // if (co->co_flags & CO_GENERATOR) {
1656+ // /* The purpose of this block is to put aside the generator's exception
1657+ // state and restore that of the calling frame. If the current
1658+ // exception state is from the caller, we clear the exception values
1659+ // on the generator frame, so they are not swapped back in latter. The
1660+ // origin of the current exception state is determined by checking for
1661+ // except handler blocks, which we must be in iff a new exception
1662+ // state came into existence in this frame. (An uncaught exception
1663+ // would have why == WHY_EXCEPTION, and we wouldn't be here). */
1664+ // int i;
1665+ // for (i = 0; i < f->f_iblock; i++)
1666+ // if (f->f_blockstack[i].b_type == EXCEPT_HANDLER)
1667+ // break;
1668+ // if (i == f->f_iblock)
1669+ // /* We did not create this exception. */
1670+ // restore_and_clear_exc_state(tstate, f);
1671+ // else
1672+ // swap_exc_state(tstate, f);
1673+ // }
1674+
1675+ if vm .curexc .IsSet () {
1676+ return vm .result , vm .curexc
16371677 }
16381678 return vm .result , nil
16391679}
0 commit comments