Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 99021da

Browse files
authored
Sped up the objc standard message codec (#25998)
Sped up the StandardMessageCodec for iOS, tiny tweaks about 5% gain.
1 parent e13e345 commit 99021da

File tree

1 file changed

+93
-56
lines changed

1 file changed

+93
-56
lines changed

shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm

Lines changed: 93 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66

77
#pragma mark - Codec for basic message channel
88

9+
static const UInt8 kZeroBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
10+
// Classes are cached in static variables to avoid the extra method calls in a
11+
// highly traffic'd recursive function.
12+
static const Class kNSNumberClass = [NSNumber class];
13+
static const id kNSNull = [NSNull null];
14+
static const Class kNSStringClass = [NSString class];
15+
static const Class kNSDataClass = [NSData class];
16+
static const Class kNSArrayClass = [NSArray class];
17+
static const Class kNSDictionaryClass = [NSDictionary class];
18+
static const Class kFlutterStandardTypedDataClass = [FlutterStandardTypedData class];
19+
920
@implementation FlutterStandardMessageCodec {
1021
FlutterStandardReaderWriter* _readerWriter;
1122
}
@@ -221,115 +232,142 @@ - (void)dealloc {
221232
[super dealloc];
222233
}
223234

224-
- (void)writeByte:(UInt8)value {
225-
[_data appendBytes:&value length:1];
235+
static void WriteByte(CFMutableDataRef data, UInt8 value) {
236+
CFDataAppendBytes(data, &value, 1);
226237
}
227238

228-
- (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
229-
[_data appendBytes:bytes length:length];
239+
static void WriteBytes(CFMutableDataRef data, const void* bytes, NSUInteger length) {
240+
CFDataAppendBytes(data, (const UInt8*)bytes, length);
230241
}
231242

232-
- (void)writeData:(NSData*)data {
233-
[_data appendData:data];
243+
static void WriteData(CFMutableDataRef destination, NSData* source) {
244+
CFDataAppendBytes(destination, (const UInt8*)source.bytes, source.length);
234245
}
235246

236-
- (void)writeSize:(UInt32)size {
247+
static void WriteSize(CFMutableDataRef data, UInt32 size) {
237248
if (size < 254) {
238-
[self writeByte:(UInt8)size];
249+
WriteByte(data, (UInt8)size);
239250
} else if (size <= 0xffff) {
240-
[self writeByte:254];
251+
WriteByte(data, 254);
241252
UInt16 value = (UInt16)size;
242-
[self writeBytes:&value length:2];
253+
WriteBytes(data, &value, 2);
243254
} else {
244-
[self writeByte:255];
245-
[self writeBytes:&size length:4];
255+
WriteByte(data, 255);
256+
WriteBytes(data, &size, 4);
246257
}
247258
}
248259

249-
- (void)writeAlignment:(UInt8)alignment {
250-
UInt8 mod = _data.length % alignment;
260+
static void WriteAlignment(CFMutableDataRef data, UInt8 alignment) {
261+
NSCAssert(alignment <= 8, @"Alignment larger than kZeroBuffer.");
262+
UInt8 mod = CFDataGetLength(data) % alignment;
251263
if (mod) {
252-
for (int i = 0; i < (alignment - mod); i++) {
253-
[self writeByte:0];
254-
}
264+
WriteBytes(data, kZeroBuffer, alignment - mod);
255265
}
256266
}
257267

258-
- (void)writeUTF8:(NSString*)value {
268+
static void WriteUTF8(CFMutableDataRef data, NSString* value) {
259269
UInt32 length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
260-
[self writeSize:length];
261-
[self writeBytes:value.UTF8String length:length];
270+
WriteSize(data, length);
271+
WriteBytes(data, value.UTF8String, length);
262272
}
263273

264-
- (void)writeValue:(id)value {
265-
if (value == nil || value == [NSNull null]) {
266-
[self writeByte:FlutterStandardFieldNil];
267-
} else if ([value isKindOfClass:[NSNumber class]]) {
274+
static void WriteValue(CFMutableDataRef data, id value) {
275+
if (value == nil || value == kNSNull) {
276+
WriteByte(data, FlutterStandardFieldNil);
277+
} else if ([value isKindOfClass:kNSNumberClass]) {
268278
CFNumberRef number = (CFNumberRef)value;
269279
BOOL success = NO;
270280
if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
271281
BOOL b = CFBooleanGetValue((CFBooleanRef)number);
272-
[self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)];
282+
WriteByte(data, (b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse));
273283
success = YES;
274284
} else if (CFNumberIsFloatType(number)) {
275285
Float64 f;
276286
success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
277287
if (success) {
278-
[self writeByte:FlutterStandardFieldFloat64];
279-
[self writeAlignment:8];
280-
[self writeBytes:(UInt8*)&f length:8];
288+
WriteByte(data, FlutterStandardFieldFloat64);
289+
WriteAlignment(data, 8);
290+
WriteBytes(data, (UInt8*)&f, 8);
281291
}
282292
} else if (CFNumberGetByteSize(number) <= 4) {
283293
SInt32 n;
284294
success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
285295
if (success) {
286-
[self writeByte:FlutterStandardFieldInt32];
287-
[self writeBytes:(UInt8*)&n length:4];
296+
WriteByte(data, FlutterStandardFieldInt32);
297+
WriteBytes(data, (UInt8*)&n, 4);
288298
}
289299
} else if (CFNumberGetByteSize(number) <= 8) {
290300
SInt64 n;
291301
success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
292302
if (success) {
293-
[self writeByte:FlutterStandardFieldInt64];
294-
[self writeBytes:(UInt8*)&n length:8];
303+
WriteByte(data, FlutterStandardFieldInt64);
304+
WriteBytes(data, (UInt8*)&n, 8);
295305
}
296306
}
297307
if (!success) {
298308
NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
299-
NSAssert(NO, @"Unsupported value for standard codec");
309+
NSCAssert(NO, @"Unsupported value for standard codec.");
300310
}
301-
} else if ([value isKindOfClass:[NSString class]]) {
311+
} else if ([value isKindOfClass:kNSStringClass]) {
302312
NSString* string = value;
303-
[self writeByte:FlutterStandardFieldString];
304-
[self writeUTF8:string];
305-
} else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
313+
WriteByte(data, FlutterStandardFieldString);
314+
WriteUTF8(data, string);
315+
} else if ([value isKindOfClass:kFlutterStandardTypedDataClass]) {
306316
FlutterStandardTypedData* typedData = value;
307-
[self writeByte:FlutterStandardFieldForDataType(typedData.type)];
308-
[self writeSize:typedData.elementCount];
309-
[self writeAlignment:typedData.elementSize];
310-
[self writeData:typedData.data];
311-
} else if ([value isKindOfClass:[NSData class]]) {
312-
[self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]];
313-
} else if ([value isKindOfClass:[NSArray class]]) {
317+
WriteByte(data, FlutterStandardFieldForDataType(typedData.type));
318+
WriteSize(data, typedData.elementCount);
319+
WriteAlignment(data, typedData.elementSize);
320+
WriteData(data, typedData.data);
321+
} else if ([value isKindOfClass:kNSDataClass]) {
322+
WriteValue(data, [FlutterStandardTypedData typedDataWithBytes:value]);
323+
} else if ([value isKindOfClass:kNSArrayClass]) {
314324
NSArray* array = value;
315-
[self writeByte:FlutterStandardFieldList];
316-
[self writeSize:array.count];
325+
WriteByte(data, FlutterStandardFieldList);
326+
WriteSize(data, array.count);
317327
for (id object in array) {
318-
[self writeValue:object];
328+
WriteValue(data, object);
319329
}
320-
} else if ([value isKindOfClass:[NSDictionary class]]) {
330+
} else if ([value isKindOfClass:kNSDictionaryClass]) {
321331
NSDictionary* dict = value;
322-
[self writeByte:FlutterStandardFieldMap];
323-
[self writeSize:dict.count];
332+
WriteByte(data, FlutterStandardFieldMap);
333+
WriteSize(data, dict.count);
324334
for (id key in dict) {
325-
[self writeValue:key];
326-
[self writeValue:[dict objectForKey:key]];
335+
WriteValue(data, key);
336+
WriteValue(data, [dict objectForKey:key]);
327337
}
328338
} else {
329339
NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
330-
NSAssert(NO, @"Unsupported value for standard codec");
340+
NSCAssert(NO, @"Unsupported value for standard codec.");
331341
}
332342
}
343+
344+
- (void)writeByte:(UInt8)value {
345+
WriteByte((__bridge CFMutableDataRef)_data, value);
346+
}
347+
348+
- (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
349+
WriteBytes((__bridge CFMutableDataRef)_data, bytes, length);
350+
}
351+
352+
- (void)writeData:(NSData*)data {
353+
WriteData((__bridge CFMutableDataRef)_data, data);
354+
}
355+
356+
- (void)writeSize:(UInt32)size {
357+
WriteSize((__bridge CFMutableDataRef)_data, size);
358+
}
359+
360+
- (void)writeAlignment:(UInt8)alignment {
361+
WriteAlignment((__bridge CFMutableDataRef)_data, alignment);
362+
}
363+
364+
- (void)writeUTF8:(NSString*)value {
365+
WriteUTF8((__bridge CFMutableDataRef)_data, value);
366+
}
367+
368+
- (void)writeValue:(id)value {
369+
WriteValue((__bridge CFMutableDataRef)_data, value);
370+
}
333371
@end
334372

335373
@implementation FlutterStandardReader {
@@ -450,7 +488,7 @@ - (nullable id)readValueOfType:(UInt8)type {
450488
NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
451489
for (UInt32 i = 0; i < length; i++) {
452490
id value = [self readValue];
453-
[array addObject:(value == nil ? [NSNull null] : value)];
491+
[array addObject:(value == nil ? kNSNull : value)];
454492
}
455493
return array;
456494
}
@@ -460,8 +498,7 @@ - (nullable id)readValueOfType:(UInt8)type {
460498
for (UInt32 i = 0; i < size; i++) {
461499
id key = [self readValue];
462500
id val = [self readValue];
463-
[dict setObject:(val == nil ? [NSNull null] : val)
464-
forKey:(key == nil ? [NSNull null] : key)];
501+
[dict setObject:(val == nil ? kNSNull : val) forKey:(key == nil ? kNSNull : key)];
465502
}
466503
return dict;
467504
}

0 commit comments

Comments
 (0)