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

Commit 773b435

Browse files
authored
Sped up reading with FlutterStandardCodec. (#38327)
* Sped up reading with FlutterStandardCodec. * added missing license diff * put the IsStandardType in the header so it's closer to where it should change * added unittest for subclassing codecs * fixed lints
1 parent 010f4ee commit 773b435

File tree

8 files changed

+380
-108
lines changed

8 files changed

+380
-108
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,8 @@ ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCh
24172417
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m + ../../../flutter/LICENSE
24182418
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm + ../../../flutter/LICENSE
24192419
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm + ../../../flutter/LICENSE
2420+
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c + ../../../flutter/LICENSE
2421+
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h + ../../../flutter/LICENSE
24202422
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h + ../../../flutter/LICENSE
24212423
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h + ../../../flutter/LICENSE
24222424
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm + ../../../flutter/LICENSE
@@ -4872,6 +4874,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChan
48724874
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m
48734875
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm
48744876
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
4877+
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c
4878+
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h
48754879
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
48764880
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
48774881
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm

shell/platform/darwin/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ source_set("flutter_channels_arc") {
4747
"common/framework/Source/FlutterChannels.mm",
4848
"common/framework/Source/FlutterCodecs.mm",
4949
"common/framework/Source/FlutterStandardCodec.mm",
50+
"common/framework/Source/FlutterStandardCodecHelper.c",
5051
"common/framework/Source/FlutterStandardCodec_Internal.h",
5152
]
5253

shell/platform/darwin/common/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ source_set("framework_shared") {
3737
"framework/Source/FlutterChannels.mm",
3838
"framework/Source/FlutterCodecs.mm",
3939
"framework/Source/FlutterStandardCodec.mm",
40+
"framework/Source/FlutterStandardCodecHelper.c",
4041
"framework/Source/FlutterStandardCodec_Internal.h",
4142
]
4243

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

Lines changed: 36 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
56
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h"
67

78
FLUTTER_ASSERT_ARC
@@ -338,30 +339,16 @@ - (BOOL)hasMore {
338339
}
339340

340341
- (void)readBytes:(void*)destination length:(NSUInteger)length {
341-
_range.length = length;
342-
[_data getBytes:destination range:_range];
343-
_range.location += _range.length;
342+
FlutterStandardCodecHelperReadBytes(&_range.location, length, destination,
343+
(__bridge CFDataRef)_data);
344344
}
345345

346346
- (UInt8)readByte {
347-
UInt8 value;
348-
[self readBytes:&value length:1];
349-
return value;
347+
return FlutterStandardCodecHelperReadByte(&_range.location, (__bridge CFDataRef)_data);
350348
}
351349

352350
- (UInt32)readSize {
353-
UInt8 byte = [self readByte];
354-
if (byte < 254) {
355-
return (UInt32)byte;
356-
} else if (byte == 254) {
357-
UInt16 value;
358-
[self readBytes:&value length:2];
359-
return value;
360-
} else {
361-
UInt32 value;
362-
[self readBytes:&value length:4];
363-
return value;
364-
}
351+
return FlutterStandardCodecHelperReadSize(&_range.location, (__bridge CFDataRef)_data);
365352
}
366353

367354
- (NSData*)readData:(NSUInteger)length {
@@ -372,86 +359,47 @@ - (NSData*)readData:(NSUInteger)length {
372359
}
373360

374361
- (NSString*)readUTF8 {
375-
NSData* bytes = [self readData:[self readSize]];
376-
return [[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding];
362+
return (__bridge NSString*)FlutterStandardCodecHelperReadUTF8(&_range.location,
363+
(__bridge CFDataRef)_data);
377364
}
378365

379366
- (void)readAlignment:(UInt8)alignment {
380-
UInt8 mod = _range.location % alignment;
381-
if (mod) {
382-
_range.location += (alignment - mod);
383-
}
367+
FlutterStandardCodecHelperReadAlignment(&_range.location, alignment);
384368
}
385369

386-
- (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type {
387-
UInt32 elementCount = [self readSize];
388-
UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
389-
[self readAlignment:elementSize];
390-
NSData* data = [self readData:elementCount * elementSize];
391-
return [FlutterStandardTypedData typedDataWithData:data type:type];
370+
- (nullable id)readValue {
371+
return (__bridge id)ReadValue((__bridge CFTypeRef)self);
392372
}
393373

394-
- (nullable id)readValue {
395-
return [self readValueOfType:[self readByte]];
374+
static CFTypeRef ReadValue(CFTypeRef user_data) {
375+
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
376+
uint8_t type = FlutterStandardCodecHelperReadByte(&reader->_range.location,
377+
(__bridge CFDataRef)reader->_data);
378+
return (__bridge CFTypeRef)[reader readValueOfType:type];
379+
}
380+
381+
static CFTypeRef ReadTypedDataOfType(FlutterStandardField field, CFTypeRef user_data) {
382+
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
383+
unsigned long* location = &reader->_range.location;
384+
CFDataRef data = (__bridge CFDataRef)reader->_data;
385+
FlutterStandardDataType type = FlutterStandardDataTypeForField(field);
386+
387+
UInt64 elementCount = FlutterStandardCodecHelperReadSize(location, data);
388+
UInt64 elementSize = elementSizeForFlutterStandardDataType(type);
389+
FlutterStandardCodecHelperReadAlignment(location, elementSize);
390+
UInt64 length = elementCount * elementSize;
391+
NSRange range = NSMakeRange(*location, length);
392+
// Note: subdataWithRange performs better than CFDataCreate and
393+
// CFDataCreateBytesNoCopy crashes.
394+
NSData* bytes = [(__bridge NSData*)data subdataWithRange:range];
395+
*location += length;
396+
return (__bridge CFTypeRef)[FlutterStandardTypedData typedDataWithData:bytes type:type];
396397
}
397398

398399
- (nullable id)readValueOfType:(UInt8)type {
399-
FlutterStandardField field = (FlutterStandardField)type;
400-
switch (field) {
401-
case FlutterStandardFieldNil:
402-
return nil;
403-
case FlutterStandardFieldTrue:
404-
return @YES;
405-
case FlutterStandardFieldFalse:
406-
return @NO;
407-
case FlutterStandardFieldInt32: {
408-
SInt32 value;
409-
[self readBytes:&value length:4];
410-
return @(value);
411-
}
412-
case FlutterStandardFieldInt64: {
413-
SInt64 value;
414-
[self readBytes:&value length:8];
415-
return @(value);
416-
}
417-
case FlutterStandardFieldFloat64: {
418-
Float64 value;
419-
[self readAlignment:8];
420-
[self readBytes:&value length:8];
421-
return [NSNumber numberWithDouble:value];
422-
}
423-
case FlutterStandardFieldIntHex:
424-
case FlutterStandardFieldString:
425-
return [self readUTF8];
426-
case FlutterStandardFieldUInt8Data:
427-
case FlutterStandardFieldInt32Data:
428-
case FlutterStandardFieldInt64Data:
429-
case FlutterStandardFieldFloat32Data:
430-
case FlutterStandardFieldFloat64Data:
431-
return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
432-
case FlutterStandardFieldList: {
433-
UInt32 length = [self readSize];
434-
NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
435-
for (UInt32 i = 0; i < length; i++) {
436-
id value = [self readValue];
437-
[array addObject:(value == nil ? [NSNull null] : value)];
438-
}
439-
return array;
440-
}
441-
case FlutterStandardFieldMap: {
442-
UInt32 size = [self readSize];
443-
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
444-
for (UInt32 i = 0; i < size; i++) {
445-
id key = [self readValue];
446-
id val = [self readValue];
447-
[dict setObject:(val == nil ? [NSNull null] : val)
448-
forKey:(key == nil ? [NSNull null] : key)];
449-
}
450-
return dict;
451-
}
452-
default:
453-
NSAssert(NO, @"Corrupted standard message");
454-
}
400+
return (__bridge id)FlutterStandardCodecHelperReadValueOfType(
401+
&_range.location, (__bridge CFDataRef)_data, type, ReadValue, ReadTypedDataOfType,
402+
(__bridge CFTypeRef)self);
455403
}
456404
@end
457405

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
6+
#include <stdint.h>
7+
8+
void FlutterStandardCodecHelperReadAlignment(unsigned long* location,
9+
uint8_t alignment) {
10+
uint8_t mod = *location % alignment;
11+
if (mod) {
12+
*location += (alignment - mod);
13+
}
14+
}
15+
16+
static uint8_t PeekByte(unsigned long location, CFDataRef data) {
17+
uint8_t result;
18+
CFRange range = CFRangeMake(location, 1);
19+
CFDataGetBytes(data, range, &result);
20+
return result;
21+
}
22+
23+
void FlutterStandardCodecHelperReadBytes(unsigned long* location,
24+
unsigned long length,
25+
void* destination,
26+
CFDataRef data) {
27+
CFRange range = CFRangeMake(*location, length);
28+
CFDataGetBytes(data, range, destination);
29+
*location += length;
30+
}
31+
32+
uint8_t FlutterStandardCodecHelperReadByte(unsigned long* location,
33+
CFDataRef data) {
34+
uint8_t value;
35+
FlutterStandardCodecHelperReadBytes(location, 1, &value, data);
36+
return value;
37+
}
38+
39+
uint32_t FlutterStandardCodecHelperReadSize(unsigned long* location,
40+
CFDataRef data) {
41+
uint8_t byte = FlutterStandardCodecHelperReadByte(location, data);
42+
if (byte < 254) {
43+
return (uint32_t)byte;
44+
} else if (byte == 254) {
45+
UInt16 value;
46+
FlutterStandardCodecHelperReadBytes(location, 2, &value, data);
47+
return value;
48+
} else {
49+
UInt32 value;
50+
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
51+
return value;
52+
}
53+
}
54+
55+
static CFDataRef ReadDataNoCopy(unsigned long* location,
56+
unsigned long length,
57+
CFDataRef data) {
58+
CFDataRef result = CFDataCreateWithBytesNoCopy(
59+
kCFAllocatorDefault, CFDataGetBytePtr(data) + *location, length,
60+
kCFAllocatorNull);
61+
*location += length;
62+
return CFAutorelease(result);
63+
}
64+
65+
CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long* location,
66+
CFDataRef data) {
67+
uint32_t size = FlutterStandardCodecHelperReadSize(location, data);
68+
CFDataRef bytes = ReadDataNoCopy(location, size, data);
69+
CFStringRef result = CFStringCreateFromExternalRepresentation(
70+
kCFAllocatorDefault, bytes, kCFStringEncodingUTF8);
71+
return CFAutorelease(result);
72+
}
73+
74+
// Peeks ahead to see if we are reading a standard type. If so, recurse
75+
// directly to FlutterStandardCodecHelperReadValueOfType, otherwise recurse to
76+
// objc.
77+
static inline CFTypeRef FastReadValue(
78+
unsigned long* location,
79+
CFDataRef data,
80+
CFTypeRef (*ReadValue)(CFTypeRef),
81+
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
82+
CFTypeRef user_data) {
83+
uint8_t type = PeekByte(*location, data);
84+
if (FlutterStandardFieldIsStandardType(type)) {
85+
*location += 1;
86+
return FlutterStandardCodecHelperReadValueOfType(
87+
location, data, type, ReadValue, ReadTypedDataOfType, user_data);
88+
} else {
89+
return ReadValue(user_data);
90+
}
91+
}
92+
93+
CFTypeRef FlutterStandardCodecHelperReadValueOfType(
94+
unsigned long* location,
95+
CFDataRef data,
96+
uint8_t type,
97+
CFTypeRef (*ReadValue)(CFTypeRef),
98+
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
99+
CFTypeRef user_data) {
100+
FlutterStandardField field = (FlutterStandardField)type;
101+
switch (field) {
102+
case FlutterStandardFieldNil:
103+
return nil;
104+
case FlutterStandardFieldTrue:
105+
return kCFBooleanTrue;
106+
case FlutterStandardFieldFalse:
107+
return kCFBooleanFalse;
108+
case FlutterStandardFieldInt32: {
109+
int32_t value;
110+
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
111+
return CFAutorelease(
112+
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value));
113+
}
114+
case FlutterStandardFieldInt64: {
115+
int64_t value;
116+
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
117+
return CFAutorelease(
118+
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value));
119+
}
120+
case FlutterStandardFieldFloat64: {
121+
Float64 value;
122+
FlutterStandardCodecHelperReadAlignment(location, 8);
123+
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
124+
return CFAutorelease(
125+
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
126+
}
127+
case FlutterStandardFieldIntHex:
128+
case FlutterStandardFieldString:
129+
return FlutterStandardCodecHelperReadUTF8(location, data);
130+
case FlutterStandardFieldUInt8Data:
131+
case FlutterStandardFieldInt32Data:
132+
case FlutterStandardFieldInt64Data:
133+
case FlutterStandardFieldFloat32Data:
134+
case FlutterStandardFieldFloat64Data:
135+
return ReadTypedDataOfType(field, user_data);
136+
case FlutterStandardFieldList: {
137+
UInt32 length = FlutterStandardCodecHelperReadSize(location, data);
138+
CFMutableArrayRef array = CFArrayCreateMutable(
139+
kCFAllocatorDefault, length, &kCFTypeArrayCallBacks);
140+
for (UInt32 i = 0; i < length; i++) {
141+
CFTypeRef value = FastReadValue(location, data, ReadValue,
142+
ReadTypedDataOfType, user_data);
143+
CFArrayAppendValue(array, (value == nil ? kCFNull : value));
144+
}
145+
return CFAutorelease(array);
146+
}
147+
case FlutterStandardFieldMap: {
148+
UInt32 size = FlutterStandardCodecHelperReadSize(location, data);
149+
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
150+
kCFAllocatorDefault, size, &kCFTypeDictionaryKeyCallBacks,
151+
&kCFTypeDictionaryValueCallBacks);
152+
for (UInt32 i = 0; i < size; i++) {
153+
CFTypeRef key = FastReadValue(location, data, ReadValue,
154+
ReadTypedDataOfType, user_data);
155+
CFTypeRef val = FastReadValue(location, data, ReadValue,
156+
ReadTypedDataOfType, user_data);
157+
CFDictionaryAddValue(dict, (key == nil ? kCFNull : key),
158+
(val == nil ? kCFNull : val));
159+
}
160+
return CFAutorelease(dict);
161+
}
162+
default:
163+
// Malformed message.
164+
assert(false);
165+
}
166+
}

0 commit comments

Comments
 (0)