Skip to content

SILOptimizer: make vtable pruning less aggressive #33770

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
Sep 4, 2020

Conversation

compnerd
Copy link
Member

@compnerd compnerd commented Sep 2, 2020

A class which is marked as internal or public can be visible outside
of the current file, where the use of the VWT indirectly is possible.
If the VWT is modified and inlined, it is possible that the offsets will
no longer match resulting in an invalid dispatch. Although this change
drastically reduces the efficacy of this pass, it ensures correctness as
a temporary measure.

Thanks to Alexander Smarus for the basis for the test case!

https://bugs.swift.org/browse/SR-13449
rdar://problem/68170038

@compnerd
Copy link
Member Author

compnerd commented Sep 2, 2020

CC: @jckarter

@compnerd
Copy link
Member Author

compnerd commented Sep 2, 2020

@swift-ci please test

@gottesmm
Copy link
Contributor

gottesmm commented Sep 2, 2020

Before this goes in I would like to understand more what is happening here.

@gottesmm gottesmm requested a review from jckarter September 2, 2020 22:02
@gottesmm
Copy link
Contributor

gottesmm commented Sep 2, 2020

Also note that @jckarter is on vacation right now as I understand it.

void runOnVTable(SILModule *M,
SILVTable *vtable) {
void runOnVTable(SILModule *M, SILVTable *vtable) {
if (!vtable->getClass()->isOutermostPrivateOrFilePrivateScope()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Turning this off for everything is not appropriate, we at least should be using the tools that we already have that handle this sort of thing. There are ways of checking this visibility while handling wmo/non-wmo that we should be using rather than referring to the ast.

Copy link
Contributor

Choose a reason for hiding this comment

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

Reading SILVTable, it seems that there is a query that tells you if the vtable will be serialized or was serialized. Given that we seem to not have SILLinkage here, I imagine that is what one would want to use.

@eeckstein what are your thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you point me to what you have in mind for checking here? I think that the WMO doesn't guarantee that every single reference is going to get fully monomorphized right? But, sure WMO with internal visibility should allow additional cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

This problem can only occur in non-WMO mode or for "open" classes in WMO mode, right?
Can we disable this optimization just for "open" classes and for non-WMO mode (which is not so important)?

@slavapestov
Copy link
Contributor

The class vtable is stored in the metadata, not the VWT.

I think a better fix would be to disable vtable pruning entirely in non-WMO mode. A more precise check would be to use vtable pruning only for fileprivate classes in non-WMO mode.

@texasmichelle
Copy link
Contributor

Before this goes in I would like to understand more what is happening here.

Background for this PR is SR-13449.

@compnerd
Copy link
Member Author

compnerd commented Sep 2, 2020

The class vtable is stored in the metadata, not the VWT.

Correct. The effective VWT in the metadata is what is being pruned.

I think a better fix would be to disable vtable pruning entirely in non-WMO mode. A more precise check would be to use vtable pruning only for fileprivate classes in non-WMO mode.

Yes, I agree with you, and that is what I would prefer to do:

  • fileprivate/private only classes always
  • in WMO, add internal classes as well (assuming that is fully safe)

I suppose that we could disable vtable pruning entirely in non-WMO mode, but if we can do it safely, why not?

@swift-ci
Copy link
Contributor

swift-ci commented Sep 2, 2020

Build failed
Swift Test Linux Platform
Git Sha - 3400f86d753014156698189b02cd3c70dcd95a02

@gottesmm
Copy link
Contributor

gottesmm commented Sep 2, 2020

@slavapestov question. I imagine the issue here in the design space is that we never have given vtables a SILLinkage and the infrastructure around isExternallyUsedSymbol. Your thoughts?

My thought is given that this causes a real crash, I think it makes sense to just disable this in this way for now. Really we should just fix the vtable to have VTables.

@swift-ci
Copy link
Contributor

swift-ci commented Sep 2, 2020

Build failed
Swift Test OS X Platform
Git Sha - 3400f86d753014156698189b02cd3c70dcd95a02

@compnerd compnerd force-pushed the pruned-pruning-date branch from 3400f86 to e5770ab Compare September 3, 2020 18:52
@compnerd
Copy link
Member Author

compnerd commented Sep 3, 2020

@slavapestov, @eeckstein - okay, the pass always runs under WMO now and only scans private classes on non-WMO mode.

@compnerd
Copy link
Member Author

compnerd commented Sep 3, 2020

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Sep 3, 2020

Build failed
Swift Test OS X Platform
Git Sha - 3400f86d753014156698189b02cd3c70dcd95a02

A class which is marked as internal or public can be visible outside
of the current file, where the use of the VWT indirectly is possible.
If the VWT is modified and inlined, it is possible that the offsets will
no longer match resulting in an invalid dispatch.  Limit the pass to
when WMO is enabled or the type is private in non-WMO cases.
@compnerd compnerd force-pushed the pruned-pruning-date branch from e5770ab to a92e9b3 Compare September 3, 2020 23:18
@compnerd
Copy link
Member Author

compnerd commented Sep 3, 2020

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Sep 3, 2020

Build failed
Swift Test OS X Platform
Git Sha - e5770ab964fe8411739de7d101c3dab6f4a60345

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

lgtm!

@compnerd compnerd merged commit 3cd4258 into swiftlang:master Sep 4, 2020
@compnerd compnerd deleted the pruned-pruning-date branch September 4, 2020 15:52
LLVM_DEBUG(llvm::dbgs() << "PruneVTables inspecting table:\n";
vtable->print(llvm::dbgs()));
if (!M->isWholeModule() &&
vtable->getClass()->getEffectiveAccess() >= AccessLevel::FilePrivate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it be > not >= then?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops, I thought Id fixed that. #33808

Copy link
Contributor

@jckarter jckarter Sep 8, 2020

Choose a reason for hiding this comment

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

I think this change is unnecessarily pessimistic. The check for calleesAreStaticallyKnowable below should already prevent us from pruning nonfinal internal vtable entries. We should still be able to prune entries for final methods as long as the final method is not itself an override, because it should never need a vtable entry for originally-final methods to begin with, and we can reliably check whether a method is final across modules without an optimization pass. I suppose that means we could set the nonoverridden bit in SILGen for final methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like if a method is originally final we already don't give it a vtable entry at all. So, we should be able to remove the if (!methodDecl->isFinal()) precondition below and get the same effect. I think that's better than reimplementing calleesAreStaticallyKnowable here.

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.

7 participants