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] Prepare to publish v15.0.0 #1649

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion pkgs/ffigen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 15.0.0-wip
## 15.0.0

- Bump minimum Dart version to 3.4.
- Dedupe `ObjCBlock` trampolines to reduce generated ObjC code.
Expand Down
2 changes: 1 addition & 1 deletion pkgs/ffigen/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.

name: ffigen
version: 15.0.0-wip
version: 15.0.0
description: >
Generator for FFI bindings, using LibClang to parse C, Objective-C, and Swift
files.
Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/arc_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#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"
Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/block_annotation_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <stdio.h>

#include "block_annotation_test.h"
#include "util.h"

@implementation EmptyObject
@end
Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/block_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#import <Foundation/NSThread.h>

#include "block_test.h"
#include "util.h"

@implementation DummyObject

Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/global_native_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#import <Foundation/NSObject.h>

#include "global_test.h"
#include "util.h"

NSString* globalNativeString = @"Hello World";
NSObject* _Nullable globalNativeObject = nil;
Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/global_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#import <Foundation/NSObject.h>

#include "global_test.h"
#include "util.h"

NSString* globalString = @"Hello World";
NSObject* _Nullable globalObject = nil;
Expand Down
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/isolate_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.

#include "isolate_test.h"
#include "util.h"

@implementation Sendable
@end
1 change: 0 additions & 1 deletion pkgs/ffigen/test/native_objc_test/protocol_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#import <dispatch/dispatch.h>

#include "protocol_test.h"
#include "util.h"

@implementation ProtocolConsumer : NSObject
- (NSString*)callInstanceMethod:(id<MyProtocol>)protocol {
Expand Down
2 changes: 0 additions & 2 deletions pkgs/ffigen/test/native_objc_test/ref_count_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>

#include "util.h"

#if __has_feature(objc_arc)
#error "This file must be compiled with ARC disabled"
#endif
Expand Down
2 changes: 0 additions & 2 deletions pkgs/ffigen/test/native_objc_test/static_func_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

#import <Foundation/NSString.h>

#include "util.h"

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

Expand Down
8 changes: 4 additions & 4 deletions pkgs/ffigen/test/native_objc_test/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ Future<void> flutterDoGC() async {
await Future<void>.delayed(Duration(milliseconds: 500));
}

@Native<Bool Function(Pointer<Void>)>(isLeaf: true, symbol: 'isReadableMemory')
external bool _isReadableMemory(Pointer<Void> ptr);
@Native<Int Function(Pointer<Void>)>(isLeaf: true, symbol: 'isReadableMemory')
external int _isReadableMemory(Pointer<Void> ptr);

@Native<Uint64 Function(Pointer<Void>)>(
isLeaf: true, symbol: 'getBlockRetainCount')
external int _getBlockRetainCount(Pointer<Void> block);

int blockRetainCount(Pointer<ObjCBlockImpl> block) {
if (!_isReadableMemory(block.cast())) return 0;
if (_isReadableMemory(block.cast()) == 0) return 0;
if (!internal_for_testing.isValidBlock(block)) return 0;
return _getBlockRetainCount(block.cast());
}
Expand All @@ -71,7 +71,7 @@ int blockRetainCount(Pointer<ObjCBlockImpl> block) {
external int _getObjectRetainCount(Pointer<Void> object);

int objectRetainCount(Pointer<ObjCObject> object) {
if (!_isReadableMemory(object.cast())) return 0;
if (_isReadableMemory(object.cast()) == 0) return 0;
final header = object.cast<Uint64>().value;

// package:objective_c's isValidObject function internally calls
Expand Down
2 changes: 1 addition & 1 deletion pkgs/objective_c/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 3.0.0-wip
## 3.0.0

- Add the following stream-related types to the core package:
- `NSInputStream`
Expand Down
2 changes: 1 addition & 1 deletion pkgs/objective_c/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

name: objective_c
description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.'
version: 3.0.0-wip
version: 3.0.0
repository: https://github.com/dart-lang/native/tree/main/pkgs/objective_c

topics:
Expand Down
6 changes: 3 additions & 3 deletions pkgs/objective_c/src/input_stream_adapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ - (BOOL)setProperty:(id)property forKey:(NSStreamPropertyKey)key {
}

- (void)setDelegate:(id<NSStreamDelegate>)delegate {
// From https://developer.apple.com/documentation/foundation/nsstream:
// "...so a delegate message with an argument of nil should restore this
// delegate..."
// From https://developer.apple.com/documentation/foundation/nsstream:
// "...so a delegate message with an argument of nil should restore this
// delegate..."
if (delegate == nil) {
_delegate = self;
} else {
Expand Down
119 changes: 80 additions & 39 deletions pkgs/objective_c/test/ns_input_stream_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,24 @@ import 'package:objective_c/objective_c.dart';
import 'package:objective_c/src/objective_c_bindings_generated.dart';
import 'package:test/test.dart';

import 'util.dart';

Future<(int, Uint8List, bool, NSStreamStatus, NSError?)> read(
NSInputStream stream, int size) async {
// TODO(https://github.com/dart-lang/tools/issues/520):
// Use `Isolate.run`.

final port = ReceivePort();
await Isolate.spawn((sendPort) {
using((arena) {
final buffer = arena<Uint8>(size);
NSInputStream stream, int size) =>
Isolate.run(() {
final buffer = calloc<Uint8>(size);
final readSize = stream.read_maxLength_(buffer, size);
final data =
Uint8List.fromList(buffer.asTypedList(readSize == -1 ? 0 : readSize));
sendPort.send((
calloc.free(buffer);
return (
readSize,
data,
stream.hasBytesAvailable,
stream.streamStatus,
stream.streamError,
));
Isolate.current.kill();
);
});
}, port.sendPort);
return await port.first as (int, Uint8List, bool, NSStreamStatus, NSError?);
}

void main() {
group('NSInputStream', () {
Expand Down Expand Up @@ -242,38 +236,85 @@ void main() {
'localizedDescription', contains('some exception message'))
.having((e) => e.domain.toString(), 'domain', 'DartError'));
});
});

group('delegate', () {
late DartInputStreamAdapter inputStream;
group('delegate', () {
late DartInputStreamAdapter inputStream;

setUp(() {
inputStream = Stream.fromIterable([
[1, 2, 3],
]).toNSInputStream() as DartInputStreamAdapter;
});
setUp(() {
inputStream = Stream.fromIterable([
[1, 2, 3],
]).toNSInputStream() as DartInputStreamAdapter;
});

test('default delegate', () async {
expect(inputStream.delegate, inputStream);
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
});
test('default delegate', () async {
expect(inputStream.delegate, inputStream);
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
});

test('non-self delegate', () async {
final protoBuilder = ObjCProtocolBuilder();
final events = <NSStreamEvent>[];

test('non-self delegate', () async {
final protoBuilder = ObjCProtocolBuilder();
final events = <NSStreamEvent>[];
NSStreamDelegate.addToBuilder(protoBuilder,
stream_handleEvent_: (stream, event) => events.add(event));
inputStream.delegate = protoBuilder.build();
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
expect(events, [NSStreamEvent.NSStreamEventOpenCompleted]);
});

NSStreamDelegate.addToBuilder(protoBuilder,
stream_handleEvent_: (stream, event) => events.add(event));
inputStream.delegate = protoBuilder.build();
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
expect(events, [NSStreamEvent.NSStreamEventOpenCompleted]);
test('assign to null', () async {
inputStream.delegate = null;
expect(inputStream.delegate, inputStream);
});
});

test('assign to null', () async {
inputStream.delegate = null;
expect(inputStream.delegate, inputStream);
group('ref counting', () {
test('with self delegate', () async {
DartInputStreamAdapter? inputStream = Stream.fromIterable([
[1, 2, 3],
]).toNSInputStream() as DartInputStreamAdapter;

expect(inputStream.delegate, inputStream);

final ptr = inputStream.ref.pointer;
expect(objectRetainCount(ptr), greaterThan(0));

inputStream.open();
inputStream.close();
inputStream = null;

doGC();
await Future<void>.delayed(Duration.zero);
doGC();

// TODO(https://github.com/dart-lang/native/issues/1665): Re-enable.
// expect(objectRetainCount(ptr), 0);
});

test('with non-self delegate', () async {
DartInputStreamAdapter? inputStream = Stream.fromIterable([
[1, 2, 3],
]).toNSInputStream() as DartInputStreamAdapter;

inputStream.delegate = NSObject.new1();
expect(inputStream.delegate, isNot(inputStream));

final ptr = inputStream.ref.pointer;
expect(objectRetainCount(ptr), greaterThan(0));

inputStream.open();
inputStream.close();
inputStream = null;

doGC();
await Future<void>.delayed(Duration.zero);
doGC();

// TODO(https://github.com/dart-lang/native/issues/1665): Re-enable.
// expect(objectRetainCount(ptr), 0);
});
});
});
}
6 changes: 5 additions & 1 deletion pkgs/objective_c/test/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import 'dart:io';

import 'package:args/args.dart';

const cFiles = ['src/objective_c.c', 'src/include/dart_api_dl.c'];
const cFiles = [
'src/objective_c.c',
'src/include/dart_api_dl.c',
'test/util.c',
];
const objCFiles = [
'src/input_stream_adapter.m',
'src/objective_c.m',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// 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.

#ifndef _TEST_UTIL_H_
#define _TEST_UTIL_H_

#include <mach/mach.h>
#include <mach/mach_vm.h>

Expand Down Expand Up @@ -33,7 +30,7 @@ uint64_t getObjectRetainCount(ObjectRefCountExtractor* object) {
return count < 0x80 ? count : k128OrMore;
}

bool isReadableMemory(void* ptr) {
int isReadableMemory(void* ptr) {
vm_map_t task = mach_task_self();
mach_vm_address_t address = (mach_vm_address_t)ptr;
mach_vm_size_t size = 0;
Expand All @@ -43,9 +40,7 @@ bool isReadableMemory(void* ptr) {
kern_return_t status =
mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64,
(vm_region_info_t)&info, &count, &object_name);
if (status != KERN_SUCCESS) return false;
if (status != KERN_SUCCESS) return 0;
return ((mach_vm_address_t)ptr) >= address &&
(info.protection & VM_PROT_READ);
}

#endif // _TEST_UTIL_H_
Loading
Loading