Skip to content

Commit f3be04a

Browse files
committed
Merge remote-tracking branch 'origin/main' into next
2 parents 05eafcb + b50dfef commit f3be04a

File tree

101 files changed

+503
-138
lines changed

Some content is hidden

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

101 files changed

+503
-138
lines changed

include/swift/AST/ASTTypeIDZone.def

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ SWIFT_TYPEID(BodyInitKind)
2121
SWIFT_TYPEID(BodyInitKindAndExpr)
2222
SWIFT_TYPEID(CtorInitializerKind)
2323
SWIFT_TYPEID(ResultBuilderBodyPreCheck)
24+
SWIFT_TYPEID(Fingerprint)
2425
SWIFT_TYPEID(GenericSignature)
2526
SWIFT_TYPEID(ImplicitImportList)
2627
SWIFT_TYPEID(ImplicitMemberAction)

include/swift/AST/ASTTypeIDs.h

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class ConstructorDecl;
3434
class CustomAttr;
3535
class Decl;
3636
class EnumDecl;
37+
class Fingerprint;
3738
class FuncDecl;
3839
enum class ResultBuilderBodyPreCheck : uint8_t;
3940
class GenericParamList;

include/swift/AST/AbstractSourceFileDepGraphFactory.h

+9-12
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class AbstractSourceFileDepGraphFactory {
3232
const std::string swiftDeps;
3333

3434
/// The fingerprint of the whole file
35-
const std::string fileFingerprint;
35+
Fingerprint fileFingerprint;
3636

3737
/// For debugging
3838
const bool emitDotFileAfterConstruction;
@@ -47,7 +47,7 @@ class AbstractSourceFileDepGraphFactory {
4747
/// See the instance variable comments for explanation.
4848
AbstractSourceFileDepGraphFactory(bool hadCompilationError,
4949
StringRef swiftDeps,
50-
StringRef fileFingerprint,
50+
Fingerprint fileFingerprint,
5151
bool emitDotFileAfterConstruction,
5252
DiagnosticEngine &diags);
5353

@@ -71,33 +71,30 @@ class AbstractSourceFileDepGraphFactory {
7171
template <NodeKind kind, typename ContentsT>
7272
void addAllDefinedDeclsOfAGivenType(std::vector<ContentsT> &contentsVec) {
7373
for (const auto &declOrPair : contentsVec) {
74-
Optional<std::string> fp =
74+
auto fp =
7575
AbstractSourceFileDepGraphFactory::getFingerprintIfAny(declOrPair);
7676
addADefinedDecl(
7777
DependencyKey::createForProvidedEntityInterface<kind>(declOrPair),
78-
fp ? StringRef(fp.getValue()) : Optional<StringRef>());
78+
fp);
7979
}
8080
}
8181

8282
/// Add an pair of interface, implementation nodes to the graph, which
8383
/// represent some \c Decl defined in this source file. \param key the
8484
/// interface key of the pair
8585
void addADefinedDecl(const DependencyKey &key,
86-
Optional<StringRef> fingerprint);
86+
Optional<Fingerprint> fingerprint);
8787

8888
void addAUsedDecl(const DependencyKey &def, const DependencyKey &use);
8989

90-
static Optional<std::string> getFingerprintIfAny(
91-
std::pair<const NominalTypeDecl *, const ValueDecl *>) {
90+
static Optional<Fingerprint>
91+
getFingerprintIfAny(std::pair<const NominalTypeDecl *, const ValueDecl *>) {
9292
return None;
9393
}
9494

95-
static Optional<std::string> getFingerprintIfAny(const Decl *d) {
95+
static Optional<Fingerprint> getFingerprintIfAny(const Decl *d) {
9696
if (const auto *idc = dyn_cast<IterableDeclContext>(d)) {
97-
auto result = idc->getBodyFingerprint();
98-
assert((!result || !result->empty()) &&
99-
"Fingerprint should never be empty");
100-
return result;
97+
return idc->getBodyFingerprint();
10198
}
10299
return None;
103100
}

include/swift/AST/DeclContext.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/ResilienceExpansion.h"
2525
#include "swift/AST/TypeAlignments.h"
2626
#include "swift/Basic/Debug.h"
27+
#include "swift/Basic/Fingerprint.h"
2728
#include "swift/Basic/LLVM.h"
2829
#include "swift/Basic/STLExtras.h"
2930
#include "swift/Basic/SourceLoc.h"
@@ -871,7 +872,7 @@ class IterableDeclContext {
871872

872873
/// Return a hash of all tokens in the body for dependency analysis, if
873874
/// available.
874-
Optional<std::string> getBodyFingerprint() const;
875+
Optional<Fingerprint> getBodyFingerprint() const;
875876

876877
private:
877878
/// Add a member to the list for iteration purposes, but do not notify the

include/swift/AST/FileUnit.h

+3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ class FileUnit : public DeclContext {
110110
const ModuleDecl *importedModule,
111111
SmallSetVector<Identifier, 4> &spiGroups) const {};
112112

113+
virtual Optional<Fingerprint>
114+
loadFingerprint(const IterableDeclContext *IDC) const { return None; }
115+
113116
protected:
114117
/// Look up an operator declaration. Do not call directly, use
115118
/// \c DirectOperatorLookupRequest instead.

include/swift/AST/FineGrainedDependencies.h

+8-21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_AST_FINE_GRAINED_DEPENDENCIES_H
1515

1616
#include "swift/Basic/Debug.h"
17+
#include "swift/Basic/Fingerprint.h"
1718
#include "swift/Basic/LLVM.h"
1819
#include "swift/Basic/NullablePtr.h"
1920
#include "swift/Basic/Range.h"
@@ -599,22 +600,15 @@ class DepGraphNode {
599600
/// frontend creates an interface node,
600601
// it adds a dependency to it from the implementation source file node (which
601602
// has the intefaceHash as its fingerprint).
602-
Optional<std::string> fingerprint;
603+
Optional<Fingerprint> fingerprint;
603604

604605
friend ::llvm::yaml::MappingTraits<DepGraphNode>;
605606

606607
public:
607608
/// See \ref SourceFileDepGraphNode::SourceFileDepGraphNode().
608609
DepGraphNode() : key(), fingerprint() {}
609610

610-
/// See SourceFileDepGraphNode::SourceFileDepGraphNode(...) and
611-
/// ModuleDepGraphNode::ModuleDepGraphNode(...) Don't set swiftDeps on
612-
/// creation because this field can change if a node is moved.
613-
DepGraphNode(DependencyKey key, Optional<StringRef> fingerprint)
614-
: DepGraphNode(key, fingerprint ? fingerprint->str()
615-
: Optional<std::string>()) {}
616-
617-
DepGraphNode(DependencyKey key, Optional<std::string> fingerprint)
611+
DepGraphNode(DependencyKey key, Optional<Fingerprint> fingerprint)
618612
: key(key), fingerprint(fingerprint) {}
619613
DepGraphNode(const DepGraphNode &other) = default;
620614

@@ -630,12 +624,7 @@ class DepGraphNode {
630624
this->key = key;
631625
}
632626

633-
const Optional<StringRef> getFingerprint() const {
634-
if (fingerprint) {
635-
return StringRef(fingerprint.getValue());
636-
}
637-
return None;
638-
}
627+
const Optional<Fingerprint> getFingerprint() const { return fingerprint; }
639628
/// When driver reads a SourceFileDepGraphNode, it may be a node that was
640629
/// created to represent a name-lookup (a.k.a a "depend") in the frontend. In
641630
/// that case, the node represents an entity that resides in some other file
@@ -644,9 +633,7 @@ class DepGraphNode {
644633
/// (someday) have a fingerprint. In order to preserve the
645634
/// ModuleDepGraphNode's identity but bring its fingerprint up to date, it
646635
/// needs to set the fingerprint *after* the node has been created.
647-
void setFingerprint(Optional<StringRef> fp) {
648-
fingerprint = fp ? fp->str() : Optional<std::string>();
649-
}
636+
void setFingerprint(Optional<Fingerprint> fp) { fingerprint = fp; }
650637

651638
SWIFT_DEBUG_DUMP;
652639
void dump(llvm::raw_ostream &os) const;
@@ -693,7 +680,7 @@ class SourceFileDepGraphNode : public DepGraphNode {
693680
SourceFileDepGraphNode() : DepGraphNode() {}
694681

695682
/// Used by the frontend to build nodes.
696-
SourceFileDepGraphNode(DependencyKey key, Optional<StringRef> fingerprint,
683+
SourceFileDepGraphNode(DependencyKey key, Optional<Fingerprint> fingerprint,
697684
bool isProvides)
698685
: DepGraphNode(key, fingerprint), isProvides(isProvides) {
699686
assert(key.verify());
@@ -827,14 +814,14 @@ class SourceFileDepGraph {
827814
/// file itself.
828815
InterfaceAndImplementationPair<SourceFileDepGraphNode>
829816
findExistingNodePairOrCreateAndAddIfNew(const DependencyKey &interfaceKey,
830-
Optional<StringRef> fingerprint);
817+
Optional<Fingerprint> fingerprint);
831818

832819
NullablePtr<SourceFileDepGraphNode>
833820
findExistingNode(const DependencyKey &key);
834821

835822
SourceFileDepGraphNode *
836823
findExistingNodeOrCreateIfNew(const DependencyKey &key,
837-
const Optional<StringRef> fingerprint,
824+
const Optional<Fingerprint> fingerprint,
838825
bool isProvides);
839826

840827
/// \p Use is the Node that must be rebuilt when \p def changes.

include/swift/AST/Module.h

+3
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,9 @@ class ModuleDecl : public DeclContext, public TypeDecl {
572572
ObjCSelector selector,
573573
SmallVectorImpl<AbstractFunctionDecl *> &results) const;
574574

575+
Optional<Fingerprint>
576+
loadFingerprint(const IterableDeclContext *IDC) const;
577+
575578
/// Find all SPI names imported from \p importedModule by this module,
576579
/// collecting the identifiers in \p spiGroups.
577580
void lookupImportedSPIGroups(

include/swift/AST/ParseRequests.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTTypeIDs.h"
2020
#include "swift/AST/EvaluatorDependencies.h"
2121
#include "swift/AST/SimpleRequest.h"
22+
#include "swift/Basic/Fingerprint.h"
2223
#include "swift/Syntax/SyntaxNodes.h"
2324

2425
namespace swift {
@@ -30,7 +31,7 @@ void reportEvaluatedRequest(UnifiedStatsReporter &stats,
3031
const Request &request);
3132

3233
struct FingerprintAndMembers {
33-
Optional<std::string> fingerprint = None;
34+
Optional<Fingerprint> fingerprint = None;
3435
ArrayRef<Decl *> members = {};
3536
bool operator==(const FingerprintAndMembers &x) const {
3637
return fingerprint == x.fingerprint && members == x.members;

include/swift/AST/SourceFile.h

+2-4
Original file line numberDiff line numberDiff line change
@@ -525,12 +525,10 @@ class SourceFile final : public FileUnit {
525525
}
526526

527527
/// Output this file's interface hash into the provided string buffer.
528-
void getInterfaceHash(llvm::SmallString<32> &str) const;
528+
Fingerprint getInterfaceHash() const;
529529

530530
void dumpInterfaceHash(llvm::raw_ostream &out) {
531-
llvm::SmallString<32> str;
532-
getInterfaceHash(str);
533-
out << str << '\n';
531+
out << getInterfaceHash() << '\n';
534532
}
535533

536534
/// If this source file has been told to collect its parsed tokens, retrieve

include/swift/Basic/Fingerprint.h

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//===--- Fingerprint.h - A stable identity for compiler data ----*- 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+
#ifndef SWIFT_BASIC_FINGERPRINT_H
14+
#define SWIFT_BASIC_FINGERPRINT_H
15+
16+
#include "llvm/ADT/Hashing.h"
17+
#include "llvm/ADT/SmallString.h"
18+
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/Support/MD5.h"
20+
21+
#include <string>
22+
23+
namespace llvm {
24+
namespace yaml {
25+
class IO;
26+
}
27+
}; // namespace llvm
28+
29+
namespace swift {
30+
31+
/// A \c Fingerprint represents a stable summary of a given piece of data
32+
/// in the compiler.
33+
///
34+
/// A \c Fingerprint value is subject to the following invariants:
35+
/// 1) For two values \c x and \c y of type T, if \c T::operator==(x, y) is
36+
/// \c true, then the Fingerprint of \c x and the Fingerprint of \c y must be
37+
/// equal.
38+
/// 2) For two values \c x and \c y of type T, the chance of a collision in
39+
/// fingerprints is a rare occurrence - especially if \c y is a minor
40+
/// perturbation of \c x.
41+
/// 3) The \c Fingerprint value is required to be stable *across compilation
42+
/// sessions*.
43+
///
44+
/// Property 3) is the most onerous. It implies that data like addresses, file
45+
/// paths, and other ephemeral compiler state *may not* be used as inputs to the
46+
/// fingerprint generation function.
47+
///
48+
/// \c Fingerprint values are currently used in two places by the compiler's
49+
/// dependency tracking subsystem. They are used at the level of files to detect
50+
/// when tokens (outside of the body of a function or an iterable decl context)
51+
/// have been perturbed. Additionally, they are used at the level of individual
52+
/// iterable decl contexts to detect when the tokens in their bodies have
53+
/// changed. This makes them a coarse - yet safe - overapproximation for when a
54+
/// decl has changed semantically.
55+
///
56+
/// \c Fingerprints are currently implemented as a thin wrapper around an MD5
57+
/// hash. MD5 is known to be neither the fastest nor the most
58+
/// cryptographically capable algorithm, but it does afford us the avalanche
59+
/// effect we desire. We should revisit the modeling decision here.
60+
class Fingerprint final {
61+
public:
62+
/// The size (in bytes) of the raw value of all fingerprints.
63+
///
64+
/// This constant's value is justified by a static assertion in the
65+
/// corresponding cpp file.
66+
constexpr static size_t DIGEST_LENGTH = 32;
67+
68+
private:
69+
std::string Core;
70+
71+
public:
72+
/// Creates a fingerprint value from the given input string that is known to
73+
/// be a 32-byte hash value.
74+
///
75+
/// In +asserts builds, strings that violate this invariant will crash. If a
76+
/// fingerprint value is needed to represent an "invalid" state, use a
77+
/// vocabulary type like \c Optional<Fingerprint> instead.
78+
explicit Fingerprint(std::string value) : Core(std::move(value)) {
79+
assert(Core.size() == Fingerprint::DIGEST_LENGTH &&
80+
"Only supports 32-byte hash values!");
81+
}
82+
83+
/// Creates a fingerprint value from the given input string literal.
84+
template <std::size_t N>
85+
explicit Fingerprint(const char (&literal)[N])
86+
: Core{literal, N-1} {
87+
static_assert(N == Fingerprint::DIGEST_LENGTH + 1,
88+
"String literal must be 32 bytes in length!");
89+
}
90+
91+
/// Creates a fingerprint value by consuming the given \c MD5Result from LLVM.
92+
explicit Fingerprint(llvm::MD5::MD5Result &&MD5Value)
93+
: Core{MD5Value.digest().str()} {}
94+
95+
public:
96+
/// Retrieve the raw underlying bytes of this fingerprint.
97+
llvm::StringRef getRawValue() const { return Core; }
98+
99+
public:
100+
friend bool operator==(const Fingerprint &lhs, const Fingerprint &rhs) {
101+
return lhs.Core == rhs.Core;
102+
}
103+
104+
friend bool operator!=(const Fingerprint &lhs, const Fingerprint &rhs) {
105+
return lhs.Core != rhs.Core;
106+
}
107+
108+
friend llvm::hash_code hash_value(const Fingerprint &fp) {
109+
return llvm::hash_value(fp.Core);
110+
}
111+
112+
public:
113+
/// The fingerprint value consisting of 32 bytes of zeroes.
114+
///
115+
/// This fingerprint is a perfectly fine value for an MD5 hash, but it is
116+
/// completely arbitrary.
117+
static Fingerprint ZERO() {
118+
return Fingerprint("00000000000000000000000000000000");
119+
}
120+
121+
private:
122+
/// llvm::yaml would like us to be default constructible, but \c Fingerprint
123+
/// would prefer to enforce its internal invariants.
124+
///
125+
/// Very well, LLVM. A default value you shall have.
126+
friend class llvm::yaml::IO;
127+
Fingerprint() : Core{DIGEST_LENGTH, '0'} {}
128+
};
129+
130+
void simple_display(llvm::raw_ostream &out, const Fingerprint &fp);
131+
}; // namespace swift
132+
133+
namespace llvm {
134+
class raw_ostream;
135+
raw_ostream &operator<<(raw_ostream &OS, const swift::Fingerprint &fp);
136+
}; // namespace llvm
137+
138+
#endif // SWIFT_BASIC_FINGERPRINT_H

include/swift/Driver/FineGrainedDependencyDriverGraph.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "swift/AST/FineGrainedDependencies.h"
1717
#include "swift/Basic/Debug.h"
18+
#include "swift/Basic/Fingerprint.h"
1819
#include "swift/Basic/LLVM.h"
1920
#include "swift/Basic/OptionSet.h"
2021
#include "swift/Driver/Job.h"
@@ -55,7 +56,8 @@ class ModuleDepGraphNode : public DepGraphNode {
5556
bool hasBeenTracedAsADependent = false;
5657

5758
public:
58-
ModuleDepGraphNode(const DependencyKey &key, Optional<StringRef> fingerprint,
59+
ModuleDepGraphNode(const DependencyKey &key,
60+
Optional<Fingerprint> fingerprint,
5961
Optional<std::string> swiftDeps)
6062
: DepGraphNode(key, fingerprint), swiftDeps(swiftDeps) {}
6163

0 commit comments

Comments
 (0)