Skip to content

Fixed layout classes should still have resilient vtables #20850

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 8 commits into from
Nov 30, 2018

Conversation

slavapestov
Copy link
Contributor

To achieve this, re-organize the metadata so that the field offset vector comes immediately after the generic parameter area, instead of after the vtable. This means the vtable can change resiliently.

Note that for non-generic @_fixed_layout classes without resiliently-sized fields, field offsets are constant and will be inlined directly, but we need the more general access pattern to work if the @_fixed_layout class has generic layout.

Also, use method dispatch thunks to call vtable methods instead of accessing the vtable directly, as with resilient classes.

Since the metadata size is not known at compile time, we use the most general metadata instantiation strategy now.

@slavapestov
Copy link
Contributor Author

(This still needs some more tests and cleanup)

@slavapestov
Copy link
Contributor Author

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

Build comment file:

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
UTF8Decode_InitDecoding_ascii 615 748 +21.6% 0.82x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
FlattenListLoop 3633 3968 +9.2% 0.92x (?)
Array2D 6201 6736 +8.6% 0.92x
Improvement
DropFirstSequence 68 52 -23.5% 1.31x
DropFirstSequenceLazy 68 52 -23.5% 1.31x
DropFirstAnyCollection 163 148 -9.2% 1.10x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Regression
Breadcrumbs.IdxToUTF16.longASCII 623 705 +13.2% 0.88x
EqualSubstringSubstring 22 24 +9.1% 0.92x (?)
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 8-Core Intel Xeon E5
  Processor Speed: 3 GHz
  Number of Processors: 1
  Total Number of Cores: 8
  L2 Cache (per Core): 256 KB
  L3 Cache: 25 MB
  Memory: 64 GB
--------------

@slavapestov
Copy link
Contributor Author

Let's try with one more tweak

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

Build comment file:

Performance: -O

TEST OLD NEW DELTA RATIO
Regression
StringEqualPointerComparison 600 657 +9.5% 0.91x
Hanoi 3469 3785 +9.1% 0.92x

Performance: -Osize

TEST OLD NEW DELTA RATIO
Regression
StringEqualPointerComparison 571 628 +10.0% 0.91x
FlattenListLoop 4057 4429 +9.2% 0.92x (?)
Array2D 6910 7505 +8.6% 0.92x
Breadcrumbs.CopyUTF16CodeUnits.ASCII 50 54 +8.0% 0.93x
Improvement
DropFirstSequence 76 58 -23.7% 1.31x
DropFirstSequenceLazy 76 58 -23.7% 1.31x
DropFirstAnyCollection 183 164 -10.4% 1.12x
PrefixAnySeqCntRangeLazy 176 159 -9.7% 1.11x

Performance: -Onone

TEST OLD NEW DELTA RATIO
Improvement
ArrayOfGenericPOD2 1180 1065 -9.7% 1.11x (?)
ArrayOfPOD 859 776 -9.7% 1.11x
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB
--------------

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

2 similar comments
@DougGregor
Copy link
Member

@swift-ci Please test source compatibility

@DougGregor
Copy link
Member

@swift-ci Please test source compatibility

@@ -928,6 +928,9 @@ SubclassScope SILDeclRef::getSubclassScope() const {
assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() &&
"class must be as visible as its members");

// FIXME: This is too narrow. Any class with resilient metadata should
// probably have this, at least for method overrides that don't add new
// vtable entries.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this seems important for the correctness issue we're worried about.

Copy link
Contributor

Choose a reason for hiding this comment

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

Slava clarified privately that we can change this later as long as the fixed-layout classes we ship in Swift 5 don't break the rules that were there in Swift 5.

@slavapestov
Copy link
Contributor Author

@swift-ci Please test

1 similar comment
@slavapestov
Copy link
Contributor Author

@swift-ci Please test

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

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

Alright, this seems ok.

As I mentioned in chat, this implies that we consider the generic signature section of the metadata to be stable when the metadata is fixed-layout, which may make some things with resiliently-added default generic arguments harder. But I think we can live with that.

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 3cac8288eff7df5d7d6a04278c56a3f1c9e67d6f

- We don't want to support changing a root class of a class, so don't
  pretend that works. Some of these tests got removed recently in
  d8104e7 but one still remained.

- For the tests that insert a non-root superclass in the inheritance
  hierarchy, also test calling a method of the derived class. This
  works now that we no longer hardcode vtable offsets and instead use
  dispatch thunks.
We want to be able to define classes with a fixed storage layout,
but a resilient (opaque) vtable. If the class is also generic,
we still have to load field offsets from the metadata if they
are dependent.

So put the field offsets after the generic arguments and before
the vtable.

This is an ABI break for @_fixed_layout classes, which are
defined by the stdlib.
…t-metadata from resilient-storage

We want @_fixed_layout classes to have non-resilient storage, but still have
resilient metadata.
@_fixed_layout classes have resilient vtables now, so we can add and
re-order methods.

Removing overrides is not legal though because they are subject to
devirtualization.
The result type mismatch comes up when we're calling a covariant
override of a class method resiliently as well.
@slavapestov
Copy link
Contributor Author

@swift-ci Please test

@slavapestov slavapestov merged commit 67ec3b7 into swiftlang:master Nov 30, 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.

5 participants