Skip to content

Commit 6d93051

Browse files
committed
perf: tighten selector dispatch target resolution
1 parent ce91a94 commit 6d93051

6 files changed

Lines changed: 60 additions & 15 deletions

File tree

NativeScript/ffi/hermes/NativeApiJsi.mm

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,13 +341,26 @@ throw JSError(runtime,
341341
"Objective-C selector requires a native receiver.");
342342
}
343343

344-
NativeApiSelectorGroupCallTarget callTarget = selectorGroupMemberForCall(
345-
receiver, selectorLookupClass, receiverIsClass, entry, count);
346-
const std::string& selectorName = *callTarget.selectorName;
347-
const NativeApiMember* selectedMember = callTarget.member;
348-
if (prepared != nullptr && prepared->selectorName != selectorName) {
349-
prepared = nullptr;
344+
const bool propertyGetterCall =
345+
entry.hasMember && entry.member.property && count == 0;
346+
const std::string* selectorNamePtr = &entry.selectorName;
347+
const NativeApiMember* selectedMember =
348+
entry.hasMember ? &entry.member : nullptr;
349+
bool callTargetCanPrepare = true;
350+
if (prepared == nullptr || propertyGetterCall) {
351+
NativeApiSelectorGroupCallTarget callTarget =
352+
selectorGroupCallTargetForEntry(receiver, selectorLookupClass,
353+
receiverIsClass, entry, count);
354+
selectorNamePtr = callTarget.selectorName;
355+
selectedMember = callTarget.member;
356+
callTargetCanPrepare = callTarget.canPrepare;
357+
if (prepared != nullptr && prepared->selectorName != *selectorNamePtr) {
358+
prepared = nullptr;
359+
}
350360
}
361+
const std::string& selectorName =
362+
prepared != nullptr && !propertyGetterCall ? prepared->selectorName
363+
: *selectorNamePtr;
351364

352365
if (receiverIsClass) {
353366
Class methodClass = prepared != nullptr ? prepared->receiverClass : Nil;
@@ -365,8 +378,7 @@ throw JSError(runtime,
365378
selectorLookupClass = methodClass;
366379
receiver = static_cast<id>(methodClass);
367380
}
368-
if (entry.hasMember && entry.member.property && count == 0 &&
369-
!callTarget.canPrepare) {
381+
if (propertyGetterCall && !callTargetCanPrepare) {
370382
return callObjCSelector(runtime, bridge, receiver, receiverIsClass,
371383
selectorName, selectedMember, nullptr, 0);
372384
}

NativeScript/ffi/jsc/NativeApiJSC.mm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,9 +1110,10 @@ throw JSError(runtime,
11101110
entry.hasMember ? &entry.member : nullptr;
11111111
bool callTargetCanPrepare = true;
11121112
if (prepared == nullptr || propertyGetterCall) {
1113-
NativeApiSelectorGroupCallTarget callTarget = selectorGroupMemberForCall(
1114-
receiver, selectorLookupClass, data->receiverIsClass, entry,
1115-
argumentCount);
1113+
NativeApiSelectorGroupCallTarget callTarget =
1114+
selectorGroupCallTargetForEntry(receiver, selectorLookupClass,
1115+
data->receiverIsClass, entry,
1116+
argumentCount);
11161117
selectorNamePtr = callTarget.selectorName;
11171118
selectedMember = callTarget.member;
11181119
callTargetCanPrepare = callTarget.canPrepare;

NativeScript/ffi/quickjs/NativeApiQuickJS.mm

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,8 +1212,9 @@ throw JSError(runtime,
12121212
entry.hasMember ? &entry.member : nullptr;
12131213
bool callTargetCanPrepare = true;
12141214
if (prepared == nullptr || propertyGetterCall) {
1215-
NativeApiSelectorGroupCallTarget callTarget = selectorGroupMemberForCall(
1216-
receiver, selectorLookupClass, data->receiverIsClass, entry, count);
1215+
NativeApiSelectorGroupCallTarget callTarget =
1216+
selectorGroupCallTargetForEntry(receiver, selectorLookupClass,
1217+
data->receiverIsClass, entry, count);
12171218
selectorNamePtr = callTarget.selectorName;
12181219
selectedMember = callTarget.member;
12191220
callTargetCanPrepare = callTarget.canPrepare;

NativeScript/ffi/shared/bridge/ObjCBridge.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,16 @@ NativeApiSelectorGroupCallTarget selectorGroupMemberForCall(
506506
return {&entry.selectorName, &entry.member, true};
507507
}
508508

509+
inline NativeApiSelectorGroupCallTarget selectorGroupCallTargetForEntry(
510+
id receiver, Class lookupClass, bool receiverIsClass,
511+
NativeApiSelectorGroupEntry& entry, size_t count) {
512+
if (entry.hasMember && (!entry.member.property || count != 0)) {
513+
return {&entry.selectorName, &entry.member, true};
514+
}
515+
return selectorGroupMemberForCall(receiver, lookupClass, receiverIsClass,
516+
entry, count);
517+
}
518+
509519
const NativeApiMember* selectPropertyMember(
510520
const std::vector<NativeApiMember>& members, const std::string& property,
511521
bool staticMethod) {

NativeScript/ffi/v8/NativeApiV8.mm

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,8 +1234,9 @@ throw JSError(runtime,
12341234
entry.hasMember ? &entry.member : nullptr;
12351235
bool callTargetCanPrepare = true;
12361236
if (prepared == nullptr || propertyGetterCall) {
1237-
NativeApiSelectorGroupCallTarget callTarget = selectorGroupMemberForCall(
1238-
receiver, selectorLookupClass, data->receiverIsClass, entry, count);
1237+
NativeApiSelectorGroupCallTarget callTarget =
1238+
selectorGroupCallTargetForEntry(receiver, selectorLookupClass,
1239+
data->receiverIsClass, entry, count);
12391240
selectorNamePtr = callTarget.selectorName;
12401241
selectedMember = callTarget.member;
12411242
callTargetCanPrepare = callTarget.canPrepare;

benchmarks/objc-dispatch/objc-dispatch-benchmarks.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,26 @@
109109
return i;
110110
});
111111

112+
if (globalThis.performance && typeof globalThis.performance.now === "function") {
113+
var performanceNow = globalThis.performance.now;
114+
function NativePrototypeCall() {}
115+
NativePrototypeCall.prototype.nativeCall = performanceNow;
116+
var nativePrototypeCall = new NativePrototypeCall();
117+
118+
addCase(cases, "js.nativeFunction.performance.now", 1, function () {
119+
return performanceNow();
120+
});
121+
122+
addCase(
123+
cases,
124+
"js.prototype.nativeFunction.performance.now",
125+
1,
126+
function () {
127+
return nativePrototypeCall.nativeCall();
128+
}
129+
);
130+
}
131+
112132
addCase(cases, "NSObject.respondsToSelector", 1, function () {
113133
return object.respondsToSelector("description");
114134
});

0 commit comments

Comments
 (0)