/
ProtocolConformance.cpp
109 lines (97 loc) · 3.88 KB
/
ProtocolConformance.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//===--- ProtocolConformance.cpp - Swift protocol conformance checking ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Checking and caching of Swift protocol conformances.
//
// This implementation is intended to be backward-deployed into Swift 5.0
// runtimes.
//
//===----------------------------------------------------------------------===//
#include "../../public/runtime/Private.h"
#include "Overrides.h"
#include "swift/Threading/Once.h"
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include <objc/runtime.h>
using namespace swift;
#if __POINTER_WIDTH__ == 64
using mach_header_platform = mach_header_64;
#else
using mach_header_platform = mach_header;
#endif
/// The Mach-O section name for the section containing protocol conformances.
/// This lives within SEG_TEXT.
constexpr const char ProtocolConformancesSection[] = "__swift5_proto";
// A dummy target context descriptor to use in conformance records which point
// to a NULL descriptor. It doesn't have to be completely valid, just something
// that code reading conformance descriptors will ignore.
struct {
ContextDescriptorFlags flags;
int32_t offset;
} DummyTargetContextDescriptor = {
ContextDescriptorFlags().withKind(ContextDescriptorKind::Extension),
0
};
// Search for any protocol conformance descriptors with a NULL type descriptor
// and rewrite those to point to the dummy descriptor. This occurs when an
// extension is used to declare a conformance on a weakly linked type and that
// type is not present at runtime.
static void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) {
unsigned long size;
const uint8_t *section =
getsectiondata(reinterpret_cast<const mach_header_platform *>(mh),
SEG_TEXT, ProtocolConformancesSection,
&size);
if (!section)
return;
auto recordsBegin
= reinterpret_cast<const ProtocolConformanceRecord*>(section);
auto recordsEnd
= reinterpret_cast<const ProtocolConformanceRecord*>
(section + size);
for (auto record = recordsBegin; record != recordsEnd; ++record) {
auto descriptor = record->get();
if (auto typePtr = descriptor->_getTypeDescriptorLocation()) {
if (*typePtr == nullptr)
*typePtr = reinterpret_cast<TargetContextDescriptor<InProcess> *>(
&DummyTargetContextDescriptor);
}
}
}
// Register the add image callback with dyld.
static void registerAddImageCallback(void *) {
_dyld_register_func_for_add_image(addImageCallback);
}
// Defined in libswiftCompatibility51, which is always linked if we link against
// libswiftCompatibility50
const Metadata *_swiftoverride_class_getSuperclass(const Metadata *theClass);
const WitnessTable *
swift::swift50override_conformsToProtocol(const Metadata *type,
const ProtocolDescriptor *protocol,
ConformsToProtocol_t *original_conformsToProtocol)
{
// Register our add image callback if necessary.
static swift::once_t token;
swift::once(token, registerAddImageCallback, nullptr);
// The implementation of swift_conformsToProtocol in Swift 5.0 would return
// a false negative answer when asking whether a subclass conforms using
// a conformance from a superclass. Work around this by walking up the
// superclass chain in cases where the original implementation returns
// null.
do {
auto result = original_conformsToProtocol(type, protocol);
if (result)
return result;
} while ((type = _swiftoverride_class_getSuperclass(type)));
return nullptr;
}