Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
c86ac884
Commit
c86ac884
authored
Jun 11, 2008
by
Benjamin Peterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
#3021: Antoine Pitrou's Lexical exception handlers
parent
55d03e06
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
410 additions
and
303 deletions
+410
-303
Doc/library/dis.rst
Doc/library/dis.rst
+21
-15
Doc/library/inspect.rst
Doc/library/inspect.rst
+0
-11
Doc/library/sys.rst
Doc/library/sys.rst
+2
-2
Doc/reference/datamodel.rst
Doc/reference/datamodel.rst
+4
-9
Include/frameobject.h
Include/frameobject.h
+7
-7
Include/opcode.h
Include/opcode.h
+8
-0
Lib/doctest.py
Lib/doctest.py
+3
-4
Lib/inspect.py
Lib/inspect.py
+0
-3
Lib/opcode.py
Lib/opcode.py
+1
-0
Lib/test/test_exceptions.py
Lib/test/test_exceptions.py
+108
-0
Lib/test/test_raise.py
Lib/test/test_raise.py
+72
-1
Misc/NEWS
Misc/NEWS
+4
-0
Misc/cheatsheet
Misc/cheatsheet
+0
-3
Objects/frameobject.c
Objects/frameobject.c
+0
-3
Python/ceval.c
Python/ceval.c
+151
-240
Python/compile.c
Python/compile.c
+27
-4
Python/import.c
Python/import.c
+2
-1
No files found.
Doc/library/dis.rst
View file @
c86ac884
...
@@ -397,6 +397,14 @@ Miscellaneous opcodes.
...
@@ -397,6 +397,14 @@ Miscellaneous opcodes.
denoting nested loops, try statements, and such.
denoting nested loops, try statements, and such.
.. opcode:: POP_EXCEPT ()
Removes one block from the block stack. The popped block must be an exception
handler block, as implicitly created when entering an except handler.
In addition to popping extraneous values from the frame stack, the
last three popped values are used to restore the exception state.
.. opcode:: END_FINALLY ()
.. opcode:: END_FINALLY ()
Terminates a :keyword:`finally` clause. The interpreter recalls whether the
Terminates a :keyword:`finally` clause. The interpreter recalls whether the
...
@@ -412,24 +420,22 @@ Miscellaneous opcodes.
...
@@ -412,24 +420,22 @@ Miscellaneous opcodes.
.. opcode:: WITH_CLEANUP ()
.. opcode:: WITH_CLEANUP ()
Cleans up the stack when a :keyword:`with` statement block exits. On top of
Cleans up the stack when a :keyword:`with` statement block exits. TOS is
the stack are 1--3 values indicating how/why the finally clause was entered:
the context manager's :meth:`__exit__` bound method. Below TOS are 1--3
values indicating how/why the finally clause was entered:
* TOP = ``None``
* (TOP, SECOND) = (``WHY_{RETURN,CONTINUE}``), retval
* TOP = ``WHY_*``; no retval below it
* (TOP, SECOND, THIRD) = exc_info()
Under them is EXIT, the context manager's :meth:`__exit__` bound method.
* SECOND = ``None``
* (SECOND, THIRD) = (``WHY_{RETURN,CONTINUE}``), retval
* SECOND = ``WHY_*``; no retval below it
* (SECOND, THIRD, FOURTH) = exc_info()
In the last case, ``
EXIT(TOP, SECOND, THIRD
)`` is called, otherwise
In the last case, ``
TOS(SECOND, THIRD, FOURTH
)`` is called, otherwise
``
EXIT(None, None, None)``
.
``
TOS(None, None, None)``. In addition, TOS is removed from the stack
.
EXIT is removed from the stack, leaving the values above it in the same
If the stack represents an exception, *and* the function call returns
order. In addition, if the stack represents an exception, *and* the function
a 'true' value, this information is "zapped" and replaced with a single
call returns a 'true' value, this information is "zapped", to prevent
``WHY_SILENCED`` to prevent ``END_FINALLY`` from re-raising the exception.
``END_FINALLY`` from re-raising the exception. (But non-local gotos should
(But non-local gotos will still be resumed.)
still be resumed.)
.. XXX explain the WHY stuff!
.. XXX explain the WHY stuff!
...
...
Doc/library/inspect.rst
View file @
c86ac884
...
@@ -94,17 +94,6 @@ attributes:
...
@@ -94,17 +94,6 @@ attributes:
| | f_code | code object being |
| | f_code | code object being |
| | | executed in this frame |
| | | executed in this frame |
+-----------+-----------------+---------------------------+
+-----------+-----------------+---------------------------+
| | f_exc_traceback | traceback if raised in |
| | | this frame, or ``None`` |
+-----------+-----------------+---------------------------+
| | f_exc_type | exception type if raised |
| | | in this frame, or |
| | | ``None`` |
+-----------+-----------------+---------------------------+
| | f_exc_value | exception value if raised |
| | | in this frame, or |
| | | ``None`` |
+-----------+-----------------+---------------------------+
| | f_globals | global namespace seen by |
| | f_globals | global namespace seen by |
| | | this frame |
| | | this frame |
+-----------+-----------------+---------------------------+
+-----------+-----------------+---------------------------+
...
...
Doc/library/sys.rst
View file @
c86ac884
...
@@ -136,8 +136,8 @@ always available.
...
@@ -136,8 +136,8 @@ always available.
frame is not handling an exception, the information is taken from the calling
frame is not handling an exception, the information is taken from the calling
stack frame, or its caller, and so on until a stack frame is found that is
stack frame, or its caller, and so on until a stack frame is found that is
handling an exception. Here, "handling an exception" is defined as "executing
handling an exception. Here, "handling an exception" is defined as "executing
or having executed an except clause." For any stack frame, only informa
tion
an except clause." For any stack frame, only information about the excep
tion
about the most recently handled exception
is accessible.
being currently handled
is accessible.
.. index:: object: traceback
.. index:: object: traceback
...
...
Doc/reference/datamodel.rst
View file @
c86ac884
...
@@ -875,19 +875,14 @@ Internal types
...
@@ -875,19 +875,14 @@ Internal types
.. index::
.. index::
single: f_trace (frame attribute)
single: f_trace (frame attribute)
single: f_exc_type (frame attribute)
single: f_exc_value (frame attribute)
single: f_exc_traceback (frame attribute)
single: f_lineno (frame attribute)
single: f_lineno (frame attribute)
Special writable attributes: :attr:`f_trace`, if not ``None``, is a function
Special writable attributes: :attr:`f_trace`, if not ``None``, is a function
called at the start of each source code line (this is used by the debugger);
called at the start of each source code line (this is used by the debugger);
:attr:`f_exc_type`, :attr:`f_exc_value`, :attr:`f_exc_traceback` represent the
:attr:`f_lineno` is the current line number of the frame --- writing to this
last exception raised in the parent frame provided another exception was ever
from within a trace function jumps to the given line (only for the bottom-most
raised in the current frame (in all other cases they are None); :attr:`f_lineno`
frame). A debugger can implement a Jump command (aka Set Next Statement)
is the current line number of the frame --- writing to this from within a trace
by writing to f_lineno.
function jumps to the given line (only for the bottom-most frame). A debugger
can implement a Jump command (aka Set Next Statement) by writing to f_lineno.
Traceback objects
Traceback objects
.. index::
.. index::
...
...
Include/frameobject.h
View file @
c86ac884
...
@@ -27,13 +27,13 @@ typedef struct _frame {
...
@@ -27,13 +27,13 @@ typedef struct _frame {
PyObject
**
f_stacktop
;
PyObject
**
f_stacktop
;
PyObject
*
f_trace
;
/* Trace function */
PyObject
*
f_trace
;
/* Trace function */
/* If an exception is raised in this frame, the next three are used to
/* In a generator, we need to be able to swap between the exception
* record the exception info (if any) originally in the thread state. See
state inside the generator and the exception state of the calling
* comments before set_exc_info() -- it's not obvious.
frame (which shouldn't be impacted when the generator "yields"
* Invariant: if _type is NULL, then so are _value and _traceback
.
from an except handler)
.
* Desired invariant: all three are NULL, or all three are non-NULL. That
These three fields exist exactly for that, and are unused for
* one isn't currently true, but "should be".
non-generator frames. See the SAVE_EXC_STATE and SWAP_EXC_STATE
*/
macros in ceval.c for details of their use.
*/
PyObject
*
f_exc_type
,
*
f_exc_value
,
*
f_exc_traceback
;
PyObject
*
f_exc_type
,
*
f_exc_value
,
*
f_exc_traceback
;
PyThreadState
*
f_tstate
;
PyThreadState
*
f_tstate
;
...
...
Include/opcode.h
View file @
c86ac884
...
@@ -70,6 +70,7 @@ extern "C" {
...
@@ -70,6 +70,7 @@ extern "C" {
#define YIELD_VALUE 86
#define YIELD_VALUE 86
#define POP_BLOCK 87
#define POP_BLOCK 87
#define END_FINALLY 88
#define END_FINALLY 88
#define POP_EXCEPT 89
#define HAVE_ARGUMENT 90
/* Opcodes from here have an argument: */
#define HAVE_ARGUMENT 90
/* Opcodes from here have an argument: */
...
@@ -133,6 +134,13 @@ extern "C" {
...
@@ -133,6 +134,13 @@ extern "C" {
#define EXTENDED_ARG 143
#define EXTENDED_ARG 143
/* EXCEPT_HANDLER is a special, implicit block type which is created when
entering an except handler. It is not an opcode but we define it here
as we want it to be available to both frameobject.c and ceval.c, while
remaining private.*/
#define EXCEPT_HANDLER 257
enum
cmp_op
{
PyCmp_LT
=
Py_LT
,
PyCmp_LE
=
Py_LE
,
PyCmp_EQ
=
Py_EQ
,
PyCmp_NE
=
Py_NE
,
PyCmp_GT
=
Py_GT
,
PyCmp_GE
=
Py_GE
,
enum
cmp_op
{
PyCmp_LT
=
Py_LT
,
PyCmp_LE
=
Py_LE
,
PyCmp_EQ
=
Py_EQ
,
PyCmp_NE
=
Py_NE
,
PyCmp_GT
=
Py_GT
,
PyCmp_GE
=
Py_GE
,
PyCmp_IN
,
PyCmp_NOT_IN
,
PyCmp_IS
,
PyCmp_IS_NOT
,
PyCmp_EXC_MATCH
,
PyCmp_BAD
};
PyCmp_IN
,
PyCmp_NOT_IN
,
PyCmp_IS
,
PyCmp_IS_NOT
,
PyCmp_EXC_MATCH
,
PyCmp_BAD
};
...
...
Lib/doctest.py
View file @
c86ac884
...
@@ -1242,10 +1242,9 @@ class DocTestRunner:
...
@@ -1242,10 +1242,9 @@ class DocTestRunner:
# The example raised an exception: check if it was expected.
# The example raised an exception: check if it was expected.
else
:
else
:
exc_info
=
sys
.
exc_info
()
exc_msg
=
traceback
.
format_exception_only
(
*
exception
[:
2
])[
-
1
]
exc_msg
=
traceback
.
format_exception_only
(
*
exc_info
[:
2
])[
-
1
]
if
not
quiet
:
if
not
quiet
:
got
+=
_exception_traceback
(
exc
_info
)
got
+=
_exception_traceback
(
exc
eption
)
# If `example.exc_msg` is None, then we weren't expecting
# If `example.exc_msg` is None, then we weren't expecting
# an exception.
# an exception.
...
@@ -1275,7 +1274,7 @@ class DocTestRunner:
...
@@ -1275,7 +1274,7 @@ class DocTestRunner:
elif
outcome
is
BOOM
:
elif
outcome
is
BOOM
:
if
not
quiet
:
if
not
quiet
:
self
.
report_unexpected_exception
(
out
,
test
,
example
,
self
.
report_unexpected_exception
(
out
,
test
,
example
,
exc
_info
)
exc
eption
)
failures
+=
1
failures
+=
1
else
:
else
:
assert
False
,
(
"unknown outcome"
,
outcome
)
assert
False
,
(
"unknown outcome"
,
outcome
)
...
...
Lib/inspect.py
View file @
c86ac884
...
@@ -197,9 +197,6 @@ def isframe(object):
...
@@ -197,9 +197,6 @@ def isframe(object):
f_back next outer frame object (this frame's caller)
f_back next outer frame object (this frame's caller)
f_builtins built-in namespace seen by this frame
f_builtins built-in namespace seen by this frame
f_code code object being executed in this frame
f_code code object being executed in this frame
f_exc_traceback traceback if raised in this frame, or None
f_exc_type exception type if raised in this frame, or None
f_exc_value exception value if raised in this frame, or None
f_globals global namespace seen by this frame
f_globals global namespace seen by this frame
f_lasti index of last attempted instruction in bytecode
f_lasti index of last attempted instruction in bytecode
f_lineno current line number in Python source code
f_lineno current line number in Python source code
...
...
Lib/opcode.py
View file @
c86ac884
...
@@ -105,6 +105,7 @@ def_op('MAKE_BYTES', 85)
...
@@ -105,6 +105,7 @@ def_op('MAKE_BYTES', 85)
def_op
(
'YIELD_VALUE'
,
86
)
def_op
(
'YIELD_VALUE'
,
86
)
def_op
(
'POP_BLOCK'
,
87
)
def_op
(
'POP_BLOCK'
,
87
)
def_op
(
'END_FINALLY'
,
88
)
def_op
(
'END_FINALLY'
,
88
)
def_op
(
'POP_EXCEPT'
,
89
)
HAVE_ARGUMENT
=
90
# Opcodes from here have an argument:
HAVE_ARGUMENT
=
90
# Opcodes from here have an argument:
...
...
Lib/test/test_exceptions.py
View file @
c86ac884
...
@@ -427,6 +427,7 @@ class ExceptionTests(unittest.TestCase):
...
@@ -427,6 +427,7 @@ class ExceptionTests(unittest.TestCase):
local_ref
=
obj
local_ref
=
obj
raise
MyException
(
obj
)
raise
MyException
(
obj
)
# Qualified "except" with "as"
obj
=
MyObj
()
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
wr
=
weakref
.
ref
(
obj
)
try
:
try
:
...
@@ -437,6 +438,113 @@ class ExceptionTests(unittest.TestCase):
...
@@ -437,6 +438,113 @@ class ExceptionTests(unittest.TestCase):
obj
=
wr
()
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# Qualified "except" without "as"
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
try
:
inner_raising_func
()
except
MyException
:
pass
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# Bare "except"
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
try
:
inner_raising_func
()
except
:
pass
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# "except" with premature block leave
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
for
i
in
[
0
]:
try
:
inner_raising_func
()
except
:
break
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# "except" block raising another exception
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
try
:
try
:
inner_raising_func
()
except
:
raise
KeyError
except
KeyError
:
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# Some complicated construct
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
try
:
inner_raising_func
()
except
MyException
:
try
:
try
:
raise
finally
:
raise
except
MyException
:
pass
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
# Inside an exception-silencing "with" block
class
Context
:
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
exc_type
,
exc_value
,
exc_tb
):
return
True
obj
=
MyObj
()
wr
=
weakref
.
ref
(
obj
)
with
Context
():
inner_raising_func
()
obj
=
None
obj
=
wr
()
self
.
failUnless
(
obj
is
None
,
"%s"
%
obj
)
def
test_generator_leaking
(
self
):
# Test that generator exception state doesn't leak into the calling
# frame
def
yield_raise
():
try
:
raise
KeyError
(
"caught"
)
except
KeyError
:
yield
sys
.
exc_info
()[
0
]
yield
sys
.
exc_info
()[
0
]
yield
sys
.
exc_info
()[
0
]
g
=
yield_raise
()
self
.
assertEquals
(
next
(
g
),
KeyError
)
self
.
assertEquals
(
sys
.
exc_info
()[
0
],
None
)
self
.
assertEquals
(
next
(
g
),
KeyError
)
self
.
assertEquals
(
sys
.
exc_info
()[
0
],
None
)
self
.
assertEquals
(
next
(
g
),
None
)
# Same test, but inside an exception handler
try
:
raise
TypeError
(
"foo"
)
except
TypeError
:
g
=
yield_raise
()
self
.
assertEquals
(
next
(
g
),
KeyError
)
self
.
assertEquals
(
sys
.
exc_info
()[
0
],
TypeError
)
self
.
assertEquals
(
next
(
g
),
KeyError
)
self
.
assertEquals
(
sys
.
exc_info
()[
0
],
TypeError
)
self
.
assertEquals
(
next
(
g
),
TypeError
)
del
g
self
.
assertEquals
(
sys
.
exc_info
()[
0
],
TypeError
)
def
test_main
():
def
test_main
():
run_unittest
(
ExceptionTests
)
run_unittest
(
ExceptionTests
)
...
...
Lib/test/test_raise.py
View file @
c86ac884
...
@@ -16,6 +16,13 @@ def get_tb():
...
@@ -16,6 +16,13 @@ def get_tb():
return
sys
.
exc_info
()[
2
]
return
sys
.
exc_info
()[
2
]
class
Context
:
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
exc_type
,
exc_value
,
exc_tb
):
return
True
class
TestRaise
(
unittest
.
TestCase
):
class
TestRaise
(
unittest
.
TestCase
):
def
test_invalid_reraise
(
self
):
def
test_invalid_reraise
(
self
):
try
:
try
:
...
@@ -37,6 +44,71 @@ class TestRaise(unittest.TestCase):
...
@@ -37,6 +44,71 @@ class TestRaise(unittest.TestCase):
else
:
else
:
self
.
fail
(
"No exception raised"
)
self
.
fail
(
"No exception raised"
)
def
test_except_reraise
(
self
):
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
try
:
raise
KeyError
(
"caught"
)
except
KeyError
:
pass
raise
self
.
assertRaises
(
TypeError
,
reraise
)
def
test_finally_reraise
(
self
):
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
try
:
raise
KeyError
(
"caught"
)
finally
:
raise
self
.
assertRaises
(
KeyError
,
reraise
)
def
test_nested_reraise
(
self
):
def
nested_reraise
():
raise
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
nested_reraise
()
self
.
assertRaises
(
TypeError
,
reraise
)
def
test_with_reraise1
(
self
):
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
with
Context
():
pass
raise
self
.
assertRaises
(
TypeError
,
reraise
)
def
test_with_reraise2
(
self
):
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
with
Context
():
raise
KeyError
(
"caught"
)
raise
self
.
assertRaises
(
TypeError
,
reraise
)
def
test_yield_reraise
(
self
):
def
reraise
():
try
:
raise
TypeError
(
"foo"
)
except
:
yield
1
raise
g
=
reraise
()
next
(
g
)
self
.
assertRaises
(
TypeError
,
lambda
:
next
(
g
))
self
.
assertRaises
(
StopIteration
,
lambda
:
next
(
g
))
def
test_erroneous_exception
(
self
):
def
test_erroneous_exception
(
self
):
class
MyException
(
Exception
):
class
MyException
(
Exception
):
def
__init__
(
self
):
def
__init__
(
self
):
...
@@ -158,6 +230,5 @@ class TestRemovedFunctionality(unittest.TestCase):
...
@@ -158,6 +230,5 @@ class TestRemovedFunctionality(unittest.TestCase):
def
test_main
():
def
test_main
():
support
.
run_unittest
(
__name__
)
support
.
run_unittest
(
__name__
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
unittest
.
main
()
unittest
.
main
()
Misc/NEWS
View file @
c86ac884
...
@@ -49,6 +49,10 @@ Core and Builtins
...
@@ -49,6 +49,10 @@ Core and Builtins
Exception (KeyboardInterrupt, and SystemExit) propagate instead of
Exception (KeyboardInterrupt, and SystemExit) propagate instead of
ignoring them.
ignoring them.
- #3021 Exception reraising sematics have been significantly improved. However,
f_exc_type, f_exc_value, and f_exc_traceback cannot be accessed from Python
code anymore.
Extension Modules
Extension Modules
-----------------
-----------------
...
...
Misc/cheatsheet
View file @
c86ac884
...
@@ -1262,9 +1262,6 @@ Special informative state attributes for some types:
...
@@ -1262,9 +1262,6 @@ Special informative state attributes for some types:
f_lineno (int, R/O): current line number
f_lineno (int, R/O): current line number
f_lasti (int, R/O): precise instruction (index into bytecode)
f_lasti (int, R/O): precise instruction (index into bytecode)
f_trace (function/None, R/W): debug hook called at start of each source line
f_trace (function/None, R/W): debug hook called at start of each source line
f_exc_type (Type/None, R/W): Most recent exception type
f_exc_value (any, R/W): Most recent exception value
f_exc_traceback (traceback/None, R/W): Most recent exception traceback
Tracebacks:
Tracebacks:
tb_next (frame/None, R/O): next level in stack trace (toward the frame where
tb_next (frame/None, R/O): next level in stack trace (toward the frame where
the exception occurred)
the exception occurred)
...
...
Objects/frameobject.c
View file @
c86ac884
...
@@ -20,9 +20,6 @@ static PyMemberDef frame_memberlist[] = {
...
@@ -20,9 +20,6 @@ static PyMemberDef frame_memberlist[] = {
{
"f_builtins"
,
T_OBJECT
,
OFF
(
f_builtins
),
READONLY
},
{
"f_builtins"
,
T_OBJECT
,
OFF
(
f_builtins
),
READONLY
},
{
"f_globals"
,
T_OBJECT
,
OFF
(
f_globals
),
READONLY
},
{
"f_globals"
,
T_OBJECT
,
OFF
(
f_globals
),
READONLY
},
{
"f_lasti"
,
T_INT
,
OFF
(
f_lasti
),
READONLY
},
{
"f_lasti"
,
T_INT
,
OFF
(
f_lasti
),
READONLY
},
{
"f_exc_type"
,
T_OBJECT
,
OFF
(
f_exc_type
)},
{
"f_exc_value"
,
T_OBJECT
,
OFF
(
f_exc_value
)},
{
"f_exc_traceback"
,
T_OBJECT
,
OFF
(
f_exc_traceback
)},
{
NULL
}
/* Sentinel */
{
NULL
}
/* Sentinel */
};
};
...
...
Python/ceval.c
View file @
c86ac884
...
@@ -116,8 +116,6 @@ static int maybe_call_line_trace(Py_tracefunc, PyObject *,
...
@@ -116,8 +116,6 @@ static int maybe_call_line_trace(Py_tracefunc, PyObject *,
static
PyObject
*
cmp_outcome
(
int
,
PyObject
*
,
PyObject
*
);
static
PyObject
*
cmp_outcome
(
int
,
PyObject
*
,
PyObject
*
);
static
PyObject
*
import_from
(
PyObject
*
,
PyObject
*
);
static
PyObject
*
import_from
(
PyObject
*
,
PyObject
*
);
static
int
import_all_from
(
PyObject
*
,
PyObject
*
);
static
int
import_all_from
(
PyObject
*
,
PyObject
*
);
static
void
set_exc_info
(
PyThreadState
*
,
PyObject
*
,
PyObject
*
,
PyObject
*
);
static
void
reset_exc_info
(
PyThreadState
*
);
static
void
format_exc_check_arg
(
PyObject
*
,
const
char
*
,
PyObject
*
);
static
void
format_exc_check_arg
(
PyObject
*
,
const
char
*
,
PyObject
*
);
static
PyObject
*
unicode_concatenate
(
PyObject
*
,
PyObject
*
,
static
PyObject
*
unicode_concatenate
(
PyObject
*
,
PyObject
*
,
PyFrameObject
*
,
unsigned
char
*
);
PyFrameObject
*
,
unsigned
char
*
);
...
@@ -483,7 +481,8 @@ enum why_code {
...
@@ -483,7 +481,8 @@ enum why_code {
WHY_RETURN
=
0x0008
,
/* 'return' statement */
WHY_RETURN
=
0x0008
,
/* 'return' statement */
WHY_BREAK
=
0x0010
,
/* 'break' statement */
WHY_BREAK
=
0x0010
,
/* 'break' statement */
WHY_CONTINUE
=
0x0020
,
/* 'continue' statement */
WHY_CONTINUE
=
0x0020
,
/* 'continue' statement */
WHY_YIELD
=
0x0040
/* 'yield' operator */
WHY_YIELD
=
0x0040
,
/* 'yield' operator */
WHY_SILENCED
=
0x0080
/* Exception silenced by 'with' */
};
};
static
enum
why_code
do_raise
(
PyObject
*
,
PyObject
*
);
static
enum
why_code
do_raise
(
PyObject
*
,
PyObject
*
);
...
@@ -692,6 +691,53 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -692,6 +691,53 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
GETLOCAL(i) = value; \
GETLOCAL(i) = value; \
Py_XDECREF(tmp); } while (0)
Py_XDECREF(tmp); } while (0)
#define UNWIND_BLOCK(b) \
while (STACK_LEVEL() > (b)->b_level) { \
PyObject *v = POP(); \
Py_XDECREF(v); \
}
#define UNWIND_EXCEPT_HANDLER(b) \
assert(STACK_LEVEL() >= (b)->b_level + 3); \
while (STACK_LEVEL() > (b)->b_level + 3) { \
PyObject *v = POP(); \
Py_XDECREF(v); \
} \
Py_XDECREF(tstate->exc_type); \
tstate->exc_type = POP(); \
Py_XDECREF(tstate->exc_value); \
tstate->exc_value = POP(); \
Py_XDECREF(tstate->exc_traceback); \
tstate->exc_traceback = POP();
#define SAVE_EXC_STATE() \
{ \
Py_XINCREF(tstate->exc_type); \
Py_XINCREF(tstate->exc_value); \
Py_XINCREF(tstate->exc_traceback); \
Py_XDECREF(f->f_exc_type); \
Py_XDECREF(f->f_exc_value); \
Py_XDECREF(f->f_exc_traceback); \
f->f_exc_type = tstate->exc_type; \
f->f_exc_value = tstate->exc_value; \
f->f_exc_traceback = tstate->exc_traceback; \
}
#define SWAP_EXC_STATE() \
{ \
PyObject *tmp; \
tmp = tstate->exc_type; \
tstate->exc_type = f->f_exc_type; \
f->f_exc_type = tmp; \
tmp = tstate->exc_value; \
tstate->exc_value = f->f_exc_value; \
f->f_exc_value = tmp; \
tmp = tstate->exc_traceback; \
tstate->exc_traceback = f->f_exc_traceback; \
f->f_exc_traceback = tmp; \
}
/* Start of code */
/* Start of code */
if
(
f
==
NULL
)
if
(
f
==
NULL
)
...
@@ -765,6 +811,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -765,6 +811,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
assert
(
stack_pointer
!=
NULL
);
assert
(
stack_pointer
!=
NULL
);
f
->
f_stacktop
=
NULL
;
/* remains NULL unless yield suspends frame */
f
->
f_stacktop
=
NULL
;
/* remains NULL unless yield suspends frame */
if
(
f
->
f_code
->
co_flags
&
CO_GENERATOR
)
{
if
(
f
->
f_exc_type
!=
NULL
&&
f
->
f_exc_type
!=
Py_None
)
{
/* We were in an except handler when we left,
restore the exception state which was put aside
(see YIELD_VALUE). */
SWAP_EXC_STATE
();
}
else
{
SAVE_EXC_STATE
();
}
}
#ifdef LLTRACE
#ifdef LLTRACE
lltrace
=
PyDict_GetItemString
(
f
->
f_globals
,
"__lltrace__"
)
!=
NULL
;
lltrace
=
PyDict_GetItemString
(
f
->
f_globals
,
"__lltrace__"
)
!=
NULL
;
#endif
#endif
...
@@ -1443,15 +1501,29 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -1443,15 +1501,29 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
retval
=
POP
();
retval
=
POP
();
f
->
f_stacktop
=
stack_pointer
;
f
->
f_stacktop
=
stack_pointer
;
why
=
WHY_YIELD
;
why
=
WHY_YIELD
;
/* Put aside the current exception state and restore
that of the calling frame. This only serves when
"yield" is used inside an except handler. */
SWAP_EXC_STATE
();
goto
fast_yield
;
goto
fast_yield
;
case
POP_
BLOCK
:
case
POP_
EXCEPT
:
{
{
PyTryBlock
*
b
=
PyFrame_BlockPop
(
f
);
PyTryBlock
*
b
=
PyFrame_BlockPop
(
f
);
while
(
STACK_LEVEL
()
>
b
->
b_level
)
{
if
(
b
->
b_type
!=
EXCEPT_HANDLER
)
{
v
=
POP
();
PyErr_SetString
(
PyExc_SystemError
,
Py_DECREF
(
v
);
"popped block is not an except handler"
);
why
=
WHY_EXCEPTION
;
break
;
}
}
UNWIND_EXCEPT_HANDLER
(
b
);
}
continue
;
case
POP_BLOCK
:
{
PyTryBlock
*
b
=
PyFrame_BlockPop
(
f
);
UNWIND_BLOCK
(
b
);
}
}
continue
;
continue
;
...
@@ -1464,6 +1536,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -1464,6 +1536,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if
(
why
==
WHY_RETURN
||
if
(
why
==
WHY_RETURN
||
why
==
WHY_CONTINUE
)
why
==
WHY_CONTINUE
)
retval
=
POP
();
retval
=
POP
();
if
(
why
==
WHY_SILENCED
)
{
/* An exception was silenced by 'with', we must
manually unwind the EXCEPT_HANDLER block which was
created when the exception was caught, otherwise
the stack will be in an inconsistent state. */
PyTryBlock
*
b
=
PyFrame_BlockPop
(
f
);
if
(
b
->
b_type
!=
EXCEPT_HANDLER
)
{
PyErr_SetString
(
PyExc_SystemError
,
"popped block is not an except handler"
);
why
=
WHY_EXCEPTION
;
}
else
{
UNWIND_EXCEPT_HANDLER
(
b
);
why
=
WHY_NOT
;
}
}
}
}
else
if
(
PyExceptionClass_Check
(
v
))
{
else
if
(
PyExceptionClass_Check
(
v
))
{
w
=
POP
();
w
=
POP
();
...
@@ -1477,19 +1565,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -1477,19 +1565,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
"'finally' pops bad exception"
);
"'finally' pops bad exception"
);
why
=
WHY_EXCEPTION
;
why
=
WHY_EXCEPTION
;
}
}
/*
Make sure the exception state is cleaned up before
the end of an except block. This ensures objects
referenced by the exception state are not kept
alive too long.
See #2507.
*/
if
(
tstate
->
frame
->
f_exc_type
!=
NULL
)
reset_exc_info
(
tstate
);
else
{
assert
(
tstate
->
frame
->
f_exc_value
==
NULL
);
assert
(
tstate
->
frame
->
f_exc_traceback
==
NULL
);
}
Py_DECREF
(
v
);
Py_DECREF
(
v
);
break
;
break
;
...
@@ -2056,59 +2131,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
...
@@ -2056,59 +2131,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
should still be resumed.)
should still be resumed.)
*/
*/
PyObject
*
exit_func
;
PyObject
*
exit_func
=
POP
();
u
=
TOP
();
u
=
POP
();
if
(
u
==
Py_None
)
{
if
(
u
==
Py_None
)
{
exit_func
=
TOP
();
SET_TOP
(
u
);
v
=
w
=
Py_None
;
v
=
w
=
Py_None
;
}
}
else
if
(
PyLong_Check
(
u
))
{
else
if
(
PyLong_Check
(
u
))
{
switch
(
PyLong_AS_LONG
(
u
))
{
case
WHY_RETURN
:
case
WHY_CONTINUE
:
/* Retval in TOP. */
exit_func
=
SECOND
();
SET_SECOND
(
TOP
());
SET_TOP
(
u
);
break
;
default:
exit_func
=
TOP
();
SET_TOP
(
u
);
break
;
}
u
=
v
=
w
=
Py_None
;
u
=
v
=
w
=
Py_None
;
}
}
else
{
else
{
v
=
TOP
();
v
=
SECOND
();
w
=
SECOND
();
w
=
THIRD
();
exit_func
=
THIRD
();
SET_TOP
(
u
);
SET_SECOND
(
v
);
SET_THIRD
(
w
);
}
}
/* XXX Not the fastest way to call it... */
/* XXX Not the fastest way to call it... */
x
=
PyObject_CallFunctionObjArgs
(
exit_func
,
u
,
v
,
w
,
x
=
PyObject_CallFunctionObjArgs
(
exit_func
,
u
,
v
,
w
,
NULL
);
NULL
);
if
(
x
==
NULL
)
{
Py_DECREF
(
exit_func
);
Py_DECREF
(
exit_func
);
if
(
x
==
NULL
)
break
;
/* Go to error exit */
break
;
/* Go to error exit */
}
if
(
u
!=
Py_None
&&
PyObject_IsTrue
(
x
))
{
if
(
u
!=
Py_None
&&
PyObject_IsTrue
(
x
))
{
/* There was an exception and a
t
rue return */
/* There was an exception and a
T
rue return */
STACKADJ
(
-
2
);
STACKADJ
(
-
2
);
Py_INCREF
(
Py_None
);
SET_TOP
(
PyLong_FromLong
((
long
)
WHY_SILENCED
));
SET_TOP
(
Py_None
);
Py_DECREF
(
u
);
Py_DECREF
(
u
);
Py_DECREF
(
v
);
Py_DECREF
(
v
);
Py_DECREF
(
w
);
Py_DECREF
(
w
);
}
else
{
/* The stack was rearranged to remove EXIT
above. Let END_FINALLY do its thing */
}
}
Py_DECREF
(
x
);
Py_DECREF
(
x
);
Py_DECREF
(
exit_func
);
PREDICT
(
END_FINALLY
);
PREDICT
(
END_FINALLY
);
break
;
break
;
}
}
...
@@ -2370,50 +2419,63 @@ fast_block_end:
...
@@ -2370,50 +2419,63 @@ fast_block_end:
break
;
break
;
}
}
while
(
STACK_LEVEL
()
>
b
->
b_level
)
{
if
(
b
->
b_type
==
EXCEPT_HANDLER
)
{
v
=
POP
();
UNWIND_EXCEPT_HANDLER
(
b
);
Py_XDECREF
(
v
);
if
(
why
==
WHY_EXCEPTION
)
{
Py_CLEAR
(
tstate
->
exc_type
);
Py_CLEAR
(
tstate
->
exc_value
);
Py_CLEAR
(
tstate
->
exc_traceback
);
}
continue
;
}
}
UNWIND_BLOCK
(
b
);
if
(
b
->
b_type
==
SETUP_LOOP
&&
why
==
WHY_BREAK
)
{
if
(
b
->
b_type
==
SETUP_LOOP
&&
why
==
WHY_BREAK
)
{
why
=
WHY_NOT
;
why
=
WHY_NOT
;
JUMPTO
(
b
->
b_handler
);
JUMPTO
(
b
->
b_handler
);
break
;
break
;
}
}
if
(
b
->
b_type
==
SETUP_FINALLY
||
if
(
why
==
WHY_EXCEPTION
&&
(
b
->
b_type
==
SETUP_EXCEPT
(
b
->
b_type
==
SETUP_EXCEPT
&&
||
b
->
b_type
==
SETUP_FINALLY
))
{
why
==
WHY_EXCEPTION
))
{
PyObject
*
exc
,
*
val
,
*
tb
;
if
(
why
==
WHY_EXCEPTION
)
{
int
handler
=
b
->
b_handler
;
PyObject
*
exc
,
*
val
,
*
tb
;
/* Beware, this invalidates all b->b_* fields */
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
PyFrame_BlockSetup
(
f
,
EXCEPT_HANDLER
,
-
1
,
STACK_LEVEL
());
if
(
val
==
NULL
)
{
PUSH
(
tstate
->
exc_traceback
);
val
=
Py_None
;
PUSH
(
tstate
->
exc_value
);
Py_INCREF
(
val
);
if
(
tstate
->
exc_type
!=
NULL
)
{
}
PUSH
(
tstate
->
exc_type
);
/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. Don't do
this for 'finally'. */
if
(
b
->
b_type
==
SETUP_EXCEPT
)
{
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
set_exc_info
(
tstate
,
exc
,
val
,
tb
);
}
if
(
tb
==
NULL
)
{
Py_INCREF
(
Py_None
);
PUSH
(
Py_None
);
}
else
PUSH
(
tb
);
PUSH
(
val
);
PUSH
(
exc
);
}
}
else
{
else
{
if
(
why
&
(
WHY_RETURN
|
WHY_CONTINUE
))
Py_INCREF
(
Py_None
);
PUSH
(
retval
);
PUSH
(
Py_None
);
v
=
PyLong_FromLong
((
long
)
why
);
PUSH
(
v
);
}
}
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
PyException_SetTraceback
(
val
,
tb
);
Py_INCREF
(
exc
);
tstate
->
exc_type
=
exc
;
Py_INCREF
(
val
);
tstate
->
exc_value
=
val
;
tstate
->
exc_traceback
=
tb
;
if
(
tb
==
NULL
)
tb
=
Py_None
;
Py_INCREF
(
tb
);
PUSH
(
tb
);
PUSH
(
val
);
PUSH
(
exc
);
why
=
WHY_NOT
;
JUMPTO
(
handler
);
break
;
}
if
(
b
->
b_type
==
SETUP_FINALLY
)
{
if
(
why
&
(
WHY_RETURN
|
WHY_CONTINUE
))
PUSH
(
retval
);
PUSH
(
PyLong_FromLong
((
long
)
why
));
why
=
WHY_NOT
;
why
=
WHY_NOT
;
JUMPTO
(
b
->
b_handler
);
JUMPTO
(
b
->
b_handler
);
break
;
break
;
...
@@ -2471,13 +2533,6 @@ fast_yield:
...
@@ -2471,13 +2533,6 @@ fast_yield:
}
}
}
}
if
(
tstate
->
frame
->
f_exc_type
!=
NULL
)
reset_exc_info
(
tstate
);
else
{
assert
(
tstate
->
frame
->
f_exc_value
==
NULL
);
assert
(
tstate
->
frame
->
f_exc_traceback
==
NULL
);
}
/* pop frame */
/* pop frame */
exit_eval_frame:
exit_eval_frame:
Py_LeaveRecursiveCall
();
Py_LeaveRecursiveCall
();
...
@@ -2757,150 +2812,6 @@ fail: /* Jump here from prelude on failure */
...
@@ -2757,150 +2812,6 @@ fail: /* Jump here from prelude on failure */
}
}
/* Implementation notes for set_exc_info() and reset_exc_info():
- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and
'exc_traceback'. These always travel together.
- tstate->curexc_ZZZ is the "hot" exception that is set by
PyErr_SetString(), cleared by PyErr_Clear(), and so on.
- Once an exception is caught by an except clause, it is transferred
from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info()
can pick it up. This is the primary task of set_exc_info().
XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ.
- Now let me explain the complicated dance with frame->f_exc_ZZZ.
Long ago, when none of this existed, there were just a few globals:
one set corresponding to the "hot" exception, and one set
corresponding to sys.exc_ZZZ. (Actually, the latter weren't C
globals; they were simply stored as sys.exc_ZZZ. For backwards
compatibility, they still are!) The problem was that in code like
this:
try:
"something that may fail"
except "some exception":
"do something else first"
"print the exception from sys.exc_ZZZ."
if "do something else first" invoked something that raised and caught
an exception, sys.exc_ZZZ were overwritten. That was a frequent
cause of subtle bugs. I fixed this by changing the semantics as
follows:
- Within one frame, sys.exc_ZZZ will hold the last exception caught
*in that frame*.
- But initially, and as long as no exception is caught in a given
frame, sys.exc_ZZZ will hold the last exception caught in the
previous frame (or the frame before that, etc.).
The first bullet fixed the bug in the above example. The second
bullet was for backwards compatibility: it was (and is) common to
have a function that is called when an exception is caught, and to
have that function access the caught exception via sys.exc_ZZZ.
(Example: traceback.print_exc()).
At the same time I fixed the problem that sys.exc_ZZZ weren't
thread-safe, by introducing sys.exc_info() which gets it from tstate;
but that's really a separate improvement.
The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ
variables to what they were before the current frame was called. The
set_exc_info() function saves them on the frame so that
reset_exc_info() can restore them. The invariant is that
frame->f_exc_ZZZ is NULL iff the current frame never caught an
exception (where "catching" an exception applies only to successful
except clauses); and if the current frame ever caught an exception,
frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ
at the start of the current frame.
*/
static
void
set_exc_info
(
PyThreadState
*
tstate
,
PyObject
*
type
,
PyObject
*
value
,
PyObject
*
tb
)
{
PyFrameObject
*
frame
=
tstate
->
frame
;
PyObject
*
tmp_type
,
*
tmp_value
,
*
tmp_tb
;
assert
(
type
!=
NULL
);
assert
(
frame
!=
NULL
);
if
(
frame
->
f_exc_type
==
NULL
)
{
assert
(
frame
->
f_exc_value
==
NULL
);
assert
(
frame
->
f_exc_traceback
==
NULL
);
/* This frame didn't catch an exception before. */
/* Save previous exception of this thread in this frame. */
if
(
tstate
->
exc_type
==
NULL
)
{
/* XXX Why is this set to Py_None? */
Py_INCREF
(
Py_None
);
tstate
->
exc_type
=
Py_None
;
}
Py_INCREF
(
tstate
->
exc_type
);
Py_XINCREF
(
tstate
->
exc_value
);
Py_XINCREF
(
tstate
->
exc_traceback
);
frame
->
f_exc_type
=
tstate
->
exc_type
;
frame
->
f_exc_value
=
tstate
->
exc_value
;
frame
->
f_exc_traceback
=
tstate
->
exc_traceback
;
}
/* Set new exception for this thread. */
tmp_type
=
tstate
->
exc_type
;
tmp_value
=
tstate
->
exc_value
;
tmp_tb
=
tstate
->
exc_traceback
;
Py_INCREF
(
type
);
Py_XINCREF
(
value
);
Py_XINCREF
(
tb
);
tstate
->
exc_type
=
type
;
tstate
->
exc_value
=
value
;
tstate
->
exc_traceback
=
tb
;
PyException_SetTraceback
(
value
,
tb
);
Py_XDECREF
(
tmp_type
);
Py_XDECREF
(
tmp_value
);
Py_XDECREF
(
tmp_tb
);
}
static
void
reset_exc_info
(
PyThreadState
*
tstate
)
{
PyFrameObject
*
frame
;
PyObject
*
tmp_type
,
*
tmp_value
,
*
tmp_tb
;
/* It's a precondition that the thread state's frame caught an
* exception -- verify in a debug build.
*/
assert
(
tstate
!=
NULL
);
frame
=
tstate
->
frame
;
assert
(
frame
!=
NULL
);
assert
(
frame
->
f_exc_type
!=
NULL
);
/* Copy the frame's exception info back to the thread state. */
tmp_type
=
tstate
->
exc_type
;
tmp_value
=
tstate
->
exc_value
;
tmp_tb
=
tstate
->
exc_traceback
;
Py_INCREF
(
frame
->
f_exc_type
);
Py_XINCREF
(
frame
->
f_exc_value
);
Py_XINCREF
(
frame
->
f_exc_traceback
);
tstate
->
exc_type
=
frame
->
f_exc_type
;
tstate
->
exc_value
=
frame
->
f_exc_value
;
tstate
->
exc_traceback
=
frame
->
f_exc_traceback
;
Py_XDECREF
(
tmp_type
);
Py_XDECREF
(
tmp_value
);
Py_XDECREF
(
tmp_tb
);
/* Clear the frame's exception info. */
tmp_type
=
frame
->
f_exc_type
;
tmp_value
=
frame
->
f_exc_value
;
tmp_tb
=
frame
->
f_exc_traceback
;
frame
->
f_exc_type
=
NULL
;
frame
->
f_exc_value
=
NULL
;
frame
->
f_exc_traceback
=
NULL
;
Py_DECREF
(
tmp_type
);
Py_XDECREF
(
tmp_value
);
Py_XDECREF
(
tmp_tb
);
}
/* Logic for the raise statement (too complicated for inlining).
/* Logic for the raise statement (too complicated for inlining).
This *consumes* a reference count to each of its arguments. */
This *consumes* a reference count to each of its arguments. */
static
enum
why_code
static
enum
why_code
...
...
Python/compile.c
View file @
c86ac884
...
@@ -760,6 +760,8 @@ opcode_stack_effect(int opcode, int oparg)
...
@@ -760,6 +760,8 @@ opcode_stack_effect(int opcode, int oparg)
case
POP_BLOCK
:
case
POP_BLOCK
:
return
0
;
return
0
;
case
POP_EXCEPT
:
return
0
;
/* -3 except if bad bytecode */
case
END_FINALLY
:
case
END_FINALLY
:
return
-
1
;
/* or -2 or -3 if exception occurred */
return
-
1
;
/* or -2 or -3 if exception occurred */
...
@@ -818,7 +820,8 @@ opcode_stack_effect(int opcode, int oparg)
...
@@ -818,7 +820,8 @@ opcode_stack_effect(int opcode, int oparg)
return
0
;
return
0
;
case
SETUP_EXCEPT
:
case
SETUP_EXCEPT
:
case
SETUP_FINALLY
:
case
SETUP_FINALLY
:
return
3
;
/* actually pushed by an exception */
return
6
;
/* can push 3 values for the new exception
+ 3 others for the previous exception state */
case
LOAD_FAST
:
case
LOAD_FAST
:
return
1
;
return
1
;
...
@@ -2031,6 +2034,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
...
@@ -2031,6 +2034,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
/* second # body */
/* second # body */
VISIT_SEQ
(
c
,
stmt
,
handler
->
v
.
ExceptHandler
.
body
);
VISIT_SEQ
(
c
,
stmt
,
handler
->
v
.
ExceptHandler
.
body
);
ADDOP
(
c
,
POP_BLOCK
);
ADDOP
(
c
,
POP_BLOCK
);
ADDOP
(
c
,
POP_EXCEPT
);
compiler_pop_fblock
(
c
,
FINALLY_TRY
,
cleanup_body
);
compiler_pop_fblock
(
c
,
FINALLY_TRY
,
cleanup_body
);
/* finally: */
/* finally: */
...
@@ -2050,9 +2054,20 @@ compiler_try_except(struct compiler *c, stmt_ty s)
...
@@ -2050,9 +2054,20 @@ compiler_try_except(struct compiler *c, stmt_ty s)
compiler_pop_fblock
(
c
,
FINALLY_END
,
cleanup_end
);
compiler_pop_fblock
(
c
,
FINALLY_END
,
cleanup_end
);
}
}
else
{
else
{
basicblock
*
cleanup_body
;
cleanup_body
=
compiler_new_block
(
c
);
if
(
!
cleanup_body
)
return
0
;
ADDOP
(
c
,
POP_TOP
);
ADDOP
(
c
,
POP_TOP
);
ADDOP
(
c
,
POP_TOP
);
ADDOP
(
c
,
POP_TOP
);
compiler_use_next_block
(
c
,
cleanup_body
);
if
(
!
compiler_push_fblock
(
c
,
FINALLY_TRY
,
cleanup_body
))
return
0
;
VISIT_SEQ
(
c
,
stmt
,
handler
->
v
.
ExceptHandler
.
body
);
VISIT_SEQ
(
c
,
stmt
,
handler
->
v
.
ExceptHandler
.
body
);
ADDOP
(
c
,
POP_EXCEPT
);
compiler_pop_fblock
(
c
,
FINALLY_TRY
,
cleanup_body
);
}
}
ADDOP_JREL
(
c
,
JUMP_FORWARD
,
end
);
ADDOP_JREL
(
c
,
JUMP_FORWARD
,
end
);
compiler_use_next_block
(
c
,
except
);
compiler_use_next_block
(
c
,
except
);
...
@@ -3109,7 +3124,7 @@ compiler_with(struct compiler *c, stmt_ty s)
...
@@ -3109,7 +3124,7 @@ compiler_with(struct compiler *c, stmt_ty s)
{
{
static
identifier
enter_attr
,
exit_attr
;
static
identifier
enter_attr
,
exit_attr
;
basicblock
*
block
,
*
finally
;
basicblock
*
block
,
*
finally
;
identifier
tmpvalue
=
NULL
;
identifier
tmpvalue
=
NULL
,
tmpexit
=
NULL
;
assert
(
s
->
kind
==
With_kind
);
assert
(
s
->
kind
==
With_kind
);
...
@@ -3144,6 +3159,10 @@ compiler_with(struct compiler *c, stmt_ty s)
...
@@ -3144,6 +3159,10 @@ compiler_with(struct compiler *c, stmt_ty s)
return
0
;
return
0
;
PyArena_AddPyObject
(
c
->
c_arena
,
tmpvalue
);
PyArena_AddPyObject
(
c
->
c_arena
,
tmpvalue
);
}
}
tmpexit
=
compiler_new_tmpname
(
c
);
if
(
tmpexit
==
NULL
)
return
0
;
PyArena_AddPyObject
(
c
->
c_arena
,
tmpexit
);
/* Evaluate EXPR */
/* Evaluate EXPR */
VISIT
(
c
,
expr
,
s
->
v
.
With
.
context_expr
);
VISIT
(
c
,
expr
,
s
->
v
.
With
.
context_expr
);
...
@@ -3151,7 +3170,8 @@ compiler_with(struct compiler *c, stmt_ty s)
...
@@ -3151,7 +3170,8 @@ compiler_with(struct compiler *c, stmt_ty s)
/* Squirrel away context.__exit__ by stuffing it under context */
/* Squirrel away context.__exit__ by stuffing it under context */
ADDOP
(
c
,
DUP_TOP
);
ADDOP
(
c
,
DUP_TOP
);
ADDOP_O
(
c
,
LOAD_ATTR
,
exit_attr
,
names
);
ADDOP_O
(
c
,
LOAD_ATTR
,
exit_attr
,
names
);
ADDOP
(
c
,
ROT_TWO
);
if
(
!
compiler_nameop
(
c
,
tmpexit
,
Store
))
return
0
;
/* Call context.__enter__() */
/* Call context.__enter__() */
ADDOP_O
(
c
,
LOAD_ATTR
,
enter_attr
,
names
);
ADDOP_O
(
c
,
LOAD_ATTR
,
enter_attr
,
names
);
...
@@ -3198,6 +3218,9 @@ compiler_with(struct compiler *c, stmt_ty s)
...
@@ -3198,6 +3218,9 @@ compiler_with(struct compiler *c, stmt_ty s)
/* Finally block starts; context.__exit__ is on the stack under
/* Finally block starts; context.__exit__ is on the stack under
the exception or return information. Just issue our magic
the exception or return information. Just issue our magic
opcode. */
opcode. */
if
(
!
compiler_nameop
(
c
,
tmpexit
,
Load
)
||
!
compiler_nameop
(
c
,
tmpexit
,
Del
))
return
0
;
ADDOP
(
c
,
WITH_CLEANUP
);
ADDOP
(
c
,
WITH_CLEANUP
);
/* Finally block ends. */
/* Finally block ends. */
...
...
Python/import.c
View file @
c86ac884
...
@@ -86,8 +86,9 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
...
@@ -86,8 +86,9 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
3100 (merge from 2.6a0, see 62151)
3100 (merge from 2.6a0, see 62151)
3102 (__file__ points to source file)
3102 (__file__ points to source file)
Python 3.0a4: 3110 (WITH_CLEANUP optimization).
Python 3.0a4: 3110 (WITH_CLEANUP optimization).
Python 3.0a5: 3130 (lexical exception stacking, including POP_EXCEPT)
*/
*/
#define MAGIC (31
1
0 | ((long)'\r'<<16) | ((long)'\n'<<24))
#define MAGIC (31
3
0 | ((long)'\r'<<16) | ((long)'\n'<<24))
/* Magic word as global; note that _PyImport_Init() can change the
/* Magic word as global; note that _PyImport_Init() can change the
value of this global to accommodate for alterations of how the
value of this global to accommodate for alterations of how the
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment