Skip to content

Commit c83e8fa

Browse files
authored
Merge pull request #1253 from NativeScript/bektchiev/fix-md-for-nested-swift-classes
fix: Register Swift classes with both native names
2 parents 5ce8fca + 0887c11 commit c83e8fa

8 files changed

Lines changed: 79 additions & 19 deletions

File tree

src/NativeScript/JSErrors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#define NS_EXCEPTION_SCOPE_ZERO_RECURSION_KEY @"__nsExceptionScopeZeroRecursion"
1818

19+
#define NS_THROW(msg) @throw [NSException exceptionWithName:NSGenericException reason:msg userInfo:nil];
20+
1921
#define NS_TRY @try
2022

2123
#define NS_CATCH_THROW_TO_JS(execState) \

src/NativeScript/Metadata/Metadata.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ inline UInt8 getMinorVersion(UInt8 encodedVersion) {
6363

6464
// Bit indices in flags section
6565
enum MetaFlags {
66+
HasDemangledName = 8,
6667
HasName = 7,
6768
// IsIosAppExtensionAvailable = 6, the flag exists in metadata generator but we never use it in the runtime
6869
FunctionReturnsUnmanaged = 3,
@@ -319,7 +320,7 @@ struct GlobalTable {
319320
return buckets.sizeInBytes();
320321
}
321322

322-
static const char* getName(const Meta& meta);
323+
static bool compareName(const Meta& meta, const char* identifierString, size_t length);
323324
};
324325

325326
struct ModuleTable {
@@ -546,22 +547,28 @@ struct LibraryMeta {
546547
}
547548
};
548549

549-
struct JsNameAndName {
550-
String jsName;
551-
String name;
550+
enum NameIndex {
551+
JsName,
552+
Name,
553+
DemangledName,
554+
NameIndexCount,
555+
};
556+
557+
struct JsNameAndNativeNames {
558+
String strings[NameIndexCount];
552559
};
553560

554561
union MetaNames {
555562
String name;
556-
PtrTo<JsNameAndName> names;
563+
PtrTo<JsNameAndNativeNames> names;
557564
};
558565

559566
struct Meta {
560567

561568
private:
562569
MetaNames _names;
563570
PtrTo<ModuleMeta> _topLevelModule;
564-
UInt8 _flags;
571+
UInt16 _flags;
565572
UInt8 _introduced;
566573

567574
public:
@@ -577,16 +584,24 @@ struct Meta {
577584
return this->flag(MetaFlags::HasName);
578585
}
579586

587+
bool hasDemangledName() const {
588+
return this->flag(MetaFlags::HasDemangledName);
589+
}
590+
580591
bool flag(int index) const {
581592
return (this->_flags & (1 << index)) > 0;
582593
}
583594

584595
const char* jsName() const {
585-
return (this->hasName()) ? this->_names.names->jsName.valuePtr() : this->_names.name.valuePtr();
596+
return this->getNameByIndex(JsName);
586597
}
587598

588599
const char* name() const {
589-
return (this->hasName()) ? this->_names.names->name.valuePtr() : this->_names.name.valuePtr();
600+
return this->getNameByIndex(Name);
601+
}
602+
603+
const char* demangledName() const {
604+
return this->getNameByIndex(DemangledName);
590605
}
591606

592607
/**
@@ -605,6 +620,24 @@ struct Meta {
605620
* > have been introduced in this or prior version;
606621
*/
607622
bool isAvailable() const;
623+
624+
private:
625+
const char* getNameByIndex(enum NameIndex index) const {
626+
int i = index;
627+
if (!this->hasName() && !this->hasDemangledName()) {
628+
return this->_names.name.valuePtr();
629+
}
630+
631+
if (!this->hasDemangledName() && i >= DemangledName) {
632+
i--;
633+
}
634+
635+
if (!this->hasName() && i >= Name) {
636+
i--;
637+
}
638+
639+
return this->_names.names.value().strings[i].valuePtr();
640+
}
608641
};
609642

610643
struct RecordMeta : Meta {

src/NativeScript/Metadata/MetadataInlines.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,21 @@ const Meta* GlobalTable<TYPE>::findMeta(const char* identifierString, size_t len
101101
const ArrayOfPtrTo<Meta>& bucketContent = buckets[bucketIndex].value();
102102
for (ArrayOfPtrTo<Meta>::iterator it = bucketContent.begin(); it != bucketContent.end(); it++) {
103103
const Meta* meta = (*it).valuePtr();
104-
const char* name = getName(*meta);
105-
if (compareIdentifiers(name, identifierString, length) == 0) {
104+
if (this->compareName(*meta, identifierString, length)) {
106105
return onlyIfAvailable ? (meta->isAvailable() ? meta : nullptr) : meta;
107106
}
108107
}
109108
return nullptr;
110109
}
111110

112-
template <GlobalTableType TYPE>
113-
inline const char* GlobalTable<TYPE>::getName(const Meta& meta) {
114-
return TYPE == GlobalTableType::ByJsName ? meta.jsName() : meta.name();
111+
template <>
112+
inline bool GlobalTable<ByJsName>::compareName(const Meta& meta, const char* identifierString, size_t length) {
113+
return compareIdentifiers(meta.jsName(), identifierString, length) == 0;
114+
}
115+
116+
template <>
117+
inline bool GlobalTable<ByNativeName>::compareName(const Meta& meta, const char* identifierString, size_t length) {
118+
return compareIdentifiers(meta.name(), identifierString, length) == 0 || (meta.hasDemangledName() && compareIdentifiers(meta.demangledName(), identifierString, length) == 0);
115119
}
116120

117121
// GlobalTable::iterator

src/NativeScript/TypeFactory.mm

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@
101101

102102
const StructMeta* structInfo = static_cast<const StructMeta*>(MetaFile::instance()->globalTableJs()->findMeta(structName.impl()));
103103
if (!structInfo) {
104-
@throw [NSException exceptionWithName:NSGenericException reason:[NSString stringWithFormat:@"Struct \"%s\" is missing from metadata. It may have been blacklisted.", structName.utf8().data()] userInfo:nil];
104+
NSString* errorMsg = [NSString stringWithFormat:@"Struct \"%s\" is missing from metadata. It may have been blacklisted.", structName.utf8().data()];
105+
NS_THROW(errorMsg);
105106
}
106107

107108
ffi_type* ffiType = new ffi_type({ .size = 0,
@@ -277,7 +278,7 @@
277278

278279
if (!klass || !metadata) {
279280
if (strcmp(metadata->name(), "NSObject") == 0) {
280-
@throw [NSException exceptionWithName:NSGenericException reason:@"fatal error: NativeScript cannot create constructor for NSObject." userInfo:nil];
281+
NS_THROW(@"fatal error: NativeScript cannot create constructor for NSObject.");
281282
}
282283
#ifdef DEBUG
283284
NSLog(@"** Can not create constructor for \"%s\". Casting it to \"NSObject\". **", metadata->name());
@@ -478,9 +479,8 @@
478479
if (Class klass = objc_getClass(declarationName.utf8().data())) {
479480
result = globalObject->constructorFor(klass, additionalProtocols);
480481
} else {
481-
auto scope = DECLARE_THROW_SCOPE(execState->vm());
482-
WTF::String message = makeString("Class \"", declarationName, "\" referenced by type encoding not found at runtime.");
483-
throwException(execState, scope, JSC::createError(execState, message, defaultSourceAppender));
482+
auto errorMsg = [NSString stringWithFormat:@"Class \"%s\" referenced by type encoding not found at runtime.", declarationName.utf8().data()];
483+
NS_THROW(errorMsg);
484484
}
485485

486486
break;

src/metadata-generator

Submodule metadata-generator updated 127 files

tests/TestFixtures/Interfaces/TNSSwiftLike.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ __attribute__((objc_runtime_name("_TtC17NativeScriptTests12TNSSwiftLike")))
1313

1414
@end
1515

16+
__attribute__((objc_runtime_name("_TtCC17NativeScriptTests12TNSSwiftLike5Inner")))
17+
@interface TNSSwiftLikeInner : NSObject
18+
19+
@end
20+
1621
@interface TNSSwiftLikeFactory : NSObject
1722
+ (TNSSwiftLike*)create;
23+
+ (TNSSwiftLikeInner*)createInner;
1824
@end
1925

2026
NS_ASSUME_NONNULL_END

tests/TestFixtures/Interfaces/TNSSwiftLike.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ @implementation TNSSwiftLike
1111

1212
@end
1313

14+
@implementation TNSSwiftLikeInner
15+
16+
@end
17+
1418
@implementation TNSSwiftLikeFactory
1519
+ (TNSSwiftLike*)create {
1620
return [TNSSwiftLike new];
1721
}
22+
23+
+ (TNSSwiftLikeInner*)createInner {
24+
return [TNSSwiftLikeInner new];
25+
}
1826
@end

tests/TestRunner/app/MetadataTests.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,11 @@ describe("Metadata", function () {
1212
expect(swiftLikeObj.constructor.name).toBe("NativeScriptTests.TNSSwiftLike");
1313
expect(NSString.stringWithUTF8String(class_getName(swiftLikeObj.constructor)).toString()).toBe("NativeScriptTests.TNSSwiftLike");
1414
});
15+
16+
it("Objects from nested Swift classes should be marshalled correctly", function () {
17+
const swiftLikeInnerObj = TNSSwiftLikeFactory.createInner();
18+
expect(swiftLikeInnerObj.constructor).toBe(global.TNSSwiftLikeInner);
19+
expect(swiftLikeInnerObj.constructor.name).toBe("_TtCC17NativeScriptTests12TNSSwiftLike5Inner");
20+
expect(NSString.stringWithUTF8String(class_getName(swiftLikeInnerObj.constructor)).toString(), "_TtCC17NativeScriptTests12TNSSwiftLike5Inner");
21+
});
1522
});

0 commit comments

Comments
 (0)