Skip to content

Commit d90dfc8

Browse files
committed
Merge branch 'feature/return_nsstring_opt' into feature/invoke_perf_opt
* feature/return_nsstring_opt: fix: debug run scheme feat: retType support string feat: return string for nsstring by default. # Conflicts: # dart_native/ios/DartNative.framework/DartNative # dart_native/lib/src/ios/common/pointer_encoding.dart # dart_native/lib/src/ios/runtime/block.dart # dart_native/lib/src/ios/runtime/message.dart
2 parents f2aa176 + 33d3699 commit d90dfc8

File tree

22 files changed

+239
-95
lines changed

22 files changed

+239
-95
lines changed

dart_native/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
buildConfiguration = "Debug"
4444
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
4545
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
46+
enableASanStackUseAfterReturn = "YES"
4647
launchStyle = "0"
4748
useCustomWorkingDirectory = "NO"
4849
ignoresPersistentStateOnLaunch = "NO"

dart_native/example/lib/ios/runtimestub.dart

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,7 @@ class RuntimeStub extends NSObject {
244244
}
245245

246246
String fooNSString(String str) {
247-
Pointer<Void> result =
248-
perform(SEL('fooNSString:'), args: [str], decodeRetVal: false);
249-
return NSString.fromPointer(result).raw;
247+
return perform(SEL('fooNSString:'), args: [str]);
250248
}
251249

252250
Future<dynamic> fooNSStringAsync(String str) async {
@@ -257,9 +255,7 @@ class RuntimeStub extends NSObject {
257255

258256
String fooNSMutableString(String str) {
259257
NSMutableString _str = NSMutableString(str);
260-
Pointer<Void> result =
261-
perform(SEL('fooNSMutableString:'), args: [_str], decodeRetVal: false);
262-
return NSMutableString.fromPointer(result).raw;
258+
return perform(SEL('fooNSMutableString:'), args: [_str]);
263259
}
264260

265261
bool fooWithError(NSObjectRef<NSError> error) {

dart_native/example/lib/ios/unit_test.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ testIOS(RuntimeStub stub, DelegateStub delegate) {
148148
Class('NSThread')
149149
.performAsync(SEL('currentThread'), onQueue: DispatchQueue.global())
150150
.then((currentThread) {
151-
NSObject description = currentThread.perform(SEL('description'));
152-
String threadResult = NSString.fromPointer(description.pointer).raw;
153-
print('currentThread: $threadResult');
151+
print('currentThread: ${currentThread.description}');
154152
});
155153

156154
NSNotificationCenter.defaultCenter.addObserver(

dart_native/ios/Classes/DNInvocation.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ - (void *)_copyPointer:(void **)pointer encode:(const char *)encode key:(NSNumbe
157157
}
158158

159159
- (void)_retainPointer:(void **)pointer encode:(const char *)encode key:(NSNumber *)key {
160-
if (!pointer) {
160+
if (!pointer || *encode == 'v') {
161161
return;
162162
}
163163
void *p = *pointer;

dart_native/ios/Classes/DNObjectDealloc.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,27 @@ + (void)attachHost:(NSObject *)host
5454
}
5555
}
5656

57+
static int64_t fuxk;
58+
5759
- (instancetype)initWithHost:(NSObject *)host
5860
dartPort:(Dart_Port)dartPort {
5961
self = [super init];
6062
if (self) {
6163
_host = host;
6264
_hostAddress = (int64_t)host;
65+
// if ([host isKindOfClass:NSClassFromString(@"Fuck")]) {
66+
// fuxk = _hostAddress;
67+
// }
6368
_dartPort = dartPort;
6469
objc_setAssociatedObject(host, _cmd, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
6570
}
6671
return self;
6772
}
6873

6974
- (void)dealloc {
75+
// if (_hostAddress == fuxk) {
76+
//
77+
// }
7078
NotifyDeallocToDart(_hostAddress, _dartPort);
7179
}
7280

dart_native/ios/Classes/native_runtime.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ native_get_class(const char *className, Class superclass);
4242
/// @param args arguments passed to method.
4343
/// @param dartPort port for dart isolate.
4444
/// @param stringTypeBitmask bitmask for checking if an argument is a string.
45+
/// @param retType type of return value.
4546
DN_EXTERN void * _Nullable
46-
native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void * _Nonnull * _Nullable args, void (^callback)(void *), Dart_Port dartPort, int64_t stringTypeBitmask);
47+
native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void * _Nonnull * _Nullable args, void (^callback)(void *), Dart_Port dartPort, int64_t stringTypeBitmask, const char *_Nonnull *_Nonnull retType);
4748

4849
DN_EXTERN void *
4950
native_block_create(char *types, void *callback, Dart_Port dartPort);

dart_native/ios/Classes/native_runtime.mm

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@
125125
(stringTypeBitmask >> argsIndex & 0x1) == 1) {
126126
const unichar *data = ((const unichar **)args)[argsIndex];
127127
// First four uint16_t is for data length.
128-
const NSUInteger dataOffset = 4;
128+
const NSUInteger lengthDataSize = 4;
129129
uint64_t length = data[0];
130-
for (int i = 1; i < dataOffset; i++) {
130+
for (int i = 1; i < lengthDataSize; i++) {
131131
length <<= 16;
132132
length |= data[i];
133133
}
134-
NSString *realArg = [NSString stringWithCharacters:data + dataOffset length:length];
134+
NSString *realArg = [NSString stringWithCharacters:data + lengthDataSize length:length];
135135
[stringTypeBucket addObject:realArg];
136136
free((void *)data); // Malloc data on dart side, need free here.
137137
[invocation setArgument:&realArg atIndex:i];
@@ -141,8 +141,32 @@
141141
}
142142
}
143143

144+
145+
/// Return data for NSString: [--dataLength(64bit--)][--dataContent(utf16 without BOM)--]
146+
/// @param retVal origin return value
147+
/// @param retType type for return value
148+
void *_dataForNSStringReturnValue(NSString *retVal, const char **retType) {
149+
// first bit is for return value.
150+
*retType = native_all_type_encodings()[18];
151+
NSUInteger length = 0;
152+
const uint16_t *utf16BufferPtr = native_convert_nsstring_to_utf16(retVal, &length);
153+
size_t size = sizeof(uint16_t) * length;
154+
const size_t lengthDataSize = 4;
155+
// free memory on dart side.
156+
uint16_t *dataPtr = (uint16_t *)malloc(size + sizeof(uint16_t) * lengthDataSize);
157+
memcpy(dataPtr + lengthDataSize, utf16BufferPtr, size);
158+
uint16_t lengthData[4] = {
159+
static_cast<uint16_t>(length >> 48 & 0xffff),
160+
static_cast<uint16_t>(length >> 32 & 0xffff),
161+
static_cast<uint16_t>(length >> 16 & 0xffff),
162+
static_cast<uint16_t>(length & 0xffff)
163+
};
164+
memcpy(dataPtr, lengthData, sizeof(uint16_t) * lengthDataSize);
165+
return dataPtr;
166+
}
167+
144168
void *
145-
native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void **args, void (^callback)(void *), Dart_Port dartPort, int64_t stringTypeBitmask) {
169+
native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void **args, void (^callback)(void *), Dart_Port dartPort, int64_t stringTypeBitmask, const char **retType) {
146170
if (!object || !selector || !signature) {
147171
return NULL;
148172
}
@@ -162,8 +186,16 @@
162186
} else {
163187
[invocation getReturnValue:&result];
164188
if (returnType == '@') {
165-
[DNObjectDealloc attachHost:(__bridge id)result
166-
dartPort:dartPort];
189+
BOOL isNSString = [(__bridge id)result isKindOfClass:NSString.class];
190+
// highest bit is a flag for decode.
191+
BOOL decodeRetVal = (stringTypeBitmask & (1LL << 63)) != 0;
192+
// return value is a NSString and needs decode.
193+
if (isNSString && decodeRetVal) {
194+
result = _dataForNSStringReturnValue((__bridge NSString *)result, retType);
195+
} else {
196+
[DNObjectDealloc attachHost:(__bridge id)result
197+
dartPort:dartPort];
198+
}
167199
}
168200
}
169201
}
@@ -201,7 +233,10 @@
201233
}
202234

203235
void *
204-
native_block_invoke(void *block, void **args, Dart_Port dartPort, int64_t stringTypeBitmask) {
236+
native_block_invoke(void *block, void **args, Dart_Port dartPort, int64_t stringTypeBitmask, const char **retType) {
237+
if (!block) {
238+
return nullptr;
239+
}
205240
const char *typeString = DNBlockTypeEncodeString((__bridge id)block);
206241
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:typeString];
207242
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
@@ -216,7 +251,12 @@
216251
[invocation getReturnValue:result];
217252
} else {
218253
[invocation getReturnValue:&result];
219-
if (returnType == '@') {
254+
BOOL isNSString = [(__bridge id)result isKindOfClass:NSString.class];
255+
BOOL decodeRetVal = (stringTypeBitmask & (1LL << 63)) != 0;
256+
// return value is a NSString and needs decode.
257+
if (isNSString && decodeRetVal) {
258+
result = _dataForNSStringReturnValue((__bridge NSString *)result, retType);
259+
} else {
220260
[DNObjectDealloc attachHost:(__bridge id)result
221261
dartPort:dartPort];
222262
}
@@ -226,7 +266,7 @@
226266
}
227267

228268
// Use pointer as key of encoding string cache (on dart side).
229-
static const char *typeList[18] = {"sint8", "sint16", "sint32", "sint64", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "object", "class", "selector", "block", "char *", "void", "ptr", "bool"};
269+
static const char *typeList[19] = {"sint8", "sint16", "sint32", "sint64", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "object", "class", "selector", "block", "char *", "void", "ptr", "bool", "string"};
230270

231271
const char **
232272
native_all_type_encodings() {

dart_native/lib/src/ios/common/callback_register.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ _callback(
6262
if (i + 1 < dartTypes.length) {
6363
String dartType = dartTypes[i + 1];
6464
arg = boxingObjCBasicValue(dartType, arg);
65-
arg = convertFromPointer(dartType, arg);
65+
arg = objcInstanceFromPointer(dartType, arg);
6666
}
6767
args.add(arg);
6868
}

dart_native/lib/src/ios/common/library.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'dart:ffi';
22

33
import 'package:dart_native/src/ios/common/callback_manager.dart';
4-
import 'package:dart_native/src/ios/runtime/nsobject.dart';
4+
import 'package:dart_native/src/ios/runtime/internal/nsobject_lifecycle.dart';
55

66
DynamicLibrary _runtimeLib;
77
DynamicLibrary get runtimeLib {
@@ -24,5 +24,4 @@ final initializeApi = runtimeLib.lookupFunction<IntPtr Function(Pointer<Void>),
2424
int Function(Pointer<Void>)>("InitDartApiDL");
2525

2626
final _dartAPIResult = initializeApi(NativeApi.initializeApiDLData);
27-
2827
final initDartAPISuccess = _dartAPIResult == 0;

dart_native/lib/src/ios/common/pointer_encoding.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extension TypeEncodings on Pointer<Utf8> {
3030
static final Pointer<Utf8> v = _typeEncodings.elementAt(15).value;
3131
static final Pointer<Utf8> pointer = _typeEncodings.elementAt(16).value;
3232
static final Pointer<Utf8> b = _typeEncodings.elementAt(17).value;
33+
static final Pointer<Utf8> string = _typeEncodings.elementAt(18).value;
3334

3435
// Return encoding only if type is struct.
3536
String get encodingForStruct {
@@ -44,6 +45,10 @@ extension TypeEncodings on Pointer<Utf8> {
4445
return cast<Uint8>().value == 123;
4546
}
4647

48+
bool get isString {
49+
return this == TypeEncodings.string;
50+
}
51+
4752
bool get isNum {
4853
bool result = this == TypeEncodings.sint8 ||
4954
this == TypeEncodings.sint16 ||
@@ -321,6 +326,23 @@ String structNameForEncoding(String encoding) {
321326
return null;
322327
}
323328

329+
String loadStringFromPointer(Pointer<Void> ptr) {
330+
final dataPtr = ptr.cast<Int16>();
331+
// get data length
332+
const lengthDataSize = 4;
333+
final lengthData = dataPtr.asTypedList(lengthDataSize);
334+
int length = lengthData[0] << 48 |
335+
lengthData[1] << 32 |
336+
lengthData[2] << 16 |
337+
lengthData[3];
338+
// get utf16 data
339+
Int16List data = dataPtr.elementAt(lengthDataSize).asTypedList(length);
340+
String result = String.fromCharCodes(data);
341+
// malloc dataPtr on native side, shoule free the memory.
342+
free(dataPtr);
343+
return result;
344+
}
345+
324346
NativeStruct loadStructFromPointer(Pointer<Void> ptr, String encoding) {
325347
if (encoding == null) {
326348
return null;

0 commit comments

Comments
 (0)