Skip to content

Commit

Permalink
Create TypedList after method invocation
Browse files Browse the repository at this point in the history
  • Loading branch information
liamappelbe committed Sep 29, 2024
2 parents d25863b + f9a3888 commit 2d8a282
Show file tree
Hide file tree
Showing 98 changed files with 1,710 additions and 1,772 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ffigen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
channel: 'stable'
- id: install
name: Install dependencies
run: flutter pub get && flutter pub get --directory="example/shared_bindings"
run: flutter pub get && flutter pub get --directory="example/shared_bindings" && flutter pub get --directory="../objective_c"
- name: Check formatting
run: dart format --output=none --set-exit-if-changed .
if: always() && steps.install.outcome == 'success'
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
with:
channel: 'stable'
- name: Install dependencies
run: flutter pub get
run: flutter pub get && flutter pub get --directory="../objective_c"
- name: Build test dylib and bindings
run: dart test/setup.dart
- name: Run VM tests and collect coverage
Expand Down Expand Up @@ -110,9 +110,9 @@ jobs:
with:
channel: 'stable'
- name: Install dependencies
run: flutter pub get
run: flutter pub get && flutter pub get --directory="../objective_c"
- name: Build test dylib and bindings
run: dart test/setup.dart
run: dart test/setup.dart --main-thread-dispatcher
- name: Run Flutter tests
run: flutter test

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ffigen_weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
flutter-version: 3.19.0
channel: 'stable'
- name: Install dependencies
run: flutter pub get
run: flutter pub get && flutter pub get --directory="../objective_c"
- name: Build test dylib and bindings
run: dart test/setup.dart
- name: Run VM tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/native.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:

- uses: nttld/setup-ndk@afb4c9964b521afb97c864b7d40b11e6911bd410
with:
ndk-version: r26b
ndk-version: r27
if: ${{ matrix.os != 'macos' }}

- run: dart pub get
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/native_toolchain_c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:

- uses: nttld/setup-ndk@afb4c9964b521afb97c864b7d40b11e6911bd410
with:
ndk-version: r26b
ndk-version: r27
if: ${{ matrix.sdk == 'stable' }}

- run: dart pub get
Expand Down
2 changes: 2 additions & 0 deletions pkgs/ffigen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
ObjC but before the invocation was received by Dart:
https://github.com/dart-lang/native/issues/1571
- `sort:` config option now affects ObjC interface/protocol methods.
- Fix a bug where `NSRange` was not being imported from package:objective_c:
https://github.com/dart-lang/native/issues/1180
- __Breaking change__: Return structs from ObjC methods by value instead of
taking a struct return pointer.

Expand Down
8 changes: 6 additions & 2 deletions pkgs/ffigen/lib/src/code_generator/compound.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ abstract class Compound extends BindingType {
}

bool get _isBuiltIn =>
objCBuiltInFunctions?.isBuiltInCompound(originalName) ?? false;
objCBuiltInFunctions?.getBuiltInCompoundName(originalName) != null;

@override
BindingString toBindingString(Writer w) {
Expand Down Expand Up @@ -188,7 +188,11 @@ abstract class Compound extends BindingType {
bool get isIncompleteCompound => isIncomplete;

@override
String getCType(Writer w) => _isBuiltIn ? '${w.objcPkgPrefix}.$name' : name;
String getCType(Writer w) {
final builtInName =
objCBuiltInFunctions?.getBuiltInCompoundName(originalName);
return builtInName != null ? '${w.objcPkgPrefix}.$builtInName' : name;
}

@override
String getNativeType({String varName = ''}) => '$nativeType $varName';
Expand Down
18 changes: 9 additions & 9 deletions pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class ObjCBuiltInFunctions {
ObjCImport('UnimplementedOptionalMethodException');

// Keep in sync with pkgs/objective_c/ffigen_objc.yaml.
static const builtInInterfaces = {
static const _builtInInterfaces = {
'DartProxy',
'DartProxyBuilder',
'NSArray',
Expand Down Expand Up @@ -78,11 +78,11 @@ class ObjCBuiltInFunctions {
'NSValue',
'Protocol',
};
static const builtInCompounds = {
'NSFastEnumerationState',
'NSRange',
static const _builtInCompounds = {
'NSFastEnumerationState': 'NSFastEnumerationState',
'_NSRange': 'NSRange',
};
static const builtInEnums = {
static const _builtInEnums = {
'NSBinarySearchingOptions',
'NSComparisonResult',
'NSDataBase64DecodingOptions',
Expand Down Expand Up @@ -110,11 +110,11 @@ class ObjCBuiltInFunctions {
// TODO(https://github.com/dart-lang/native/issues/1173): Ideally this check
// would be based on more than just the name.
bool isBuiltInInterface(String name) =>
!generateForPackageObjectiveC && builtInInterfaces.contains(name);
bool isBuiltInCompound(String name) =>
!generateForPackageObjectiveC && builtInCompounds.contains(name);
!generateForPackageObjectiveC && _builtInInterfaces.contains(name);
String? getBuiltInCompoundName(String name) =>
generateForPackageObjectiveC ? null : _builtInCompounds[name];
bool isBuiltInEnum(String name) =>
!generateForPackageObjectiveC && builtInEnums.contains(name);
!generateForPackageObjectiveC && _builtInEnums.contains(name);
bool isNSObject(String name) => name == 'NSObject';

// We need to load a separate instance of objc_msgSend for each signature. If
Expand Down
6 changes: 3 additions & 3 deletions pkgs/ffigen/lib/src/code_generator/objc_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,10 @@ class ObjCInterface extends BindingType with ObjCMethods {
.invoke(w, target, sel, msgSendParams, structRetPtr: '_ptr');
s.write('''
final _ptr = $calloc<$returnTypeStr>();
final _data = _ptr.cast<$uint8Type>().asTypedList(
$sizeOf<$returnTypeStr>(), finalizer: $calloc.nativeFree);
$invoke;
return ${w.ffiLibraryPrefix}.Struct.create<$returnTypeStr>(_data);
final _finalizable = _ptr.cast<$uint8Type>().asTypedList(
$sizeOf<$returnTypeStr>(), finalizer: $calloc.nativeFree);
return ${w.ffiLibraryPrefix}.Struct.create<$returnTypeStr>(_finalizable);
''');
} else {
if (returnType != voidType) {
Expand Down
7 changes: 5 additions & 2 deletions pkgs/ffigen/test/native_objc_test/arc_config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: ArcTestObjCLibrary
description: 'Tests ARC'
language: objc
output: 'arc_bindings.dart'
output:
bindings: 'arc_bindings.dart'
objc-bindings: 'arc_bindings.m'
exclude-all-by-default: true
functions:
include:
Expand All @@ -10,8 +12,9 @@ functions:
objc-interfaces:
include:
- ArcTestObject
- ArcDtorTestObject
headers:
entry-points:
- 'arc_test.m'
- 'arc_test.h'
preamble: |
// ignore_for_file: camel_case_types, non_constant_identifier_names, unnecessary_non_null_assertion, unused_element, unused_field
20 changes: 19 additions & 1 deletion pkgs/ffigen/test/native_objc_test/arc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import 'util.dart';
void main() {
late ArcTestObjCLibrary lib;

group('Reference counting', () {
group('ARC', () {
setUpAll(() {
// TODO(https://github.com/dart-lang/native/issues/1068): Remove this.
DynamicLibrary.open('../objective_c/test/objective_c.dylib');
Expand Down Expand Up @@ -474,5 +474,23 @@ void main() {
expect(counter.value, 0);
calloc.free(counter);
}, skip: !canDoGC);

test('Destroy on main thread', () async {
const numTestObjects = 1000;

final dtorCounter = calloc<Int32>();
final dtorOnMainThreadCounter = calloc<Int32>();
final objects = <ArcDtorTestObject>[];
for (var i = 0; i < numTestObjects; ++i) {
objects.add(ArcDtorTestObject.alloc().initWithCounters_onMainThread_(
dtorCounter, dtorOnMainThreadCounter));
}
objects.clear();

while (dtorCounter.value < numTestObjects) {
await flutterDoGC();
}
expect(dtorOnMainThreadCounter.value, numTestObjects);
}, skip: !isFlutterTester);
});
}
41 changes: 41 additions & 0 deletions pkgs/ffigen/test/native_objc_test/arc_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#import <Foundation/NSObject.h>

void objc_autoreleasePoolPop(void *pool);
void *objc_autoreleasePoolPush();

@interface ArcTestObject : NSObject {
int32_t* counter;
}

+ (instancetype)allocTheThing;
+ (instancetype)newWithCounter:(int32_t*) _counter;
- (instancetype)initWithCounter:(int32_t*) _counter;
+ (ArcTestObject*)makeAndAutorelease:(int32_t*) _counter;
- (void)setCounter:(int32_t*) _counter;
- (void)dealloc;
- (ArcTestObject*)copyMe;
- (ArcTestObject*)mutableCopyMe;
- (id)copyWithZone:(NSZone*) zone;
- (ArcTestObject*)returnsRetained NS_RETURNS_RETAINED;
- (ArcTestObject*)copyMeNoRetain __attribute__((ns_returns_not_retained));
- (ArcTestObject*)copyMeAutorelease __attribute__((ns_returns_autoreleased));
- (ArcTestObject*)copyMeConsumeSelf __attribute__((ns_consumes_self));
+ (void)consumeArg:(ArcTestObject*) __attribute((ns_consumed)) arg;

@property (assign) ArcTestObject* assignedProperty;
@property (retain) ArcTestObject* retainedProperty;
@property (copy) ArcTestObject* copiedProperty;

@end

@interface ArcDtorTestObject : NSObject {
int32_t* dtorCounter;
int32_t* dtorOnMainThreadCounter;
}
- (instancetype)initWithCounters:(int32_t*) _dtorCounter
onMainThread: (int32_t*) _dtorOnMainThreadCounter;
@end
48 changes: 19 additions & 29 deletions pkgs/ffigen/test/native_objc_test/arc_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#import <Foundation/NSObject.h>
#import <Foundation/NSThread.h>

#include "arc_test.h"
#include "util.h"

#if !__has_feature(objc_arc)
#error "This file must be compiled with ARC enabled"
#endif

void objc_autoreleasePoolPop(void *pool);
void *objc_autoreleasePoolPush();

@interface ArcTestObject : NSObject {
int32_t* counter;
}

+ (instancetype)allocTheThing;
+ (instancetype)newWithCounter:(int32_t*) _counter;
- (instancetype)initWithCounter:(int32_t*) _counter;
+ (ArcTestObject*)makeAndAutorelease:(int32_t*) _counter;
- (void)setCounter:(int32_t*) _counter;
- (void)dealloc;
- (ArcTestObject*)copyMe;
- (ArcTestObject*)mutableCopyMe;
- (id)copyWithZone:(NSZone*) zone;
- (ArcTestObject*)returnsRetained NS_RETURNS_RETAINED;
- (ArcTestObject*)copyMeNoRetain __attribute__((ns_returns_not_retained));
- (ArcTestObject*)copyMeAutorelease __attribute__((ns_returns_autoreleased));
- (ArcTestObject*)copyMeConsumeSelf __attribute__((ns_consumes_self));
+ (void)consumeArg:(ArcTestObject*) __attribute((ns_consumed)) arg;

@property (assign) ArcTestObject* assignedProperty;
@property (retain) ArcTestObject* retainedProperty;
@property (copy) ArcTestObject* copiedProperty;

@end

@implementation ArcTestObject

+ (instancetype)allocTheThing {
Expand Down Expand Up @@ -98,3 +71,20 @@ - (ArcTestObject*)copyMeConsumeSelf __attribute__((ns_consumes_self)) {
+ (void)consumeArg:(ArcTestObject*) __attribute((ns_consumed)) arg {}

@end

@implementation ArcDtorTestObject

- (instancetype)initWithCounters:(int32_t*) _dtorCounter
onMainThread: (int32_t*) _dtorOnMainThreadCounter {
dtorCounter = _dtorCounter;
dtorOnMainThreadCounter = _dtorOnMainThreadCounter;
return [super init];
}

- (void)dealloc {
++*dtorCounter;
if ([NSThread isMainThread]) {
++*dtorOnMainThreadCounter;
}
}
@end
44 changes: 44 additions & 0 deletions pkgs/ffigen/test/native_objc_test/ns_range_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Objective C support is only available on mac.
@TestOn('mac-os')

import 'dart:ffi';
import 'dart:io';

import 'package:ffi/ffi.dart';
import 'package:ffigen/ffigen.dart';
import 'package:ffigen/src/config_provider/config.dart';
import 'package:ffigen/src/config_provider/config_types.dart';
import 'package:logging/logging.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';
import '../test_utils.dart';
import 'util.dart';

void main() {
group('NSRange', () {
late final String bindings;
setUpAll(() {
final config = Config(
wrapperName: 'NSRangeTestObjCLibrary',
language: Language.objc,
output: Uri.file('test/native_objc_test/ns_range_bindings.dart'),
entryPoints: [Uri.file('test/native_objc_test/ns_range_test.m')],
formatOutput: false,
objcInterfaces: DeclarationFilters.include({'SFTranscriptionSegment'}),
);
FfiGen(logLevel: Level.SEVERE).run(config);
bindings = File('test/native_objc_test/ns_range_bindings.dart')
.readAsStringSync();
});

test('interfaces', () {
// Regression test for https://github.com/dart-lang/native/issues/1180.
expect(bindings.split('\n'),
isNot(contains(matches(RegExp(r'class.*NSRange.*Struct')))));
});
});
}
5 changes: 5 additions & 0 deletions pkgs/ffigen/test/native_objc_test/ns_range_test.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#import <Speech/Speech.h>
16 changes: 13 additions & 3 deletions pkgs/ffigen/test/native_objc_test/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import 'dart:async';
import 'dart:io';

import 'package:args/args.dart';

// All ObjC source files are compiled with ARC enabled except these.
const arcDisabledFiles = <String>{
'ref_count_test.m',
Expand Down Expand Up @@ -152,16 +154,24 @@ Future<void> clean(List<String> testNames) async {
}

Future<void> main(List<String> arguments) async {
final parser = ArgParser();
parser.addFlag('clean');
parser.addFlag('main-thread-dispatcher');
final args = parser.parse(arguments);

// Allow running this script directly from any path (or an IDE).
Directory.current = Platform.script.resolve('.').toFilePath();
if (!Platform.isMacOS) {
throw OSError('Objective C tests are only supported on MacOS');
}

if (arguments.isNotEmpty && arguments[0] == 'clean') {
if (args.flag('clean')) {
return await clean(_getTestNames());
}

await _runDart(['../objective_c/test/setup.dart']);
return await build(arguments.isNotEmpty ? arguments : _getTestNames());
await _runDart([
'../objective_c/test/setup.dart',
if (args.flag('main-thread-dispatcher')) '--main-thread-dispatcher',
]);
return await build(args.rest.isNotEmpty ? args.rest : _getTestNames());
}
Loading

0 comments on commit 2d8a282

Please sign in to comment.