Skip to content

Implement generalized accessors using yield-once coroutines #18156

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

Merged
merged 1 commit into from
Jul 24, 2018

Conversation

rjmccall
Copy link
Contributor

For now, the accessors have been underscored as _read and _modify. I'll prepare an evolution proposal for this feature which should allow us to remove the underscores or, y'know, rename them to purple and lettuce.

_read accessors do not make any effort yet to avoid copying the value being yielded. I'll work on it in follow-up patches.

Opaque accesses to properties and subscripts defined with _modify accessors will use an inefficient materializeForSet pattern that materializes the value to a temporary instead of accessing it in-place. That will be fixed by migrating to modify over materializeForSet, which is next up after the read optimizations.

SIL ownership verification doesn't pass yet for the test cases here because of a general fault in SILGen where borrows can outlive their borrowed value due to being cleaned up on the general cleanup stack when the borrowed value is cleaned up on the formal-access stack. Michael, Andy, and I discussed various ways to fix this, but it seems clear to me that it's not in any way specific to coroutine accesses.

rdar://35399664

@rjmccall
Copy link
Contributor Author

@swift-ci Please test.

@rjmccall
Copy link
Contributor Author

@atrick I'd appreciate a review of the SILOptimizer changes here.
@slavapestov @jckarter If y'all wouldn't mind looking over the Sema and SILGen changes.

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 92044016cdc37b43a86746df19bcf95e4deb50a1

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 92044016cdc37b43a86746df19bcf95e4deb50a1

@rjmccall rjmccall force-pushed the generalized-accessors branch from 9204401 to 217c651 Compare July 23, 2018 21:30
@rjmccall
Copy link
Contributor Author

@swift-ci Please test.

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 92044016cdc37b43a86746df19bcf95e4deb50a1

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 92044016cdc37b43a86746df19bcf95e4deb50a1

For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.

`_read` accessors do not make any effort yet to avoid copying the
value being yielded.  I'll work on it in follow-up patches.

Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.

SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.

rdar://35399664
@rjmccall rjmccall force-pushed the generalized-accessors branch from 217c651 to 7a4aeed Compare July 23, 2018 23:00
@rjmccall
Copy link
Contributor Author

@swift-ci Please test.

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 217c651ee7fd63e31eb46be855a8d970715c6ab2

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 217c651ee7fd63e31eb46be855a8d970715c6ab2

@rjmccall rjmccall merged commit 70e2aea into swiftlang:master Jul 24, 2018
@rjmccall rjmccall deleted the generalized-accessors branch July 24, 2018 02:58
if (!peekToken().is(tok::colon)) {
// "yield" in the right context begins a yield statement.
if (isContextualYieldKeyword()) {
Tok.setKind(tok::kw_yield);
Copy link
Member

@rintaro rintaro Jul 24, 2018

Choose a reason for hiding this comment

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

I'm not a fan of mutating token in isStartOfStmt(). For example, skipUntil family functions call this method that may accidentally mutates it. I think it's better to leave it tok::identifier here, then setKind() in parseStmt(). In case you really need this, please add case tok::kw_yield: return true in the switch at least.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay. How's this look? #18179

@atrick
Copy link
Contributor

atrick commented Jul 26, 2018

@rjmccall it looks to me like SIL formal access on the begin_apply's address will be handled correctly with this patch.

I suspect that side effect analysis will just be conservative at the begin_apply, in the sense that it continues analyzing the function past the yield, summarizing both the initialization and resume effects at the begin_apply.

The end_apply will be a problem if there's no restriction on what users can do in the coroutine's "tail". As such, I'm a little surprised that it isn't also modeled as an ApplySite. In the current implementation, its side effects are conservative, and the effects on the call graph should already be modeled by the begin_apply, so it may be ok in general. But I'm pretty sure AccessedStorageAnalysis will be wrong. It currently assumes that formal access can only occur at an ApplySite or begin_access. Ultimately, that should be fixed to view the end_apply's effects as if it were an ApplySite. The most natural way to do that would be to teach SideEffectAnalysis in general to treat end_apply as an ApplySite. How do you feel about that? I don't see an alternative short of preventing the user from performing formal access in the coroutine tail. Of course, for now, I could just hack SideEffectAnalysis to call setWorstEffects at an end_apply.

@rjmccall
Copy link
Contributor Author

There are no restrictions about what can happen in the end_apply; that instruction runs the coroutine to completion. Note that borrows and inout accesses that are initiated for arguments to begin_apply must last until the end of the end_apply / abort_apply, so you may need some special treatment.

Beyond that, I don't know what significance treating end_apply as an apply site has beyond having pessimal side effects.

@atrick
Copy link
Contributor

atrick commented Jul 27, 2018

Two things.

  1. Correctness. I want to rely on the fact that only a begin_access or ApplySite may initiate formal access. I need to extend that to include end_apply now, and maybe abort_apply† Note that there's no other non-apply instruction quite like this that can execute arbitrary SIL operations (aside from deinit). So, more generally, if I create a new opcode and declare that something can only happen via that opcode, now I need to check for: the opcode itself, all ApplySites, all end_apply's.

  2. Strength of the analysis. In the long run, we don't just want to assume an end_apply could access anything, unless we also assume it will be inlined whenever possible.

†I'd like to assume that an arbitrary release, which may call deinit, does not need to check at runtime that a global/property accessed by the deinit may conflict with something being accessed in the caller. That will be prohibitive for access marker merging/elimination. That's shady though because it's not quite "as if" the deinit ran later.

@rjmccall
Copy link
Contributor Author

rjmccall commented Jul 27, 2018

Note that abort_apply can run arbitrary cleanups including, yes, releases, but also defer blocks. So yeah, anything can happen there. If you think it makes sense to treat it and end_apply as ApplySites, okay, but I suspect that that isn't right for literally any other client of ApplySite.

@atrick
Copy link
Contributor

atrick commented Jul 27, 2018

I think it's conceptually right to make end_apply and apply everywhere. But I don't think it's worth it. There are too many places in the code that assume an ApplySite is either Full or Partial. This would be neither. It would have a callee but no normal arguments. I think that's sort of what you're saying.

In practice, giving end_apply arbitrary side effects will end up being conservatively correct in almost all cases. AccessedStorageAnalysis can be fixed easily. SIL developers will just need to remember that there are other apply-like things to check for now.

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.

4 participants