Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-31113: Get rid of recursion in the compiler for normal control flow. #3015

Merged
merged 12 commits into from Jan 11, 2018

Conversation

serhiy-storchaka
Copy link
Member

@serhiy-storchaka serhiy-storchaka commented Aug 7, 2017

@@ -670,6 +670,11 @@ def __fspath__(self):

compile("42", PathLike("test_compile_pathlike"), "single")

def test_dfs_next(self):
# Issue #31113: Stack overflow when compile a long sequence of
Copy link
Member

@vstinner vstinner Aug 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the new "bpo-xxx" format.

@vstinner vstinner requested a review from benjaminp Aug 7, 2017
Python/compile.c Outdated
for (j = nblocks; b && !b->b_seen; b = b->b_next) {
b->b_seen = 1;
assert(a->a_nblocks < j);
a->a_postorder[--j] = b;
Copy link
Member

@pitrou pitrou Aug 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works because blocks are emitted in topological order, right? It would be nice to add a comment.

Copy link
Member

@pitrou pitrou Aug 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or are you using a_postorder as a stack or worklist?

Copy link
Member Author

@serhiy-storchaka serhiy-storchaka Aug 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, since the number of blocks is limited, the space at the end of a_postorder can be used as a stack.

Python/compile.c Outdated
while (j < nblocks) {
b = a->a_postorder[j++];
for (i = 0; i < b->b_iused; i++) {
struct instr *instr = instr = &b->b_instr[i];
Copy link
Member

@pitrou pitrou Aug 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the struct instr *instr = instr part.

Copy link
Member Author

@serhiy-storchaka serhiy-storchaka Aug 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! This is just a copying error.

@pitrou
Copy link
Member

pitrou commented Aug 7, 2017

It's telling that you're still getting a stack overflow on Windows :-)

dfs(c, instr->i_target, a);
int i, j;

/* Get rid of recursion for normal control flow.
Copy link
Member

@pitrou pitrou Aug 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it is possible to get rid of recursion entirely -- perhaps by allocating a separate stack? Or is it unlikely to have a stack overflow though i_target?

Copy link
Member Author

@serhiy-storchaka serhiy-storchaka Aug 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, though this likely will complicate the code. I don't have an example that overflows a stack though i_target. After getting such example I'll try to get rid of recursion entirely.

Python/compile.c Outdated
int i;
basicblock *next;
b = sp[-1];
if (b->b_seen == 2) {
Copy link
Member

@pitrou pitrou Aug 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add some comment as to the different values of b_seen? Does 1 mean "queued for processing" and 2 "already processed"?

Python/compile.c Outdated
if (instr->i_jrel || instr->i_jabs)
dfs(c, instr->i_target, a, j);
}
a->a_postorder[a->a_nblocks++] = b;
Copy link
Member

@pitrou pitrou Aug 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add something like assert(a->a_nblocks <= j) here? The stack trick is smart but I'd like to make sure it's not buggy.

Copy link
Member Author

@serhiy-storchaka serhiy-storchaka Aug 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Python/compile.c Outdated
while (sp != stack) {
int i;
basicblock *next;
b = sp[-1];
Copy link
Member

@pitrou pitrou Aug 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we decrement sp here instead of setting b->b_seen = 2 below?

Copy link
Member Author

@serhiy-storchaka serhiy-storchaka Aug 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is closer to the current implementation. If just pop a block from the stack and keep b->b_seen == 1, all seems working, but the result is different. I don't know what result is more correct, but larger depth is safer. Clearing b->b_seen after popping a block causes an infinite loop. Current code contains bugs (see bpo-24340), may be after fixing them this code could be simplified.

@pitrou
Copy link
Member

pitrou commented Aug 30, 2017

What is the status of this?

@serhiy-storchaka
Copy link
Member Author

serhiy-storchaka commented Aug 30, 2017

If it is allowed to backport this change to other branches, I think it is ready for committing if you have no objections. If it is 3.7 only, we can wait until bpo-17611 and bpo-24340 be resolved. May be this will make this change slightly simpler (I'm not sure).

@pitrou
Copy link
Member

pitrou commented Aug 30, 2017

I'm wary of backporting this and would prefer it to be 3.7-only.

@pitrou
Copy link
Member

pitrou commented Aug 30, 2017

I think a good experiment would be to take the PR for bpo-17611 and make it non-recursive. It should be similar to this PR in principle.

@serhiy-storchaka serhiy-storchaka merged commit 782d6fe into python:master Jan 11, 2018
@serhiy-storchaka serhiy-storchaka deleted the compile-dfs branch Jan 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants