Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
M
micropython
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
card10
micropython
Commits
4bf3f2d3
Commit
4bf3f2d3
authored
Oct 15, 2015
by
Damien George
Browse files
Options
Downloads
Patches
Plain Diff
py: Fix with+for+return bug by popping for-iter when unwinding exc stack.
Addresses issue #1182.
parent
556c8a9a
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
py/vm.c
+18
-5
18 additions, 5 deletions
py/vm.c
tests/basics/try_finally_return.py
+49
-0
49 additions, 0 deletions
tests/basics/try_finally_return.py
tests/basics/with_return.py
+43
-4
43 additions, 4 deletions
tests/basics/with_return.py
with
110 additions
and
9 deletions
py/vm.c
+
18
−
5
View file @
4bf3f2d3
...
@@ -637,10 +637,14 @@ unwind_jump:;
...
@@ -637,10 +637,14 @@ unwind_jump:;
unum
-=
1
;
unum
-=
1
;
assert
(
exc_sp
>=
exc_stack
);
assert
(
exc_sp
>=
exc_stack
);
if
(
MP_TAGPTR_TAG1
(
exc_sp
->
val_sp
))
{
if
(
MP_TAGPTR_TAG1
(
exc_sp
->
val_sp
))
{
// Getting here the stack looks like:
// (..., X, dest_ip)
// where X is pointed to by exc_sp->val_sp and in the case
// of a "with" block contains the context manager info.
// We're going to run "finally" code as a coroutine
// We're going to run "finally" code as a coroutine
// (not calling it recursively). Set up a sentinel
// (not calling it recursively). Set up a sentinel
// on a stack so it can return back to us when it is
// on a stack so it can return back to us when it is
// done (when END_FINALLY reached).
// done (when
WITH_CLEANUP or
END_FINALLY reached).
PUSH
((
void
*
)
unum
);
// push number of exception handlers left to unwind
PUSH
((
void
*
)
unum
);
// push number of exception handlers left to unwind
PUSH
(
MP_OBJ_NEW_SMALL_INT
(
UNWIND_JUMP
));
// push sentinel
PUSH
(
MP_OBJ_NEW_SMALL_INT
(
UNWIND_JUMP
));
// push sentinel
ip
=
exc_sp
->
handler
;
// get exception handler byte code address
ip
=
exc_sp
->
handler
;
// get exception handler byte code address
...
@@ -1016,15 +1020,24 @@ unwind_jump:;
...
@@ -1016,15 +1020,24 @@ unwind_jump:;
unwind_return:
unwind_return:
while
(
exc_sp
>=
exc_stack
)
{
while
(
exc_sp
>=
exc_stack
)
{
if
(
MP_TAGPTR_TAG1
(
exc_sp
->
val_sp
))
{
if
(
MP_TAGPTR_TAG1
(
exc_sp
->
val_sp
))
{
// Getting here the stack looks like:
// (..., X, [iter0, iter1, ...,] ret_val)
// where X is pointed to by exc_sp->val_sp and in the case
// of a "with" block contains the context manager info.
// There may be 0 or more for-iterators between X and the
// return value, and these must be removed before control can
// pass to the finally code. We simply copy the ret_value down
// over these iterators, if they exist. If they don't then the
// following is a null operation.
mp_obj_t
*
finally_sp
=
MP_TAGPTR_PTR
(
exc_sp
->
val_sp
);
finally_sp
[
1
]
=
sp
[
0
];
sp
=
&
finally_sp
[
1
];
// We're going to run "finally" code as a coroutine
// We're going to run "finally" code as a coroutine
// (not calling it recursively). Set up a sentinel
// (not calling it recursively). Set up a sentinel
// on a stack so it can return back to us when it is
// on a stack so it can return back to us when it is
// done (when END_FINALLY reached).
// done (when
WITH_CLEANUP or
END_FINALLY reached).
PUSH
(
MP_OBJ_NEW_SMALL_INT
(
UNWIND_RETURN
));
PUSH
(
MP_OBJ_NEW_SMALL_INT
(
UNWIND_RETURN
));
ip
=
exc_sp
->
handler
;
ip
=
exc_sp
->
handler
;
// We don't need to do anything with sp, finally is just
// syntactic sugar for sequential execution??
// sp =
exc_sp
--
;
exc_sp
--
;
goto
dispatch_loop
;
goto
dispatch_loop
;
}
}
...
...
This diff is collapsed.
Click to expand it.
tests/basics/try_finally_return.py
+
49
−
0
View file @
4bf3f2d3
...
@@ -21,3 +21,52 @@ def func3():
...
@@ -21,3 +21,52 @@ def func3():
print
(
"
finally 3
"
)
print
(
"
finally 3
"
)
print
(
func3
())
print
(
func3
())
# for loop within try-finally
def
f
():
try
:
for
i
in
[
1
,
2
]:
return
i
finally
:
print
(
'
finally
'
)
print
(
f
())
# multiple for loops within try-finally
def
f
():
try
:
for
i
in
[
1
,
2
]:
for
j
in
[
3
,
4
]:
return
(
i
,
j
)
finally
:
print
(
'
finally
'
)
print
(
f
())
# multiple for loops and nested try-finally's
def
f
():
try
:
for
i
in
[
1
,
2
]:
for
j
in
[
3
,
4
]:
try
:
for
k
in
[
5
,
6
]:
for
l
in
[
7
,
8
]:
return
(
i
,
j
,
k
,
l
)
finally
:
print
(
'
finally 2
'
)
finally
:
print
(
'
finally 1
'
)
print
(
f
())
# multiple for loops that are optimised, and nested try-finally's
def
f
():
try
:
for
i
in
range
(
1
,
3
):
for
j
in
range
(
3
,
5
):
try
:
for
k
in
range
(
5
,
7
):
for
l
in
range
(
7
,
9
):
return
(
i
,
j
,
k
,
l
)
finally
:
print
(
'
finally 2
'
)
finally
:
print
(
'
finally 1
'
)
print
(
f
())
This diff is collapsed.
Click to expand it.
tests/basics/with_return.py
+
43
−
4
View file @
4bf3f2d3
class
CtxMgr
:
class
CtxMgr
:
def
__init__
(
self
,
id
):
self
.
id
=
id
def
__enter__
(
self
):
def
__enter__
(
self
):
print
(
"
__enter__
"
)
print
(
"
__enter__
"
,
self
.
id
)
return
self
return
self
def
__exit__
(
self
,
a
,
b
,
c
):
def
__exit__
(
self
,
a
,
b
,
c
):
print
(
"
__exit__
"
,
repr
(
a
),
repr
(
b
))
print
(
"
__exit__
"
,
self
.
id
,
repr
(
a
),
repr
(
b
))
# simple case
def
foo
():
def
foo
():
with
CtxMgr
():
with
CtxMgr
(
1
):
return
4
return
4
print
(
foo
())
print
(
foo
())
# for loop within with (iterator needs removing upon return)
def
f
():
with
CtxMgr
(
1
):
for
i
in
[
1
,
2
]:
return
i
print
(
f
())
# multiple for loops within with
def
f
():
with
CtxMgr
(
1
):
for
i
in
[
1
,
2
]:
for
j
in
[
3
,
4
]:
return
(
i
,
j
)
print
(
f
())
# multiple for loops within nested withs
def
f
():
with
CtxMgr
(
1
):
for
i
in
[
1
,
2
]:
for
j
in
[
3
,
4
]:
with
CtxMgr
(
2
):
for
k
in
[
5
,
6
]:
for
l
in
[
7
,
8
]:
return
(
i
,
j
,
k
,
l
)
print
(
f
())
# multiple for loops that are optimised, and nested withs
def
f
():
with
CtxMgr
(
1
):
for
i
in
range
(
1
,
3
):
for
j
in
range
(
3
,
5
):
with
CtxMgr
(
2
):
for
k
in
range
(
5
,
7
):
for
l
in
range
(
7
,
9
):
return
(
i
,
j
,
k
,
l
)
print
(
f
())
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment