Skip to content

Commit e81ed9f

Browse files
authored
Merge pull request #35288 from slavapestov/perf-fixes-5.4
Cherry-pick compiler performance fixes [5.4]
2 parents 52f9da7 + b10dda6 commit e81ed9f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1084
-597
lines changed

include/swift/AST/ASTScope.h

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,16 @@ class ASTScopeImpl {
136136
/// storage declaration or is directly descended from it.
137137

138138
private:
139-
/// Always set by the constructor, so that when creating a child
140-
/// the parent chain is available.
141-
ASTScopeImpl *parent = nullptr; // null at the root
139+
/// The pointer:
140+
/// - Always set by the constructor, so that when creating a child
141+
/// the parent chain is available. Null at the root.
142+
/// The int:
143+
/// - A flag indicating if the scope has been expanded yet or not.
144+
llvm::PointerIntPair<ASTScopeImpl *, 1> parentAndWasExpanded;
142145

143146
/// Child scopes, sorted by source range.
144147
Children storedChildren;
145148

146-
bool wasExpanded = false;
147-
148-
/// Can clear storedChildren, so must remember this
149-
bool haveAddedCleanup = false;
150-
151149
mutable Optional<CharSourceRange> cachedCharSourceRange;
152150

153151
#pragma mark - constructor / destructor
@@ -177,8 +175,12 @@ class ASTScopeImpl {
177175

178176
#pragma mark - tree declarations
179177
protected:
180-
NullablePtr<ASTScopeImpl> getParent() { return parent; }
181-
NullablePtr<const ASTScopeImpl> getParent() const { return parent; }
178+
NullablePtr<ASTScopeImpl> getParent() {
179+
return parentAndWasExpanded.getPointer();
180+
}
181+
NullablePtr<const ASTScopeImpl> getParent() const {
182+
return parentAndWasExpanded.getPointer();
183+
}
182184

183185
const Children &getChildren() const { return storedChildren; }
184186

@@ -247,19 +249,13 @@ class ASTScopeImpl {
247249

248250
#pragma mark - Scope tree creation
249251
public:
250-
/// expandScope me, sending deferred nodes to my descendants.
251-
/// Return the scope into which to place subsequent decls
252-
ASTScopeImpl *expandAndBeCurrentDetectingRecursion(ScopeCreator &);
253-
254-
/// Expand or reexpand the scope if unexpanded or if not current.
255-
/// There are several places in the compiler that mutate the AST after the
256-
/// fact, above and beyond adding Decls to the SourceFile.
252+
/// Expand the scope if unexpanded.
257253
ASTScopeImpl *expandAndBeCurrent(ScopeCreator &);
258254

259-
bool getWasExpanded() const { return wasExpanded; }
255+
bool getWasExpanded() const { return parentAndWasExpanded.getInt(); }
260256

261257
protected:
262-
void setWasExpanded() { wasExpanded = true; }
258+
void setWasExpanded() { parentAndWasExpanded.setInt(1); }
263259
virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0;
264260

265261
public:
@@ -360,7 +356,7 @@ class ASTScopeImpl {
360356
/// what obtaines for scoping. However, guards are different. The scope after
361357
/// the guard else must hop into the innermoset scope of the guard condition.
362358
virtual NullablePtr<const ASTScopeImpl> getLookupParent() const {
363-
return parent;
359+
return getParent();
364360
}
365361

366362
#pragma mark - - lookup- local bindings
@@ -629,8 +625,6 @@ class IterableTypeScope : public GenericTypeScope {
629625

630626
public:
631627
NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override;
632-
633-
void countBodies(ScopeCreator &) const;
634628
};
635629

636630
class NominalTypeScope final : public IterableTypeScope {

include/swift/AST/AnyRequest.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct AnyRequestVTable {
8383
const std::function<void(const void *, DiagnosticEngine &)> noteCycleStep;
8484
const std::function<SourceLoc(const void *)> getNearestLoc;
8585
const std::function<bool(const void *)> isCached;
86+
bool isDependencySource;
8687

8788
template <typename Request,
8889
typename std::enable_if<Request::isEverCached>::type * = nullptr>
@@ -99,6 +100,7 @@ struct AnyRequestVTable {
99100
&Impl<Request>::noteCycleStep,
100101
&Impl<Request>::getNearestLoc,
101102
&Impl<Request>::isCached,
103+
Request::isDependencySource,
102104
};
103105
return &vtable;
104106
}
@@ -118,6 +120,7 @@ struct AnyRequestVTable {
118120
&Impl<Request>::noteCycleStep,
119121
&Impl<Request>::getNearestLoc,
120122
[](auto){ return false; },
123+
Request::isDependencySource,
121124
};
122125
return &vtable;
123126
}
@@ -224,6 +227,10 @@ class AnyRequestBase {
224227
return getVTable()->isCached(getRawStorage());
225228
}
226229

230+
bool isDependencySource() const {
231+
return getVTable()->isDependencySource;
232+
}
233+
227234
/// Compare two instances for equality.
228235
friend bool operator==(const AnyRequestBase<Derived> &lhs,
229236
const AnyRequestBase<Derived> &rhs) {

include/swift/AST/Decl.h

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class alignas(1 << DeclAlignInBits) Decl {
418418
HasNestedTypeDeclarations : 1
419419
);
420420

421-
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
421+
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1+1+1,
422422
/// Whether we've computed the 'static' flag yet.
423423
IsStaticComputed : 1,
424424

@@ -437,21 +437,28 @@ class alignas(1 << DeclAlignInBits) Decl {
437437
/// Backing bits for 'self' access kind.
438438
SelfAccess : 2,
439439

440+
/// Whether we've computed the IsAsyncHandlerRequest.
441+
IsAsyncHandlerComputed : 1,
442+
443+
/// The value of IsAsyncHandlerRequest.
444+
IsAsyncHandler : 1,
445+
440446
/// Whether this is a top-level function which should be treated
441447
/// as if it were in local context for the purposes of capture
442448
/// analysis.
443449
HasTopLevelLocalContextCaptures : 1
444450
);
445451

446452
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4 + 1 + 1,
447-
/// The kind of accessor this is.
448-
AccessorKind : 4,
453+
/// The kind of accessor this is.
454+
AccessorKind : 4,
449455

450-
/// Whether the accessor is transparent.
451-
IsTransparent : 1,
456+
/// Whether the accessor is transparent.
457+
IsTransparent : 1,
452458

453-
/// Whether we have computed the above.
454-
IsTransparentComputed : 1);
459+
/// Whether we have computed the above.
460+
IsTransparentComputed : 1
461+
);
455462

456463
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 1+1,
457464
/// Whether this constructor can fail, by building an Optional type.
@@ -5926,6 +5933,7 @@ class FuncDecl : public AbstractFunctionDecl {
59265933
friend class SelfAccessKindRequest;
59275934
friend class IsStaticRequest;
59285935
friend class ResultTypeRequest;
5936+
friend class IsAsyncHandlerRequest;
59295937

59305938
SourceLoc StaticLoc; // Location of the 'static' token or invalid.
59315939
SourceLoc FuncLoc; // Location of the 'func' token.
@@ -5957,6 +5965,8 @@ class FuncDecl : public AbstractFunctionDecl {
59575965
Bits.FuncDecl.SelfAccessComputed = false;
59585966
Bits.FuncDecl.IsStaticComputed = false;
59595967
Bits.FuncDecl.IsStatic = false;
5968+
Bits.FuncDecl.IsAsyncHandlerComputed = false;
5969+
Bits.FuncDecl.IsAsyncHandler = false;
59605970
Bits.FuncDecl.HasTopLevelLocalContextCaptures = false;
59615971
}
59625972

@@ -5987,6 +5997,18 @@ class FuncDecl : public AbstractFunctionDecl {
59875997
return None;
59885998
}
59895999

6000+
Optional<bool> getCachedIsAsyncHandler() const {
6001+
if (Bits.FuncDecl.IsAsyncHandlerComputed)
6002+
return Bits.FuncDecl.IsAsyncHandler;
6003+
6004+
return None;
6005+
}
6006+
6007+
void setIsAsyncHandler(bool value) {
6008+
Bits.FuncDecl.IsAsyncHandlerComputed = true;
6009+
Bits.FuncDecl.IsAsyncHandler = value;
6010+
}
6011+
59906012
public:
59916013
/// Factory function only for use by deserialization.
59926014
static FuncDecl *createDeserialized(ASTContext &Context,
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//===--- DependencyCollector.h -------------------------------- -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines a class for recording incremental dependencies.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_DEPENDENCY_COLLECTOR_H
18+
#define SWIFT_AST_DEPENDENCY_COLLECTOR_H
19+
20+
#include "swift/AST/Identifier.h"
21+
#include "llvm/ADT/DenseMap.h"
22+
#include "llvm/ADT/DenseSet.h"
23+
24+
namespace swift {
25+
26+
class NominalTypeDecl;
27+
28+
namespace evaluator {
29+
30+
class DependencyRecorder;
31+
32+
/// A \c DependencyCollector defines an abstract write-only buffer of
33+
/// \c Reference objects. References are added to a collector during the write
34+
/// phase of request evaluation (in \c writeDependencySink) with the various
35+
/// \c add* functions below.
36+
///
37+
/// A \c DependencyCollector should not be created directly; instances are
38+
/// vended by the request evaluator infrastructure itself.
39+
struct DependencyCollector {
40+
friend DependencyRecorder;
41+
42+
struct Reference {
43+
public:
44+
enum class Kind {
45+
Empty,
46+
Tombstone,
47+
UsedMember,
48+
PotentialMember,
49+
TopLevel,
50+
Dynamic,
51+
} kind;
52+
53+
NominalTypeDecl *subject;
54+
DeclBaseName name;
55+
56+
private:
57+
Reference(Kind kind, NominalTypeDecl *subject, DeclBaseName name)
58+
: kind(kind), subject(subject), name(name) {}
59+
60+
public:
61+
static Reference empty() {
62+
return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey(),
63+
llvm::DenseMapInfo<DeclBaseName>::getEmptyKey()};
64+
}
65+
66+
static Reference tombstone() {
67+
return {Kind::Tombstone,
68+
llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey(),
69+
llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey()};
70+
}
71+
72+
public:
73+
static Reference usedMember(NominalTypeDecl *subject, DeclBaseName name) {
74+
return {Kind::UsedMember, subject, name};
75+
}
76+
77+
static Reference potentialMember(NominalTypeDecl *subject) {
78+
return {Kind::PotentialMember, subject, DeclBaseName()};
79+
}
80+
81+
static Reference topLevel(DeclBaseName name) {
82+
return {Kind::TopLevel, nullptr, name};
83+
}
84+
85+
static Reference dynamic(DeclBaseName name) {
86+
return {Kind::Dynamic, nullptr, name};
87+
}
88+
89+
public:
90+
struct Info {
91+
static inline Reference getEmptyKey() { return Reference::empty(); }
92+
static inline Reference getTombstoneKey() {
93+
return Reference::tombstone();
94+
}
95+
static inline unsigned getHashValue(const Reference &Val) {
96+
return llvm::hash_combine(Val.kind, Val.subject,
97+
Val.name.getAsOpaquePointer());
98+
}
99+
static bool isEqual(const Reference &LHS, const Reference &RHS) {
100+
return LHS.kind == RHS.kind && LHS.subject == RHS.subject &&
101+
LHS.name == RHS.name;
102+
}
103+
};
104+
};
105+
106+
private:
107+
DependencyRecorder &parent;
108+
109+
public:
110+
explicit DependencyCollector(DependencyRecorder &parent);
111+
~DependencyCollector();
112+
113+
public:
114+
/// Registers a named reference from the current dependency scope to a member
115+
/// defined in the given \p subject type.
116+
///
117+
/// Used member constraints are typically the by-product of direct lookups,
118+
/// where the name being looked up and the target of the lookup are known
119+
/// up front. A used member dependency causes the file to be rebuilt if the
120+
/// definition of that member changes in any way - via
121+
/// deletion, addition, or mutation of a member with that same name.
122+
void addUsedMember(NominalTypeDecl *subject, DeclBaseName name);
123+
/// Registers a reference from the current dependency scope to a
124+
/// "potential member" of the given \p subject type.
125+
///
126+
/// A single potential member dependency can be thought of as many used member
127+
/// dependencies - one for each current member of the subject type, but also
128+
/// one for every member that will be added or removed from the type in the
129+
/// future. As such, these dependencies cause rebuilds when any members are
130+
/// added, removed, or changed in the \p subject type. It also indicates a
131+
/// dependency on the \p subject type's existence, so deleting the \p subject
132+
/// type will also cause a rebuild.
133+
///
134+
/// These dependencies are most appropriate for protocol conformances,
135+
/// superclass constraints, and other requirements involving entire types.
136+
void addPotentialMember(NominalTypeDecl *subject);
137+
/// Registers a reference from the current dependency scope to a given
138+
/// top-level \p name.
139+
///
140+
/// A top level dependency causes a rebuild when another top-level entity with
141+
/// that name is added, removed, or modified.
142+
void addTopLevelName(DeclBaseName name);
143+
/// Registers a reference from the current dependency scope to a given
144+
/// dynamic member \p name.
145+
///
146+
/// A dynamic lookup dependency is a special kind of member dependency on
147+
/// a name that is found by \c AnyObject lookup.
148+
void addDynamicLookupName(DeclBaseName name);
149+
150+
public:
151+
/// Retrieves the dependency recorder that created this dependency collector.
152+
const DependencyRecorder &getRecorder() const { return parent; }
153+
};
154+
155+
} // end namespace evaluator
156+
157+
} // end namespace swift
158+
159+
#endif // SWIFT_AST_DEPENDENCY_COLLECTOR_H

0 commit comments

Comments
 (0)