Skip to content

[Runtime] When the ObjC runtime supports lazy class names, lazily create the ObjC names for generic classes. #28753

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 4 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,6 @@ class Demangler : public NodeFactory {
NodePointer demangleGenericType();
NodePointer demangleValueWitness();

NodePointer demangleObjCTypeName();
NodePointer demangleTypeMangling();
NodePointer demangleSymbolicReference(unsigned char rawKind,
const void *at);
Expand Down
44 changes: 1 addition & 43 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ NodePointer Demangler::demangleSymbol(StringRef MangledName,
// Demangle old-style class and protocol names, which are still used in the
// ObjC metadata.
if (nextIf("_Tt"))
return demangleObjCTypeName();
return demangleOldSymbolAsNode(Text, *this);

unsigned PrefixLength = getManglingPrefixLength(MangledName);
if (PrefixLength == 0)
Expand Down Expand Up @@ -3193,45 +3193,3 @@ NodePointer Demangler::demangleValueWitness() {
addChild(VW, createNode(Node::Kind::Index, unsigned(Kind)));
return addChild(VW, popNode(Node::Kind::Type));
}

NodePointer Demangler::demangleObjCTypeName() {
NodePointer Ty = createNode(Node::Kind::Type);
NodePointer Global = addChild(createNode(Node::Kind::Global),
addChild(createNode(Node::Kind::TypeMangling), Ty));
NodePointer Nominal = nullptr;
bool isProto = false;
if (nextIf('C')) {
Nominal = createNode(Node::Kind::Class);
addChild(Ty, Nominal);
} else if (nextIf('P')) {
isProto = true;
Nominal = createNode(Node::Kind::Protocol);
addChild(Ty, addChild(createNode(Node::Kind::ProtocolList),
addChild(createNode(Node::Kind::TypeList),
addChild(createNode(Node::Kind::Type), Nominal))));
} else {
return nullptr;
}

if (nextIf('s')) {
Nominal->addChild(createNode(Node::Kind::Module, "Swift"), *this);
} else {
NodePointer Module = demangleIdentifier();
if (!Module)
return nullptr;
Nominal->addChild(changeKind(Module, Node::Kind::Module), *this);
}

NodePointer Ident = demangleIdentifier();
if (!Ident)
return nullptr;
Nominal->addChild(Ident, *this);

if (isProto && !nextIf('_'))
return nullptr;

if (Pos < Text.size())
return nullptr;

return Global;
}
56 changes: 51 additions & 5 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2172,7 +2172,10 @@ namespace {
#if __POINTER_WIDTH__ == 64
uint32_t Reserved;
#endif
const uint8_t *IvarLayout;
union {
const uint8_t *IvarLayout;
ClassMetadata *NonMetaClass;
};
const char *Name;
const void *MethodList;
const void *ProtocolList;
Expand All @@ -2197,7 +2200,7 @@ static inline ClassROData *getROData(ClassMetadata *theClass) {
return (ClassROData*)(theClass->Data & ~uintptr_t(SWIFT_CLASS_IS_SWIFT_MASK));
}

static void initGenericClassObjCName(ClassMetadata *theClass) {
static char *copyGenericClassObjCName(ClassMetadata *theClass) {
// Use the remangler to generate a mangled name from the type metadata.
Demangle::StackAllocatedDemangler<4096> Dem;

Expand Down Expand Up @@ -2230,11 +2233,54 @@ static void initGenericClassObjCName(ClassMetadata *theClass) {
} else {
fullNameBuf[string.size()] = '\0';
}
return fullNameBuf;
}

static void initGenericClassObjCName(ClassMetadata *theClass) {
auto theMetaclass = (ClassMetadata *)object_getClass((id)theClass);

getROData(theClass)->Name = fullNameBuf;
getROData(theMetaclass)->Name = fullNameBuf;
char *name = copyGenericClassObjCName(theClass);
getROData(theClass)->Name = name;
getROData(theMetaclass)->Name = name;
}

static bool installLazyClassNameHook() {
#if !OBJC_SETHOOK_LAZYCLASSNAMER_DEFINED
using objc_hook_lazyClassNamer =
const char * _Nullable (*)(_Nonnull Class cls);
auto objc_setHook_lazyClassNamer =
(void (*)(objc_hook_lazyClassNamer, objc_hook_lazyClassNamer *))
dlsym(RTLD_NEXT, "objc_setHook_lazyClassNamer");
#endif

static objc_hook_lazyClassNamer oldHook;
auto myHook = [](Class theClass) -> const char * {
ClassMetadata *metadata = (ClassMetadata *)theClass;
if (metadata->isTypeMetadata())
return copyGenericClassObjCName(metadata);
return oldHook(theClass);
};

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
if (objc_setHook_lazyClassNamer == nullptr)
return false;
objc_setHook_lazyClassNamer(myHook, &oldHook);
#pragma clang diagnostic pop

return true;
}

static void setUpGenericClassObjCName(ClassMetadata *theClass) {
bool supportsLazyNames = SWIFT_LAZY_CONSTANT(installLazyClassNameHook());
if (supportsLazyNames) {
getROData(theClass)->Name = nullptr;
auto theMetaclass = (ClassMetadata *)object_getClass((id)theClass);
getROData(theMetaclass)->Name = nullptr;
getROData(theMetaclass)->NonMetaClass = theClass;
} else {
initGenericClassObjCName(theClass);
}
}
#endif

Expand Down Expand Up @@ -2488,7 +2534,7 @@ initGenericObjCClass(ClassMetadata *self, size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) {
// If the class is generic, we need to give it a name for Objective-C.
initGenericClassObjCName(self);
setUpGenericClassObjCName(self);

ClassROData *rodata = getROData(self);

Expand Down