@@ -91,6 +91,8 @@ void SetNativeApiObjectPrototype(Runtime& runtime, Object& object,
9191
9292#include " NativeApiJsiGsd.mm"
9393
94+ #include " ../shared/bridge/SelectorGroupCall.h"
95+
9496
9597void * lookupGeneratedEngineObjCGsdInvoker (uint64_t dispatchId) {
9698 return reinterpret_cast <void *>(lookupObjCGsdInvoker (dispatchId));
@@ -123,207 +125,84 @@ Function CreateNativeApiSelectorGroupFunctionImpl(
123125 std::shared_ptr<
124126 std::vector<std::shared_ptr<NativeApiPreparedObjCInvocation>>>
125127 preparedInvocations,
126- std::weak_ptr<NativeApiObjectHostObject> boundReceiver = {},
127- std::shared_ptr<NativeApiObjectLifetimeState> boundReceiverState =
128- nullptr ) {
128+ std::weak_ptr<NativeApiObjectHostObject> boundReceiver,
129+ std::shared_ptr<NativeApiObjectLifetimeState> boundReceiverState) {
130+ NativeApiSelectorGroupState state (
131+ std::move (bridge), lookupClass, receiverIsClass, std::move (selectors),
132+ std::move (preparedInvocations), std::move (boundReceiver),
133+ std::move (boundReceiverState));
129134 return Function::createFromHostFunction (
130135 runtime, PropNameID::forAscii (runtime, " __nativeSelectorGroup" ), 0 ,
131- [bridge = std::move (bridge), lookupClass, receiverIsClass,
132- selectors = std::move (selectors),
133- preparedInvocations = std::move (preparedInvocations),
134- boundReceiver = std::move (boundReceiver),
135- boundReceiverState = std::move (boundReceiverState),
136- cachedReceiverClass = Class (Nil ),
137- cachedDispatchClass = Class (Nil )](
136+ [state = std::move (state)](
138137 Runtime& runtime, const Value& thisValue, const Value* args,
139138 size_t count) mutable -> Value {
140- NativeApiRoundTripCacheFrameGuard roundTripFrame (bridge);
141- if (count >= selectors->size () ||
142- (*selectors)[count].selectorName .empty ()) {
143- throw JSError (runtime,
144- " Objective-C selector is not available for the provided "
145- " arguments count." );
146- }
147-
148- NativeApiSelectorGroupEntry& entry = (*selectors)[count];
149- auto & prepared = (*preparedInvocations)[count];
150- Class selectorLookupClass = lookupClass;
151- id receiver = receiverIsClass ? static_cast <id >(lookupClass) : nil ;
139+ NativeApiRoundTripCacheFrameGuard roundTripFrame (state.bridge );
152140 std::shared_ptr<NativeApiObjectHostObject> receiverHostObject;
153- if (!receiverIsClass) {
154- if (boundReceiverState != nullptr ) {
155- receiver = boundReceiverState->object ();
156- if (receiver == nil ) {
157- throw JSError (runtime,
158- " Objective-C selector requires a native receiver." );
159- }
141+ auto resolveReceiverHost = [&]() {
142+ if (receiverHostObject) {
143+ return receiverHostObject;
144+ }
145+ if (state.boundReceiverState != nullptr ) {
146+ receiverHostObject = state.boundReceiver .lock ();
160147 } else if (thisValue.isObject ()) {
161148 Object receiverObject = thisValue.asObject (runtime);
162149 if (receiverObject.isHostObject <NativeApiObjectHostObject>(
163150 runtime)) {
164151 receiverHostObject =
165152 receiverObject.getHostObject <NativeApiObjectHostObject>(
166153 runtime);
167- receiver = receiverHostObject->object ();
168- }
169- }
170- }
171- if (receiver == nil ) {
172- throw JSError (runtime,
173- " Objective-C selector requires a native receiver." );
174- }
175-
176- const bool propertyGetterCall =
177- entry.hasMember && entry.member .property && count == 0 ;
178- const std::string* selectorNamePtr = &entry.selectorName ;
179- const NativeApiMember* selectedMember =
180- entry.hasMember ? &entry.member : nullptr ;
181- bool callTargetCanPrepare = true ;
182- if (prepared == nullptr || propertyGetterCall) {
183- NativeApiSelectorGroupCallTarget callTarget =
184- selectorGroupCallTargetForEntry (receiver, selectorLookupClass,
185- receiverIsClass, entry, count);
186- selectorNamePtr = callTarget.selectorName ;
187- selectedMember = callTarget.member ;
188- callTargetCanPrepare = callTarget.canPrepare ;
189- if (prepared != nullptr && prepared->selectorName != *selectorNamePtr) {
190- prepared = nullptr ;
191- }
192- }
193- const std::string& selectorName =
194- prepared != nullptr && !propertyGetterCall ? prepared->selectorName
195- : *selectorNamePtr;
196-
197- if (receiverIsClass) {
198- Class methodClass = prepared != nullptr ? prepared->receiverClass : Nil ;
199- if (methodClass == Nil ) {
200- SEL selector = sel_registerName (selectorName.c_str ());
201- methodClass =
202- NativeApiClassHostObject::classRespondingToClassSelector (
203- lookupClass, selector);
204- }
205- if (methodClass == Nil ) {
206- throw JSError (runtime,
207- " Objective-C selector is not available: " +
208- entry.selectorName );
209- }
210- selectorLookupClass = methodClass;
211- receiver = static_cast <id >(methodClass);
212- }
213- if (propertyGetterCall && !callTargetCanPrepare) {
214- return callObjCSelector (runtime, bridge, receiver, receiverIsClass,
215- selectorName, selectedMember, nullptr , 0 );
216- }
217-
218- if (prepared == nullptr ) {
219- if (!receiverIsClass) {
220- SEL selector = sel_registerName (selectorName.c_str ());
221- if (class_getInstanceMethod (selectorLookupClass, selector) == nullptr ) {
222- Class receiverClass = object_getClass (receiver);
223- if (class_getInstanceMethod (receiverClass, selector) != nullptr ) {
224- selectorLookupClass = receiverClass;
225- }
226- }
227- }
228- prepared = prepareNativeApiObjCInvocation (
229- runtime, bridge, selectorLookupClass, receiverIsClass, selectorName,
230- selectedMember);
231- // Look up the engine-neutral GSD invoker for this signature.
232- if (prepared->engineInvoker == nullptr ) {
233- uint64_t dispatchId = dispatchIdForEngineSignature (
234- prepared->signature , SignatureCallKind::ObjCMethod);
235- if (auto gsdInvoker = lookupObjCGsdInvoker (dispatchId)) {
236- prepared->engineInvoker = reinterpret_cast <void *>(gsdInvoker);
237- configureGeneratedEngineObjCInvocation (*prepared);
238154 }
239155 }
156+ return receiverHostObject;
157+ };
158+ auto call = resolveNativeApiSelectorGroupCall<false >(
159+ runtime, state, count,
160+ [&]() -> id {
161+ auto host = resolveReceiverHost ();
162+ return host != nullptr ? host->object () : nil ;
163+ },
164+ resolveReceiverHost,
165+ [](uint64_t dispatchId) {
166+ return lookupObjCGsdInvoker (dispatchId);
167+ });
168+ if (call.hasImmediateResult ) {
169+ return std::move (call.immediateResult );
240170 }
241171
242- // Memoized dispatch-superclass resolution (pure function of the
243- // receiver's class + lookupClass) — avoids a per-call
244- // class_conformsToProtocol probe.
245- Class gsdDispatchClass = Nil ;
246- if (!receiverIsClass) {
247- Class receiverClass = object_getClass (receiver);
248- if (receiverClass == cachedReceiverClass) {
249- gsdDispatchClass = cachedDispatchClass;
250- } else {
251- gsdDispatchClass =
252- dispatchSuperclassForEngineDerivedReceiver (receiver, lookupClass);
253- cachedReceiverClass = receiverClass;
254- cachedDispatchClass = gsdDispatchClass;
255- }
256- }
257172 // GSD fast path: read jsi args directly, call objc_msgSend with a
258173 // typed cast, produce the jsi return value — bypassing all generic
259174 // marshalling. Only engages for plain calls (no super dispatch, init
260175 // disown handling, or implicit NSError-out argument).
261- if (prepared->gsdEngineCallable && gsdDispatchClass == Nil &&
262- count == prepared->gsdEngineArgumentCount &&
263- !(!receiverIsClass && prepared->isInitMethod )) {
176+ if (call. prepared ->gsdEngineCallable && call. dispatchClass == Nil &&
177+ count == call. prepared ->gsdEngineArgumentCount &&
178+ !(!state. receiverIsClass && call. prepared ->isInitMethod )) {
264179 auto invoker =
265- reinterpret_cast <ObjCGsdInvoker>(prepared->engineInvoker );
266- GsdObjCContext ctx{runtime, bridge, receiver, prepared->selector ,
267- args, prepared->signature .returnType };
180+ reinterpret_cast <ObjCGsdInvoker>(call.prepared ->engineInvoker );
181+ GsdObjCContext ctx{runtime, state.bridge , call.receiver ,
182+ call.prepared ->selector , args,
183+ call.prepared ->signature .returnType };
268184 if (invoker (ctx)) {
269185 return std::move (ctx.result );
270186 }
271187 }
272188
273- if (receiverIsClass) {
274- return callPreparedObjCSelector (runtime, bridge, receiver, true ,
275- *prepared, args, count, Nil );
189+ if (state.receiverIsClass ) {
190+ return callPreparedObjCSelector (runtime, state.bridge , call.receiver ,
191+ true , *call.prepared , args, count,
192+ Nil );
276193 }
277194 if (!receiverHostObject) {
278- if (boundReceiverState != nullptr ) {
279- if (auto bound = boundReceiver.lock ()) {
280- receiverHostObject = std::move (bound);
281- }
282- } else if (thisValue.isObject ()) {
283- Object receiverObject = thisValue.asObject (runtime);
284- if (receiverObject.isHostObject <NativeApiObjectHostObject>(
285- runtime)) {
286- receiverHostObject =
287- receiverObject.getHostObject <NativeApiObjectHostObject>(
288- runtime);
289- }
290- }
195+ receiverHostObject = resolveReceiverHost ();
291196 }
292197 if (!receiverHostObject) {
293198 throw JSError (runtime,
294199 " Objective-C selector requires a native receiver." );
295200 }
296201 return receiverHostObject->callPreparedObjectSelector (
297- runtime, *prepared, args, count, gsdDispatchClass );
202+ runtime, *call. prepared , args, count, call. dispatchClass );
298203 });
299204}
300205
301- Function CreateNativeApiSelectorGroupFunction (
302- Runtime& runtime, std::shared_ptr<NativeApiBridge> bridge,
303- Class lookupClass, bool receiverIsClass,
304- std::shared_ptr<std::vector<NativeApiSelectorGroupEntry>> selectors,
305- std::shared_ptr<
306- std::vector<std::shared_ptr<NativeApiPreparedObjCInvocation>>>
307- preparedInvocations) {
308- return CreateNativeApiSelectorGroupFunctionImpl (
309- runtime, std::move (bridge), lookupClass, receiverIsClass,
310- std::move (selectors), std::move (preparedInvocations), {}, nullptr );
311- }
312-
313- Function CreateNativeApiBoundSelectorGroupFunction (
314- Runtime& runtime, std::shared_ptr<NativeApiBridge> bridge, Class lookupClass,
315- std::shared_ptr<NativeApiObjectHostObject> receiverHostObject,
316- std::shared_ptr<std::vector<NativeApiSelectorGroupEntry>> selectors,
317- std::shared_ptr<
318- std::vector<std::shared_ptr<NativeApiPreparedObjCInvocation>>>
319- preparedInvocations) {
320- return CreateNativeApiSelectorGroupFunctionImpl (
321- runtime, std::move (bridge), lookupClass, false , std::move (selectors),
322- std::move (preparedInvocations), receiverHostObject,
323- receiverHostObject != nullptr ? receiverHostObject->lifetimeState ()
324- : nullptr );
325- }
326-
327206} // namespace
328207
329208#include " ../shared/bridge/Install.mm"
0 commit comments