-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Exclusivity] Enforce exclusive access for class offsets in KeyPaths #15502
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
[Exclusivity] Enforce exclusive access for class offsets in KeyPaths #15502
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
stdlib/public/core/KeyPath.swift
Outdated
|
||
// Tail allocate the UnsafeValueBuffer used as the AccessRecord. | ||
// This avoids a second heap allocation since we cannot have a | ||
// stored property of Builtin.UnsafeValueBuffer type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no Swift-level way to initialize a value of UnsafeValueBuffer type, so the initializer doesn't pass DI. I'll update the comment with more information.
stdlib/public/core/KeyPath.swift
Outdated
1._builtinWordValue, | ||
AccessRecord.self) | ||
|
||
withUnsafeMutablePointer(to: &holder.previous) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is more a question for @jckarter. Why did we drop down to withUnsafeMutablePointer, instead of just holding on to an Unmanaged reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason we couldn't use Unmanaged
and manual reference counting here. Are there undesired interactions between the exclusivity calls and the implicit refcounting at the unmanaged-managed boundaries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, it's obvious now that I look at this again, the ClassHolder is now allocated with a builtin. There's just no way to get the memory in an initialized state without using an unsafe pointer.
// Key path accesses are performed in the Standard Library. The Standard Library | ||
// is currently compiled in Swift 3 mode and the compiler currently logs conflicts | ||
// (rather than trapping on them) code compiled in Swift 3 mode. For this reason | ||
// conflicts where the second conflicting access is via a kKeyey path will log rather than |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: kKeyey
6305429
to
f062d6a
Compare
Updated to add additional comments about allocation and initialization of ClassHolder instances. Also rebased on top of master. |
@swift-ci Please smoke test and merge |
Add dynamic enforcement of exclusive access when a KeyPath directly accesses a final stored property on an instance of a class. For read-only projections, this begins and ends the access immediately. For mutable projections, this uses the ClassHolder to perform a long-term access that lasts as long as the lifetime of the ClassHolder. rdar://problem/31972680
f062d6a
to
d1757fc
Compare
@swift-ci please smoke test |
@devincoughlin that looks good to me. |
@swift-ci smoke test OS X Platform. |
@devincoughlin you can either set noNestedAccess to false and let the future optimization handle it, or wait until this PR is merged and retest: #15659 |
@swift-ci smoke test. |
@swift-ci Please smoke test |
So, the IRGen "fix" I mentioned above, What's more, I don't think the no_nested_conflict changes should have any effect on the KeyPathInoutDirectWriteClassStoredProp test that is failing (there's no instantaneous access in that test). So, was the test ever passing? I looked into it and noticed that it requires the standard library to emit the unpaired access markers. We had never intended to enable access markers in the standard library because, once it's been tested, there's no point shipping it with extra checks. This is generally the right strategy, but doesn't work for the Builtin checks, which actually form an outer access scope surrounding user code. I'm tempted to suggest handling the Builtins specially, and unconditionally emitting markers. But first we should consider whether there are other instances of this issue. Maybe the solution needs to |
Oof. That explains why the test passes locally. I'm using a debug version of the standard library. |
I would hope that the standard library generally doesn't need dynamic checks because it can just use static enforcement. So the approach I would suggest would be to look at all the dynamic checks that we do emit and either (1) decide they're statically okay (and disable them with an attribute?) or (2) leave them in as dynamic checks. A base policy of disabling all the checks feels like going the wrong way about it. |
@gottesmm plans to add a function-level |
…ename it to IRGenPrepare. I am going to be adding logic here to enable swiftlang#1550 to be completed. The rename makes sense due to precedent from LLVM's codegen prepare and also since I am going to be expanding what the pass is doing beyond just "cleaning up". It is really a grab bag pass for performing simple transformations that we do not want to pollute IRGen's logic with. swiftlang#15502 rdar://39335800
@devincoughlin I am going to chop off a part of this commit since I need it to test my semantics thing. Specifically I am just going to cut off the builtin emission part. |
@devincoughlin, Since @gottesmm is testing this in conjunction with his changes, he'll probably end of staging it back in as two parts it in new PRs. |
…ename it to IRGenPrepare. I am going to be adding logic here to enable swiftlang#1550 to be completed. The rename makes sense due to precedent from LLVM's codegen prepare and also since I am going to be expanding what the pass is doing beyond just "cleaning up". It is really a grab bag pass for performing simple transformations that we do not want to pollute IRGen's logic with. swiftlang#15502 rdar://39335800
See #16051.. |
Add dynamic enforcement of exclusive access when a KeyPath directly accesses a final
stored property on an instance of a class. For read-only projections, this begins and ends
the access immediately. For mutable projections, this uses the ClassHolder to perform
a long-term access that lasts as long as the lifetime of the ClassHolder.
rdar://problem/31972680