Skip to content

[ffigen] Investigate dart-lang/http#1702 #2027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
liamappelbe opened this issue Feb 24, 2025 · 1 comment · Fixed by #2029
Closed

[ffigen] Investigate dart-lang/http#1702 #2027

liamappelbe opened this issue Feb 24, 2025 · 1 comment · Fixed by #2029

Comments

@liamappelbe
Copy link
Contributor

liamappelbe commented Feb 24, 2025

dart-lang/http#1702 appears to be caused by a bug in firebase. But we only noticed the bug when cupertino_http switched from manually written delegates to ffigen's NSProxy based delegates. Normal delegates didn't manifest this bug. So maybe it's possible to make our delegates more compatible/robust and avoid bugs like this in future?

One thing we could investigate is whether we could implement delegates without NSProxy, such as by constructing classes at runtime using ObjC's runtime API (eg class_addMethod).

@liamappelbe liamappelbe added this to the ffigen 18.0.0 (2025 Q1) milestone Feb 24, 2025
@liamappelbe liamappelbe self-assigned this Feb 24, 2025
@liamappelbe liamappelbe moved this to In progress in ObjC/Swift interop Feb 24, 2025
@liamappelbe liamappelbe changed the title [ffigen] Investigate https://github.com/dart-lang/http/issues/1702 [ffigen] Investigate dart-lang/http#1702 Feb 24, 2025
@liamappelbe
Copy link
Contributor Author

The main problem that needs to be solved here is what to pass as the implementation of the method, imp:

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

imp is a C function pointer that needs to have the same signature as the method, but with a self and SEL as the first two args. This is tricky because at the moment we implement methods by constructing blocks, but this is taking a raw C function pointer, not a block.

The simplest solution would be to store all the methods in a map on the constructed object, and write a trampoline in package:objective_c that uses the SEL to look up the method in self (which is how the current NSProxy approach works). But the imp function needs to have the same signature as the method, so a one-size-fits-all trampoline won't work. We'll need one trampoline per protocol method signature.

The trampolines need to be written in native code, due to the same ref counting issues as the block trampolines. We'll also need to support listener and blocking variants. But since we already have all the plumbing for implementing protocol methods using blocks, we can do the same here, effectively allowing us to reuse the block trampolines for the listener and blocking variants. All we need to do is write one tiny trampoline per signature:

R protocolTrampoline(id target, SEL sel, T1 arg1, T2 arg2, T3 arg3) {
  return [target getMethodForSelector: sel](arg1, arg2, arg3);
}

Where getMethodForSelector looks up the corresponding block in the map using the selector. The listener/blocking logic, and all the arg retains etc, are handled by the existing block infra.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

1 participant