Skip to content

Commit fd62be5

Browse files
committed
stdlib: Use the re-mangler for _typeByName
The old method of constructing a mangled class name does not work anymore with the new mangling scheme. Also, by using the re-mangler, _typeByName now works with class names containing non-ascii characters.
1 parent 5bb69bd commit fd62be5

File tree

3 files changed

+40
-31
lines changed

3 files changed

+40
-31
lines changed

stdlib/public/core/Misc.swift

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ func _typeName(_ type: Any.Type, qualified: Bool = true) -> String {
8484
input: UnsafeBufferPointer(start: stringPtr, count: count))
8585
}
8686

87-
@_silgen_name("swift_getTypeByMangledName")
88-
func _getTypeByMangledName(
87+
@_silgen_name("swift_getTypeByName")
88+
func _getTypeByName(
8989
_ name: UnsafePointer<UInt8>,
9090
_ nameLength: UInt)
9191
-> Any.Type?
@@ -94,26 +94,10 @@ func _getTypeByMangledName(
9494
/// names is stabilized, this is limited to top-level class names (Foo.bar).
9595
public // SPI(Foundation)
9696
func _typeByName(_ name: String) -> Any.Type? {
97-
let components = name.characters.split{$0 == "."}.map(String.init)
98-
guard components.count == 2 else {
99-
return nil
100-
}
101-
102-
// Note: explicitly build a class name to match on, rather than matching
103-
// on the result of _typeName(), to ensure the type we are resolving is
104-
// actually a class.
105-
var name = "C"
106-
if components[0] == "Swift" {
107-
name += "s"
108-
} else {
109-
name += String(components[0].characters.count) + components[0]
110-
}
111-
name += String(components[1].characters.count) + components[1]
112-
11397
let nameUTF8 = Array(name.utf8)
11498
return nameUTF8.withUnsafeBufferPointer { (nameUTF8) in
115-
let type = _getTypeByMangledName(nameUTF8.baseAddress!,
116-
UInt(nameUTF8.endIndex))
99+
let type = _getTypeByName(nameUTF8.baseAddress!,
100+
UInt(nameUTF8.endIndex))
117101

118102
return type
119103
}

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/Basic/LLVM.h"
1818
#include "swift/Basic/Lazy.h"
19+
#include "swift/Basic/Demangle.h"
1920
#include "swift/Runtime/Concurrent.h"
2021
#include "swift/Runtime/HeapObject.h"
2122
#include "swift/Runtime/Metadata.h"
@@ -189,27 +190,46 @@ _searchTypeMetadataRecords(const TypeMetadataState &T,
189190
}
190191

191192
static const Metadata *
192-
_typeByMangledName(const llvm::StringRef typeName) {
193+
_classByName(const llvm::StringRef typeName) {
194+
195+
size_t DotPos = typeName.find('.');
196+
if (DotPos == llvm::StringRef::npos)
197+
return nullptr;
198+
if (typeName.find('.', DotPos + 1) != llvm::StringRef::npos)
199+
return nullptr;
200+
201+
using namespace Demangle;
202+
203+
NodePointer ClassNd = NodeFactory::create(Node::Kind::Class);
204+
NodePointer ModuleNd = NodeFactory::create(Node::Kind::Module,
205+
typeName.substr(0, DotPos));
206+
NodePointer NameNd = NodeFactory::create(Node::Kind::Module,
207+
typeName.substr(DotPos + 1));
208+
ClassNd->addChildren(ModuleNd, NameNd);
209+
210+
std::string Mangled = mangleNode(ClassNd);
211+
StringRef MangledName = Mangled;
212+
193213
const Metadata *foundMetadata = nullptr;
194214
auto &T = TypeMetadataRecords.get();
195215

196216
// Look for an existing entry.
197217
// Find the bucket for the metadata entry.
198-
if (auto Value = T.Cache.find(typeName))
218+
if (auto Value = T.Cache.find(MangledName))
199219
return Value->getMetadata();
200220

201221
// Check type metadata records
202222
T.SectionsToScanLock.withLock([&] {
203-
foundMetadata = _searchTypeMetadataRecords(T, typeName);
223+
foundMetadata = _searchTypeMetadataRecords(T, MangledName);
204224
});
205225

206226
// Check protocol conformances table. Note that this has no support for
207227
// resolving generic types yet.
208228
if (!foundMetadata)
209-
foundMetadata = _searchConformancesByMangledTypeName(typeName);
229+
foundMetadata = _searchConformancesByMangledTypeName(MangledName);
210230

211231
if (foundMetadata) {
212-
T.Cache.getOrInsert(typeName, foundMetadata);
232+
T.Cache.getOrInsert(MangledName, foundMetadata);
213233
}
214234

215235
#if SWIFT_OBJC_INTEROP
@@ -226,13 +246,16 @@ _typeByMangledName(const llvm::StringRef typeName) {
226246
return foundMetadata;
227247
}
228248

229-
/// Return the type metadata for a given mangled name, used in the
230-
/// implementation of _typeByName(). The human readable name returned
231-
/// by swift_getTypeName() is non-unique, so we used mangled names
232-
/// internally.
249+
/// Return the type metadata for a given name, used in the
250+
/// implementation of _typeByName().
251+
///
252+
/// Currently only top-level classes are supported.
253+
254+
/// \param typeName The name of a class in the form: <module>.<class>
255+
/// \return Returns the metadata of the type, if found.
233256
SWIFT_RUNTIME_EXPORT
234257
const Metadata *
235-
swift_getTypeByMangledName(const char *typeName, size_t typeNameLength) {
258+
swift_getTypeByName(const char *typeName, size_t typeNameLength) {
236259
llvm::StringRef name(typeName, typeNameLength);
237-
return _typeByMangledName(name);
260+
return _classByName(name);
238261
}

test/stdlib/Runtime.swift.gyb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,14 @@ class SomeSubclass : SomeClass {}
349349
protocol SomeProtocol {}
350350
class SomeConformingClass : SomeProtocol {}
351351
class SomeConformingSubclass : SomeConformingClass {}
352+
class UnicodeCläss {}
352353

353354
Runtime.test("typeByName") {
354355
expectTrue(_typeByName("a.SomeClass") == SomeClass.self)
355356
expectTrue(_typeByName("a.SomeSubclass") == SomeSubclass.self)
356357
// name lookup will be via protocol conformance table
357358
expectTrue(_typeByName("a.SomeConformingClass") == SomeConformingClass.self)
359+
expectTrue(_typeByName("a.UnicodeCläss") == UnicodeCläss.self)
358360
}
359361

360362
Runtime.test("demangleName") {

0 commit comments

Comments
 (0)