Skip to content

Commit b93d636

Browse files
committed
fix: preserve dynamic property getter selectors
1 parent ea830e1 commit b93d636

6 files changed

Lines changed: 272 additions & 95 deletions

File tree

NativeScript/ffi/hermes/NativeApiJsi.mm

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -282,12 +282,41 @@ throw JSError(runtime,
282282
const NativeApiSelectorGroupEntry& entry = (*selectors)[count];
283283
auto& prepared = (*preparedInvocations)[count];
284284
Class selectorLookupClass = lookupClass;
285-
id receiver = nil;
285+
id receiver = receiverIsClass ? static_cast<id>(lookupClass) : nil;
286286
std::shared_ptr<NativeApiObjectHostObject> receiverHostObject;
287+
if (!receiverIsClass) {
288+
if (auto bound = boundReceiver.lock()) {
289+
receiverHostObject = std::move(bound);
290+
receiver = receiverHostObject->object();
291+
} else if (thisValue.isObject()) {
292+
Object receiverObject = thisValue.asObject(runtime);
293+
if (receiverObject.isHostObject<NativeApiObjectHostObject>(
294+
runtime)) {
295+
receiverHostObject =
296+
receiverObject.getHostObject<NativeApiObjectHostObject>(
297+
runtime);
298+
receiver = receiverHostObject->object();
299+
}
300+
}
301+
}
302+
if (receiver == nil) {
303+
throw JSError(runtime,
304+
"Objective-C selector requires a native receiver.");
305+
}
306+
307+
std::string selectorName;
308+
NativeApiMember adjustedMember;
309+
const NativeApiMember* selectedMember = selectorGroupMemberForCall(
310+
receiver, selectorLookupClass, receiverIsClass, entry, count,
311+
adjustedMember, selectorName);
312+
if (prepared != nullptr && prepared->selectorName != selectorName) {
313+
prepared = nullptr;
314+
}
315+
287316
if (receiverIsClass) {
288317
Class methodClass = prepared != nullptr ? prepared->receiverClass : Nil;
289318
if (methodClass == Nil) {
290-
SEL selector = sel_registerName(entry.selectorName.c_str());
319+
SEL selector = sel_registerName(selectorName.c_str());
291320
methodClass =
292321
NativeApiClassHostObject::classRespondingToClassSelector(
293322
lookupClass, selector);
@@ -299,26 +328,16 @@ throw JSError(runtime,
299328
}
300329
selectorLookupClass = methodClass;
301330
receiver = static_cast<id>(methodClass);
302-
} else if (auto bound = boundReceiver.lock()) {
303-
receiverHostObject = std::move(bound);
304-
receiver = receiverHostObject->object();
305-
} else if (thisValue.isObject()) {
306-
Object receiverObject = thisValue.asObject(runtime);
307-
if (receiverObject.isHostObject<NativeApiObjectHostObject>(
308-
runtime)) {
309-
receiverHostObject =
310-
receiverObject.getHostObject<NativeApiObjectHostObject>(
311-
runtime);
312-
receiver = receiverHostObject->object();
313-
}
314331
}
315-
if (receiver == nil) {
316-
throw JSError(runtime,
317-
"Objective-C selector requires a native receiver.");
332+
if (entry.hasMember && entry.member.property && count == 0 &&
333+
!selectorGroupCanPrepareSelector(receiver, selectorLookupClass,
334+
receiverIsClass, selectorName)) {
335+
return callObjCSelector(runtime, bridge, receiver, receiverIsClass,
336+
selectorName, selectedMember, nullptr, 0);
318337
}
319338

320339
if (!receiverIsClass) {
321-
SEL selector = sel_registerName(entry.selectorName.c_str());
340+
SEL selector = sel_registerName(selectorName.c_str());
322341
if (class_getInstanceMethod(selectorLookupClass, selector) == nullptr) {
323342
Class receiverClass = object_getClass(receiver);
324343
if (class_getInstanceMethod(receiverClass, selector) != nullptr) {
@@ -329,8 +348,8 @@ throw JSError(runtime,
329348

330349
if (prepared == nullptr) {
331350
prepared = prepareNativeApiObjCInvocation(
332-
runtime, bridge, selectorLookupClass, receiverIsClass, entry.selectorName,
333-
entry.hasMember ? &entry.member : nullptr);
351+
runtime, bridge, selectorLookupClass, receiverIsClass, selectorName,
352+
selectedMember);
334353
// Look up the engine-neutral GSD invoker for this signature.
335354
if (prepared->engineInvoker == nullptr) {
336355
uint64_t dispatchId = dispatchIdForEngineSignature(

NativeScript/ffi/jsc/NativeApiJSC.mm

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -880,12 +880,44 @@ throw JSError(runtime,
880880
(*data->selectors)[argumentCount];
881881
auto& prepared = (*data->preparedInvocations)[argumentCount];
882882
Class selectorLookupClass = data->lookupClass;
883-
id receiver = nil;
883+
id receiver = data->receiverIsClass ? static_cast<id>(data->lookupClass) : nil;
884884
std::shared_ptr<NativeApiObjectHostObject> receiverHostObject;
885+
if (!data->receiverIsClass) {
886+
if (auto boundReceiver = data->boundReceiver.lock()) {
887+
receiverHostObject = std::move(boundReceiver);
888+
receiver = receiverHostObject->object();
889+
} else if (thisObject != nullptr) {
890+
auto* holder = static_cast<engine::jscengine::HostObjectHolder*>(
891+
JSObjectGetPrivate(thisObject));
892+
if (holder != nullptr &&
893+
holder->typeToken ==
894+
engine::jscengine::hostObjectTypeToken<
895+
NativeApiObjectHostObject>()) {
896+
receiverHostObject =
897+
std::static_pointer_cast<NativeApiObjectHostObject>(
898+
holder->hostObject);
899+
receiver = receiverHostObject->object();
900+
}
901+
}
902+
}
903+
if (receiver == nil) {
904+
throw JSError(runtime,
905+
"Objective-C selector requires a native receiver.");
906+
}
907+
908+
std::string selectorName;
909+
NativeApiMember adjustedMember;
910+
const NativeApiMember* selectedMember = selectorGroupMemberForCall(
911+
receiver, selectorLookupClass, data->receiverIsClass, entry,
912+
argumentCount, adjustedMember, selectorName);
913+
if (prepared != nullptr && prepared->selectorName != selectorName) {
914+
prepared = nullptr;
915+
}
916+
885917
if (data->receiverIsClass) {
886918
Class methodClass = prepared != nullptr ? prepared->receiverClass : Nil;
887919
if (methodClass == Nil) {
888-
SEL selector = sel_registerName(entry.selectorName.c_str());
920+
SEL selector = sel_registerName(selectorName.c_str());
889921
methodClass =
890922
NativeApiClassHostObject::classRespondingToClassSelector(
891923
data->lookupClass, selector);
@@ -897,29 +929,18 @@ throw JSError(runtime,
897929
}
898930
selectorLookupClass = methodClass;
899931
receiver = static_cast<id>(methodClass);
900-
} else if (auto boundReceiver = data->boundReceiver.lock()) {
901-
receiverHostObject = std::move(boundReceiver);
902-
receiver = receiverHostObject->object();
903-
} else if (thisObject != nullptr) {
904-
auto* holder = static_cast<engine::jscengine::HostObjectHolder*>(
905-
JSObjectGetPrivate(thisObject));
906-
if (holder != nullptr &&
907-
holder->typeToken ==
908-
engine::jscengine::hostObjectTypeToken<
909-
NativeApiObjectHostObject>()) {
910-
receiverHostObject =
911-
std::static_pointer_cast<NativeApiObjectHostObject>(
912-
holder->hostObject);
913-
receiver = receiverHostObject->object();
914-
}
915932
}
916-
if (receiver == nil) {
917-
throw JSError(runtime,
918-
"Objective-C selector requires a native receiver.");
933+
if (entry.hasMember && entry.member.property && argumentCount == 0 &&
934+
!selectorGroupCanPrepareSelector(receiver, selectorLookupClass,
935+
data->receiverIsClass, selectorName)) {
936+
return callObjCSelector(runtime, data->bridge, receiver,
937+
data->receiverIsClass, selectorName,
938+
selectedMember, nullptr, 0)
939+
.local(runtime);
919940
}
920941

921942
if (!data->receiverIsClass) {
922-
SEL selector = sel_registerName(entry.selectorName.c_str());
943+
SEL selector = sel_registerName(selectorName.c_str());
923944
if (class_getInstanceMethod(selectorLookupClass, selector) == nullptr) {
924945
Class receiverClass = object_getClass(receiver);
925946
if (class_getInstanceMethod(receiverClass, selector) != nullptr) {
@@ -931,7 +952,7 @@ throw JSError(runtime,
931952
if (prepared == nullptr) {
932953
prepared = prepareNativeApiObjCInvocation(
933954
runtime, data->bridge, selectorLookupClass, data->receiverIsClass,
934-
entry.selectorName, entry.hasMember ? &entry.member : nullptr);
955+
selectorName, selectedMember);
935956
// Look up the engine-neutral GSD invoker for this signature.
936957
if (prepared->engineInvoker == nullptr) {
937958
uint64_t dispatchId = dispatchIdForEngineSignature(

NativeScript/ffi/quickjs/NativeApiQuickJS.mm

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -990,12 +990,38 @@ throw JSError(runtime,
990990
const NativeApiSelectorGroupEntry& entry = (*data->selectors)[count];
991991
auto& prepared = (*data->preparedInvocations)[count];
992992
Class selectorLookupClass = data->lookupClass;
993-
id receiver = nil;
993+
id receiver = data->receiverIsClass ? static_cast<id>(data->lookupClass) : nil;
994994
std::shared_ptr<NativeApiObjectHostObject> receiverHostObject;
995+
if (!data->receiverIsClass) {
996+
if (auto boundReceiver = data->boundReceiver.lock()) {
997+
receiverHostObject = std::move(boundReceiver);
998+
receiver = receiverHostObject->object();
999+
} else {
1000+
receiverHostObject =
1001+
quickJSHostObject<NativeApiObjectHostObject>(runtime, thisValue);
1002+
if (receiverHostObject != nullptr) {
1003+
receiver = receiverHostObject->object();
1004+
}
1005+
}
1006+
}
1007+
if (receiver == nil) {
1008+
throw JSError(runtime,
1009+
"Objective-C selector requires a native receiver.");
1010+
}
1011+
1012+
std::string selectorName;
1013+
NativeApiMember adjustedMember;
1014+
const NativeApiMember* selectedMember = selectorGroupMemberForCall(
1015+
receiver, selectorLookupClass, data->receiverIsClass, entry, count,
1016+
adjustedMember, selectorName);
1017+
if (prepared != nullptr && prepared->selectorName != selectorName) {
1018+
prepared = nullptr;
1019+
}
1020+
9951021
if (data->receiverIsClass) {
9961022
Class methodClass = prepared != nullptr ? prepared->receiverClass : Nil;
9971023
if (methodClass == Nil) {
998-
SEL selector = sel_registerName(entry.selectorName.c_str());
1024+
SEL selector = sel_registerName(selectorName.c_str());
9991025
methodClass =
10001026
NativeApiClassHostObject::classRespondingToClassSelector(
10011027
data->lookupClass, selector);
@@ -1007,23 +1033,18 @@ throw JSError(runtime,
10071033
}
10081034
selectorLookupClass = methodClass;
10091035
receiver = static_cast<id>(methodClass);
1010-
} else if (auto boundReceiver = data->boundReceiver.lock()) {
1011-
receiverHostObject = std::move(boundReceiver);
1012-
receiver = receiverHostObject->object();
1013-
} else {
1014-
receiverHostObject =
1015-
quickJSHostObject<NativeApiObjectHostObject>(runtime, thisValue);
1016-
if (receiverHostObject != nullptr) {
1017-
receiver = receiverHostObject->object();
1018-
}
10191036
}
1020-
if (receiver == nil) {
1021-
throw JSError(runtime,
1022-
"Objective-C selector requires a native receiver.");
1037+
if (entry.hasMember && entry.member.property && count == 0 &&
1038+
!selectorGroupCanPrepareSelector(receiver, selectorLookupClass,
1039+
data->receiverIsClass, selectorName)) {
1040+
return callObjCSelector(runtime, data->bridge, receiver,
1041+
data->receiverIsClass, selectorName,
1042+
selectedMember, nullptr, 0)
1043+
.local(runtime);
10231044
}
10241045

10251046
if (!data->receiverIsClass) {
1026-
SEL selector = sel_registerName(entry.selectorName.c_str());
1047+
SEL selector = sel_registerName(selectorName.c_str());
10271048
if (class_getInstanceMethod(selectorLookupClass, selector) == nullptr) {
10281049
Class receiverClass = object_getClass(receiver);
10291050
if (class_getInstanceMethod(receiverClass, selector) != nullptr) {
@@ -1035,7 +1056,7 @@ throw JSError(runtime,
10351056
if (prepared == nullptr) {
10361057
prepared = prepareNativeApiObjCInvocation(
10371058
runtime, data->bridge, selectorLookupClass, data->receiverIsClass,
1038-
entry.selectorName, entry.hasMember ? &entry.member : nullptr);
1059+
selectorName, selectedMember);
10391060
// Look up the engine-neutral GSD invoker for this signature.
10401061
if (prepared->engineInvoker == nullptr) {
10411062
uint64_t dispatchId = dispatchIdForEngineSignature(

NativeScript/ffi/shared/bridge/HostObjects.mm

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,24 +1293,14 @@ throw JSError(runtime,
12931293
const auto& members = bridge_->membersForClass(*symbol);
12941294
if (const NativeApiMember* propertyMember =
12951295
selectPropertyMember(members, property, false)) {
1296-
SEL selector = sel_getUid(propertyMember->selectorName.c_str());
1297-
if ([object_ respondsToSelector:selector]) {
1296+
if (auto getter = respondingPropertyGetterSelector(
1297+
object_, property, propertyMember->selectorName)) {
1298+
NativeApiMember getterMember = *propertyMember;
1299+
getterMember.selectorName = *getter;
12981300
bridge_->cachePropertyGetter(object_getClass(object_), property,
1299-
propertyMember,
1300-
propertyMember->selectorName);
1301-
return callObjectSelector(runtime, propertyMember->selectorName,
1302-
propertyMember, nullptr, 0);
1303-
}
1304-
std::string booleanSelectorName =
1305-
booleanGetterSelectorForProperty(property);
1306-
if (booleanSelectorName != propertyMember->selectorName) {
1307-
SEL booleanSelector = sel_getUid(booleanSelectorName.c_str());
1308-
if ([object_ respondsToSelector:booleanSelector]) {
1309-
NativeApiMember getterMember = *propertyMember;
1310-
getterMember.selectorName = booleanSelectorName;
1311-
return callObjectSelector(runtime, getterMember.selectorName,
1312-
&getterMember, nullptr, 0);
1313-
}
1301+
propertyMember, getterMember.selectorName);
1302+
return callObjectSelector(runtime, getterMember.selectorName,
1303+
&getterMember, nullptr, 0);
13141304
}
13151305
}
13161306

@@ -1370,7 +1360,10 @@ throw JSError(runtime,
13701360
getter = customGetter;
13711361
free(customGetter);
13721362
}
1373-
return callObjectSelector(runtime, getter, nullptr, nullptr, 0);
1363+
if (auto selector =
1364+
respondingPropertyGetterSelector(object_, property, getter)) {
1365+
return callObjectSelector(runtime, *selector, nullptr, nullptr, 0);
1366+
}
13741367
}
13751368
}
13761369

@@ -2154,8 +2147,14 @@ Value makeProtocolPropertyGetter(Runtime& runtime, NativeApiMember member,
21542147
throw JSError(
21552148
runtime, "Protocol property requires a native receiver.");
21562149
}
2150+
NativeApiMember getterMember = member;
2151+
if (auto selector = respondingPropertyGetterSelector(
2152+
receiver, member.name, member.selectorName)) {
2153+
getterMember.selectorName = *selector;
2154+
}
21572155
return callObjCSelector(runtime, bridge, receiver, receiverIsClass,
2158-
member.selectorName, &member, nullptr, 0);
2156+
getterMember.selectorName, &getterMember,
2157+
nullptr, 0);
21592158
});
21602159
}
21612160

0 commit comments

Comments
 (0)