Match the new SILGen pattern, where only the box parameter is partially applied to the closure, and the address of the value is projected on the callee side.
The C++ ABI for static locals is a bit heavy compared to dispatch_once; doing this saves more than 1KB in runtime code size. Dispatch_once/call_once is also more likely to be hot because it's also used by Swift and ObjC code.
Alas, llvm::get_execution_seed() from llvm/ADT/Hashing.h still inflicts one static local initialization on us we can't override (without forking Hashing.h, anyway).
The drivers for this change are providing a simpler API to SIL pass
authors, having a more efficient of the in-memory representation,
and ruling out an entire class of common bugs that usually result
in hard-to-debug backend crashes.
Summary
-------
SILInstruction
Old New
+---------------+ +------------------+ +-----------------+
|SILInstruction | |SILInstruction | |SILDebugLocation |
+---------------+ +------------------+ +-----------------+
| ... | | ... | | ... |
|SILLocation | |SILDebugLocation *| -> |SILLocation |
|SILDebugScope *| +------------------+ |SILDebugScope * |
+---------------+ +-----------------+
We’re introducing a new class SILDebugLocation which represents the
combination of a SILLocation and a SILDebugScope.
Instead of storing an inline SILLocation and a SILDebugScope pointer,
SILInstruction now only has one SILDebugLocation pointer. The APIs of
SILBuilder and SILDebugLocation guarantees that every SILInstruction
has a nonempty SILDebugScope.
Developer-visible changes include:
SILBuilder
----------
In the old design SILBuilder populated the InsertedInstrs list to
allow setting the debug scopes of all built instructions in bulk
at the very end (as the responsibility of the user). In the new design,
SILBuilder now carries a "current debug scope" state and immediately
sets the debug scope when an instruction is inserted.
This fixes a use-after-free issue with with SIL passes that delete
instructions before destroying the SILBuilder that created them.
Because of this, SILBuilderWithScopes no longer needs to be a template,
which simplifies its call sites.
SILInstruction
--------------
It is neither possible or necessary to manually call setDebugScope()
on a SILInstruction any more. The function still exists as a private
method, but is only used when splicing instructions from one function
to another.
Efficiency
----------
In addition to dropping 20 bytes from each SILInstruction,
SILDebugLocations are now allocated in the SILModule's bump pointer
allocator and are uniqued by SILBuilder. Unfortunately repeat compiles
of the standard library already vary by about 5% so I couldn’t yet
produce reliable numbers for how much this saves overall.
rdar://problem/22017421
The properties of a context indicate those things that are considered
"contained within" the context (among other things). This helps us
avoid producing overly-generic names when we identify a redundancy in
the base name. For example, NSView contains the following:
var gestureRecognizers: [NSGestureRecognizer]
func addGestureRecognizer(gestureRecognizer: NSGestureRecognizer)
func removeGestureRecognizer(gestureRecognizer: NSGestureRecognizer)
Normally, omit-needless-words would prune the two method names down to
"add" and "remove", respectively, because they restate type
information. However, this pruning is not ideal, because a view isn't
primarily a collection of gesture recognizers.
Use the presence of the property "gestureRecognizers" to indicate that
we should not strip "gestureRecognizer" or "gestureRecognizers" from
the base names of methods within that class (or its subclasses).
Note that there is more work to do here to properly deal with API
evolution: a newly-added property shouldn't have any effect on
existing APIs. We should use availability information here, and only
consider properties introduced no later than the entity under
consideration.
A fixed layout type is one about which the compiler is allowed to
make certain assumptions across resilience domains. The assumptions
will be documented elsewhere, but for the purposes of this patch
series, they will include:
- the size of the type
- offsets of stored properties
- whether accessed properties are stored or computed
When -enable-resilience is passed to the frontend, all types become
resilient unless annotated with the @fixed_layout attribute.
So far, the @fixed_layout attribute only comes into play in SIL type
lowering of structs and enums, which now become address-only unless
they are @fixed_layout. For now, @fixed_layout is also allowed on
classes, but has no effect. In the future, support for less resilient
type lowering within a single resilience domain will be added, with
appropriate loads and stores in function prologs and epilogs.
Resilience is not enabled by default, which gives all types fixed
layout and matches the behavior of the compiler today. Since
we do not want the -enable-resilience flag to change the behavior
of existing compiled modules, only the currently-compiling module,
Sema adds the @fixed_layout flag to all declarations when the flag
is off. To reduce the size of .swiftmodule files, this could become
a flag on the module itself in the future.
The reasoning behind this is that the usual case is building
applications and private frameworks, where there is no need to make
anything resilient.
For the standard library, we can start out with resilience disabled,
while perfoming an audit adding @fixed_layout annotations in the
right places. Once the implementation is robust enough we can then
build the standard library with resilience enabled.
Revert "Fix complete_decl_attribute test for @fixed_layout"
Revert "Sema: non-@objc private stored properties do not need accessors"
Revert "Sema: Access stored properties of resilient structs through accessors"
Revert "Strawman @fixed_layout attribute and -{enable,disable}-resilience flags"
This reverts commit c91c6a789e.
This reverts commit 693d3d339f.
This reverts commit 085f88f616.
This reverts commit 5d99dc9bb8.
A fixed layout type is one about which the compiler is allowed to
make certain assumptions across resilience domains. The assumptions
will be documented elsewhere, but for the purposes of this patch
series, they will include:
- the size of the type
- offsets of stored properties
- whether accessed properties are stored or computed
When -enable-resilience is passed to the frontend, all types become
resilient unless annotated with the @fixed_layout attribute.
So far, the @fixed_layout attribute only comes into play in SIL type
lowering of structs and enums, which now become address-only unless
they are @fixed_layout. For now, @fixed_layout is also allowed on
classes, but has no effect. In the future, support for less resilient
type lowering within a single resilience domain will be added, with
appropriate loads and stores in function prologs and epilogs.
Resilience is not enabled by default, which gives all types fixed
layout and matches the behavior of the compiler today. Since
we do not want the -enable-resilience flag to change the behavior
of existing compiled modules, only the currently-compiling module,
Sema adds the @fixed_layout flag to all declarations when the flag
is off. To reduce the size of .swiftmodule files, this could become
a flag on the module itself in the future.
The reasoning behind this is that the usual case is building
applications and private frameworks, where there is no need to make
anything resilient.
For the standard library, we can start out with resilience disabled,
while perfoming an audit adding @fixed_layout annotations in the
right places. Once the implementation is robust enough we can then
build the standard library with resilience enabled.
This reverts r32940. In reality this is not dead code, because
foreign to native thunks have the _TTO mangling. We need better
tests, which I will add in an upcoming commit.
Swift SVN r32945
And include some supplementary mangling changes:
- Give the first generic param (depth=0, index=0) a single character mangling. Even after removing the self type from method declaration types, 'Self' still shows up very frequently in protocol requirement signatures.
- Fix the mangling of generic parameter counts to elide the count when there's only one parameter at the starting depth of the mangling.
Together these carve another 154KB out of a debug standard library. There's some awkwardness in demangled strings that I'll clean up in subsequent commits; since decl types now only mangle the number of generic params at their own depth, it's context-dependent what depths those represent, which we get wrong now. Currying markers are also wrong, but since free function currying is going away, we can mangle the partial application thunks in different ways.
Swift SVN r32896
Previously we represented all successors in a list where each successor
was represented by a SuccessorID. A SuccessorID is essentially an
unsigned int that stores some flags in the lower bits of the
integer. The two flags are: 1. IsDead, 2. IsNonLocal (where non local
means that it is a loop exit edge). When the IsNonLocal flag is not set,
the integer that is actually stored represents the ID of the successor
region. If the IsNonLocal flag is set, then the integer represents the
index in the parent region's successor list of the actual loop exit
successor.
The bug I mentioned was that we were not being careful enough in the
replacement code to distinguish in between successors that were loop
exit successors and those that were not. This could cause us to replace
a loop exit successor whose integer value was the same as the index of a
non-loop exit successor with the non-loop exit successor. This then
would cause us to miscompile and or introduce duplicate values into the
successor list. Luckily an assert I added caught the latter condition.
After I fixed this problem, an interesting performance issue was
exposed. I had assumed when using a list that I would never have more
than 10-20 successors (in general a reasonable assumption). But
introducing loop exit successors adds in an interesting wrinkle, namely
every block with an unreachable terminator will result in a successor
edge. This makes just iterating over a uniqued list really slow.
I solved the issue by writing a new data structure called
BlotSetVector. The interesting thing about BlotSetVector is that all
operations preserve index offsets. This means that if one erases a
value, all other values in the set vector are not moved around in the
internal vector. This is important since a loop exit edge needs to refer
to an invariant offset in the parent region's successor array since we
do not want to have to go through and update large amounts of unrelated
edges every time we erase an edge.
In terms of a test case, this invariant was impossible for me to reproduce since
it is sensitive to the order of successors. Even dumping the file and running
the analysis would not catch it. After 2 days of trying to make a test case I
gave up. But I filed rdar://23228299 to verify that sil-opt can round trip
in memory ordering of various items such as use lists, successors, predecessors,
block ordering, function ordering, etc.
rdar://22238658
Swift SVN r32839
Canonical dependent member types are always based from a generic parameter, so we can use a more optimal mangling that assumes this. We can also introduce substitutions for AssociatedTypeDecls, and when a generic parameter in a signature is constrained by a single protocol, we can leave that protocol qualification out of the unsubstituted associated type mangling. These optimizations together shrink the standard library by 117KB, and bring the length of the longest Swift symbol in the stdlib down from 578 to 334 characters, shorter than the longest C++ symbol in the stdlib.
Swift SVN r32786
This is a WIP to make CompilerVersion more general.
- Rename CompilerVersion to just "Version"
- Make version comparison general and put _compiler_version special logic
with its second version component in a specialized parsing function
- Add a generic version parsing function
Swift SVN r32726
Internal compiler versions must be able to be packed into a 64-bit
value, and there is a limit on how many components we can use and which
values they can take on.
Versions must have no more than five components, assuming a version
X.Y.Z.a.b, where X, Y, Z, a, and b are integers with the following
inclusive ranges:
X: [0 - 214747]
Y: [0 - 999]
Z: [0 - 999]
a: [0 - 999]
b: [0 - 999]
Swift SVN r32724
When users try to print the interface of a specific type (most often through cursor
infor query of SourceKit), we should simplify the original decls by replacing
archetypes with instantiated types, hiding extension details, and omitting
unfulfilled extension requirements. So the users can get the straight-to-the-point
"type interface". This commit builds the testing infrastructure for this feature,
and implements the first trick that wraps extension contents into the interface body.
This commit also moves some generic testing support from SourceKit to Swift.
Swift SVN r32630
Prepend "is" to Boolean property names (e.g., "empty" becomes
"isEmpty") unless the property name strongly indicates its Boolean
nature or we're likely to ruin the name. Therefore, the presence of
one of the following in the property name will suppress this
transformation:
* An auxiliary verb, such as "is", "has", "may", "should", or "will".
* A word ending in "s", indicating either a plural (for which
prepending "is" would be incorrect) or a verb in the continuous
tense (which indicates its Boolean nature, e.g., "translates" in
"translatesCoordinates").
Swift SVN r32458