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

Commit 54407e1

Browse files
committed
Sped up reading with FlutterStandardCodec.
1 parent a7ec07f commit 54407e1

File tree

7 files changed

+296
-108
lines changed

7 files changed

+296
-108
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4872,6 +4872,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChan
48724872
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m
48734873
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm
48744874
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
4875+
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c
4876+
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h
48754877
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
48764878
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
48774879
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: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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+
static bool IsStandardType(uint8_t type) {
24+
switch (type) {
25+
case FlutterStandardFieldNil:
26+
case FlutterStandardFieldTrue:
27+
case FlutterStandardFieldFalse:
28+
case FlutterStandardFieldInt32:
29+
case FlutterStandardFieldInt64:
30+
case FlutterStandardFieldIntHex:
31+
case FlutterStandardFieldFloat64:
32+
case FlutterStandardFieldString:
33+
case FlutterStandardFieldUInt8Data:
34+
case FlutterStandardFieldInt32Data:
35+
case FlutterStandardFieldInt64Data:
36+
case FlutterStandardFieldFloat64Data:
37+
case FlutterStandardFieldList:
38+
case FlutterStandardFieldMap:
39+
case FlutterStandardFieldFloat32Data:
40+
return true;
41+
default:
42+
return false;
43+
}
44+
}
45+
46+
void FlutterStandardCodecHelperReadBytes(unsigned long* location,
47+
unsigned long length,
48+
void* destination,
49+
CFDataRef data) {
50+
CFRange range = CFRangeMake(*location, length);
51+
CFDataGetBytes(data, range, destination);
52+
*location += length;
53+
}
54+
55+
uint8_t FlutterStandardCodecHelperReadByte(unsigned long* location,
56+
CFDataRef data) {
57+
uint8_t value;
58+
FlutterStandardCodecHelperReadBytes(location, 1, &value, data);
59+
return value;
60+
}
61+
62+
uint32_t FlutterStandardCodecHelperReadSize(unsigned long* location,
63+
CFDataRef data) {
64+
uint8_t byte = FlutterStandardCodecHelperReadByte(location, data);
65+
if (byte < 254) {
66+
return (uint32_t)byte;
67+
} else if (byte == 254) {
68+
UInt16 value;
69+
FlutterStandardCodecHelperReadBytes(location, 2, &value, data);
70+
return value;
71+
} else {
72+
UInt32 value;
73+
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
74+
return value;
75+
}
76+
}
77+
78+
static CFDataRef ReadDataNoCopy(unsigned long* location,
79+
unsigned long length,
80+
CFDataRef data) {
81+
CFDataRef result = CFDataCreateWithBytesNoCopy(
82+
kCFAllocatorDefault, CFDataGetBytePtr(data) + *location, length,
83+
kCFAllocatorNull);
84+
*location += length;
85+
return CFAutorelease(result);
86+
}
87+
88+
CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long* location,
89+
CFDataRef data) {
90+
uint32_t size = FlutterStandardCodecHelperReadSize(location, data);
91+
CFDataRef bytes = ReadDataNoCopy(location, size, data);
92+
CFStringRef result = CFStringCreateFromExternalRepresentation(
93+
kCFAllocatorDefault, bytes, kCFStringEncodingUTF8);
94+
return CFAutorelease(result);
95+
}
96+
97+
// Peeks ahead to see if we are reading a standard type. If so, recurse
98+
// directly to FlutterStandardCodecHelperReadValueOfType, otherwise recurse to
99+
// objc.
100+
static inline CFTypeRef FastReadValue(
101+
unsigned long* location,
102+
CFDataRef data,
103+
CFTypeRef (*ReadValue)(CFTypeRef),
104+
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
105+
CFTypeRef user_data) {
106+
uint8_t type = PeekByte(*location, data);
107+
if (IsStandardType(type)) {
108+
*location += 1;
109+
return FlutterStandardCodecHelperReadValueOfType(
110+
location, data, type, ReadValue, ReadTypedDataOfType, user_data);
111+
} else {
112+
return ReadValue(user_data);
113+
}
114+
}
115+
116+
CFTypeRef FlutterStandardCodecHelperReadValueOfType(
117+
unsigned long* location,
118+
CFDataRef data,
119+
uint8_t type,
120+
CFTypeRef (*ReadValue)(CFTypeRef),
121+
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
122+
CFTypeRef user_data) {
123+
FlutterStandardField field = (FlutterStandardField)type;
124+
switch (field) {
125+
case FlutterStandardFieldNil:
126+
return nil;
127+
case FlutterStandardFieldTrue:
128+
return kCFBooleanTrue;
129+
case FlutterStandardFieldFalse:
130+
return kCFBooleanFalse;
131+
case FlutterStandardFieldInt32: {
132+
int32_t value;
133+
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
134+
return CFAutorelease(
135+
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value));
136+
}
137+
case FlutterStandardFieldInt64: {
138+
int64_t value;
139+
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
140+
return CFAutorelease(
141+
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value));
142+
}
143+
case FlutterStandardFieldFloat64: {
144+
Float64 value;
145+
FlutterStandardCodecHelperReadAlignment(location, 8);
146+
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
147+
return CFAutorelease(
148+
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
149+
}
150+
case FlutterStandardFieldIntHex:
151+
case FlutterStandardFieldString:
152+
return FlutterStandardCodecHelperReadUTF8(location, data);
153+
case FlutterStandardFieldUInt8Data:
154+
case FlutterStandardFieldInt32Data:
155+
case FlutterStandardFieldInt64Data:
156+
case FlutterStandardFieldFloat32Data:
157+
case FlutterStandardFieldFloat64Data:
158+
return ReadTypedDataOfType(field, user_data);
159+
case FlutterStandardFieldList: {
160+
UInt32 length = FlutterStandardCodecHelperReadSize(location, data);
161+
CFMutableArrayRef array = CFArrayCreateMutable(
162+
kCFAllocatorDefault, length, &kCFTypeArrayCallBacks);
163+
for (UInt32 i = 0; i < length; i++) {
164+
CFTypeRef value = FastReadValue(location, data, ReadValue,
165+
ReadTypedDataOfType, user_data);
166+
CFArrayAppendValue(array, (value == nil ? kCFNull : value));
167+
}
168+
return CFAutorelease(array);
169+
}
170+
case FlutterStandardFieldMap: {
171+
UInt32 size = FlutterStandardCodecHelperReadSize(location, data);
172+
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
173+
kCFAllocatorDefault, size, &kCFTypeDictionaryKeyCallBacks,
174+
&kCFTypeDictionaryValueCallBacks);
175+
for (UInt32 i = 0; i < size; i++) {
176+
CFTypeRef key = FastReadValue(location, data, ReadValue,
177+
ReadTypedDataOfType, user_data);
178+
CFTypeRef val = FastReadValue(location, data, ReadValue,
179+
ReadTypedDataOfType, user_data);
180+
CFDictionaryAddValue(dict, (key == nil ? kCFNull : key),
181+
(val == nil ? kCFNull : val));
182+
}
183+
return CFAutorelease(dict);
184+
}
185+
default:
186+
// Malformed message.
187+
assert(false);
188+
}
189+
}

0 commit comments

Comments
 (0)