Skip to content
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

[ffigen] Experiment to remove synth blocks #1869

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 178 additions & 99 deletions pkgs/ffigen/lib/src/code_generator/objc_block.dart

Large diffs are not rendered by default.

144 changes: 124 additions & 20 deletions pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ class ObjCBuiltInFunctions {
static const msgSendStretPointer = ObjCImport('msgSendStretPointer');
static const useMsgSendVariants = ObjCImport('useMsgSendVariants');
static const respondsToSelector = ObjCImport('respondsToSelector');
static const newPointerBlock = ObjCImport('newPointerBlock');
static const newClosureBlock = ObjCImport('newClosureBlock');
static const registerBlockClosure = ObjCImport('registerBlockClosure');
static const getBlockClosure = ObjCImport('getBlockClosure');
static const getProtocolMethodSignature =
ObjCImport('getProtocolMethodSignature');
static const getProtocol = ObjCImport('getProtocol');
static const objectRelease = ObjCImport('objectRelease');
static const signalWaiter = ObjCImport('signalWaiter');
static const wrapBlockingBlock = ObjCImport('wrapBlockingBlock');
static const newBlockingBlock = ObjCImport('newBlockingBlock');
static const newClosureBlock = ObjCImport('newClosureBlock');
static const blockClosureDisposePort = ObjCImport('blockClosureDisposePort');
static const disposeObjCBlockWithClosure =
ObjCImport('disposeObjCBlockWithClosure');
static const objectBase = ObjCImport('ObjCObjectBase');
static const blockType = ObjCImport('ObjCBlock');
static const consumedType = ObjCImport('Consumed');
Expand Down Expand Up @@ -210,36 +213,130 @@ class ObjCBuiltInFunctions {
.toList();

final _blockTrampolines = <String, ObjCBlockWrapperFuncs>{};
ObjCBlockWrapperFuncs? getBlockTrampolines(ObjCBlock block) {
ObjCBlockWrapperFuncs getBlockTrampolines(ObjCBlock block) {
final id = _methodSigId(block.returnType, block.params);
final idHash = fnvHash32(id).toRadixString(36);
final dtorType = FunctionType(
returnType: voidType,
parameters: [
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'dispose_port',
objCConsumed: false),
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'closure_id',
objCConsumed: false),
],
);
return _blockTrampolines[id] ??= ObjCBlockWrapperFuncs(
_blockTrampolineFunc('_${wrapperName}_wrapListenerBlock_$idHash'),
_blockTrampolineFunc('_${wrapperName}_wrapBlockingBlock_$idHash',
blocking: true),
Func(
name: '_${wrapperName}_invokeBlock_$idHash',
returnType: block.returnType,
parameters: [
Parameter(
name: 'block',
type: PointerType(objCBlockType),
objCConsumed: false),
...block.params,
],
objCReturnsRetained: block.returnsRetained,
isLeaf: false,
isInternal: true,
useNameForLookup: true,
ffiNativeConfig: const FfiNativeConfig(enabled: true),
),
Func(
name: '_${wrapperName}_newPointerBlock_$idHash',
returnType: PointerType(objCBlockType),
parameters: [
Parameter(
name: 'trampoline',
type: PointerType(voidType),
objCConsumed: false),
Parameter(
name: 'func', type: PointerType(voidType), objCConsumed: false),
],
objCReturnsRetained: true,
isLeaf: true,
isInternal: true,
useNameForLookup: true,
ffiNativeConfig: const FfiNativeConfig(enabled: true),
),
Func(
name: '_${wrapperName}_newClosureBlock_$idHash',
returnType: PointerType(objCBlockType),
parameters: [
Parameter(
name: 'trampoline',
type: PointerType(voidType),
objCConsumed: false),
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'closure_id',
objCConsumed: false),
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'dispose_port',
objCConsumed: false),
Parameter(
name: 'dtor',
type: PointerType(NativeFunc(dtorType)),
objCConsumed: false),
],
objCReturnsRetained: true,
isLeaf: true,
isInternal: true,
useNameForLookup: true,
ffiNativeConfig: const FfiNativeConfig(enabled: true),
),
block.hasListener
? _blockTrampolineFunc(
'_${wrapperName}_newListenerBlock_$idHash', dtorType)
: null,
block.hasListener
? _blockTrampolineFunc(
'_${wrapperName}_newBlockingBlock_$idHash', dtorType,
blocking: true)
: null,
);
}

Func _blockTrampolineFunc(String name, {bool blocking = false}) => Func(
Func _blockTrampolineFunc(String name, Type dtorType,
{bool blocking = false}) =>
Func(
name: name,
returnType: PointerType(objCBlockType),
parameters: [
Parameter(
name: 'block',
type: PointerType(objCBlockType),
name: 'trampoline',
type: PointerType(voidType),
objCConsumed: false),
if (blocking) ...[
if (blocking)
Parameter(
name: 'listnerBlock',
type: PointerType(objCBlockType),
name: 'listener_trampoline',
type: PointerType(voidType),
objCConsumed: false),
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'closure_id',
objCConsumed: false),
Parameter(
type: NativeType(SupportedNativeType.int64),
name: 'dispose_port',
objCConsumed: false),
Parameter(
name: 'dtor',
type: PointerType(NativeFunc(dtorType)),
objCConsumed: false),
if (blocking) ...[
Parameter(
name: 'newWaiter',
name: 'new_waiter',
type: PointerType(NativeFunc(FunctionType(
returnType: PointerType(voidType), parameters: []))),
objCConsumed: false),
Parameter(
name: 'awaitWaiter',
name: 'await_waiter',
type: PointerType(
NativeFunc(FunctionType(returnType: voidType, parameters: [
Parameter(type: PointerType(voidType), objCConsumed: false),
Expand All @@ -263,17 +360,24 @@ class ObjCBuiltInFunctions {

/// A native trampoline function for a listener block.
class ObjCBlockWrapperFuncs extends AstNode {
final Func listenerWrapper;
final Func blockingWrapper;
final Func invokeBlock;
final Func newPointerBlock;
final Func newClosureBlock;
final Func? newListenerBlock;
final Func? newBlockingBlock;
bool objCBindingsGenerated = false;

ObjCBlockWrapperFuncs(this.listenerWrapper, this.blockingWrapper);
ObjCBlockWrapperFuncs(this.invokeBlock, this.newPointerBlock,
this.newClosureBlock, this.newListenerBlock, this.newBlockingBlock);

@override
void visitChildren(Visitor visitor) {
super.visitChildren(visitor);
visitor.visit(listenerWrapper);
visitor.visit(blockingWrapper);
visitor.visit(invokeBlock);
visitor.visit(newPointerBlock);
visitor.visit(newClosureBlock);
visitor.visit(newListenerBlock);
visitor.visit(newBlockingBlock);
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkgs/ffigen/lib/src/code_generator/pointer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class IncompleteArray extends PointerType {

@override
String getNativeType({String varName = ''}) =>
'${child.getNativeType()} $varName[]';
'${child.getNativeType()}* $varName';

@override
String toString() => '$child[]';
Expand Down
21 changes: 21 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ class Writer {
for (final entryPoint in nativeEntryPoints) {
s.write(_objcImport(entryPoint, outDir));
}
final dtorClass = '_${className}_BlockDestroyer';
s.write('''

#if !__has_feature(objc_arc)
Expand All @@ -446,6 +447,26 @@ class Writer {

id objc_retain(id);
id objc_retainBlock(id);

@interface $dtorClass : NSObject {}
@property int64_t closure_id;
@property int64_t dispose_port;
@property void (*dtor)(int64_t, int64_t);
+ (instancetype)new:(int64_t) closure_id disposePort:(int64_t) dispose_port
destructor:(void (*)(int64_t, int64_t)) dtor;
- (void)dealloc;
@end
@implementation $dtorClass
+ (instancetype)new:(int64_t) closure_id disposePort:(int64_t) dispose_port
destructor:(void (*)(int64_t, int64_t)) dtor {
$dtorClass* d = [[$dtorClass alloc] init];
d.closure_id = closure_id;
d.dispose_port = dispose_port;
d.dtor = dtor;
return d;
}
- (void)dealloc { self.dtor(self.dispose_port, self.closure_id); }
@end
''');

var empty = true;
Expand Down
Loading
Loading