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

Sped up reading with FlutterStandardCodec. #38327

Merged
merged 5 commits into from
Dec 16, 2022
Merged
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
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,8 @@ ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCh
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4872,6 +4874,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChan
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.mm
Expand Down
1 change: 1 addition & 0 deletions shell/platform/darwin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ source_set("flutter_channels_arc") {
"common/framework/Source/FlutterChannels.mm",
"common/framework/Source/FlutterCodecs.mm",
"common/framework/Source/FlutterStandardCodec.mm",
"common/framework/Source/FlutterStandardCodecHelper.c",
"common/framework/Source/FlutterStandardCodec_Internal.h",
]

Expand Down
1 change: 1 addition & 0 deletions shell/platform/darwin/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ source_set("framework_shared") {
"framework/Source/FlutterChannels.mm",
"framework/Source/FlutterCodecs.mm",
"framework/Source/FlutterStandardCodec.mm",
"framework/Source/FlutterStandardCodecHelper.c",
"framework/Source/FlutterStandardCodec_Internal.h",
]

Expand Down
124 changes: 36 additions & 88 deletions shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h"

FLUTTER_ASSERT_ARC
Expand Down Expand Up @@ -338,30 +339,16 @@ - (BOOL)hasMore {
}

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

- (UInt8)readByte {
UInt8 value;
[self readBytes:&value length:1];
return value;
return FlutterStandardCodecHelperReadByte(&_range.location, (__bridge CFDataRef)_data);
}

- (UInt32)readSize {
UInt8 byte = [self readByte];
if (byte < 254) {
return (UInt32)byte;
} else if (byte == 254) {
UInt16 value;
[self readBytes:&value length:2];
return value;
} else {
UInt32 value;
[self readBytes:&value length:4];
return value;
}
return FlutterStandardCodecHelperReadSize(&_range.location, (__bridge CFDataRef)_data);
}

- (NSData*)readData:(NSUInteger)length {
Expand All @@ -372,86 +359,47 @@ - (NSData*)readData:(NSUInteger)length {
}

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

- (void)readAlignment:(UInt8)alignment {
UInt8 mod = _range.location % alignment;
if (mod) {
_range.location += (alignment - mod);
}
FlutterStandardCodecHelperReadAlignment(&_range.location, alignment);
}

- (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type {
UInt32 elementCount = [self readSize];
UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
[self readAlignment:elementSize];
NSData* data = [self readData:elementCount * elementSize];
return [FlutterStandardTypedData typedDataWithData:data type:type];
- (nullable id)readValue {
return (__bridge id)ReadValue((__bridge CFTypeRef)self);
}

- (nullable id)readValue {
return [self readValueOfType:[self readByte]];
static CFTypeRef ReadValue(CFTypeRef user_data) {
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
uint8_t type = FlutterStandardCodecHelperReadByte(&reader->_range.location,
(__bridge CFDataRef)reader->_data);
return (__bridge CFTypeRef)[reader readValueOfType:type];
}

static CFTypeRef ReadTypedDataOfType(FlutterStandardField field, CFTypeRef user_data) {
FlutterStandardReader* reader = (__bridge FlutterStandardReader*)user_data;
unsigned long* location = &reader->_range.location;
CFDataRef data = (__bridge CFDataRef)reader->_data;
FlutterStandardDataType type = FlutterStandardDataTypeForField(field);

UInt64 elementCount = FlutterStandardCodecHelperReadSize(location, data);
UInt64 elementSize = elementSizeForFlutterStandardDataType(type);
FlutterStandardCodecHelperReadAlignment(location, elementSize);
UInt64 length = elementCount * elementSize;
NSRange range = NSMakeRange(*location, length);
// Note: subdataWithRange performs better than CFDataCreate and
// CFDataCreateBytesNoCopy crashes.
NSData* bytes = [(__bridge NSData*)data subdataWithRange:range];
*location += length;
return (__bridge CFTypeRef)[FlutterStandardTypedData typedDataWithData:bytes type:type];
}

- (nullable id)readValueOfType:(UInt8)type {
FlutterStandardField field = (FlutterStandardField)type;
switch (field) {
case FlutterStandardFieldNil:
return nil;
case FlutterStandardFieldTrue:
return @YES;
case FlutterStandardFieldFalse:
return @NO;
case FlutterStandardFieldInt32: {
SInt32 value;
[self readBytes:&value length:4];
return @(value);
}
case FlutterStandardFieldInt64: {
SInt64 value;
[self readBytes:&value length:8];
return @(value);
}
case FlutterStandardFieldFloat64: {
Float64 value;
[self readAlignment:8];
[self readBytes:&value length:8];
return [NSNumber numberWithDouble:value];
}
case FlutterStandardFieldIntHex:
case FlutterStandardFieldString:
return [self readUTF8];
case FlutterStandardFieldUInt8Data:
case FlutterStandardFieldInt32Data:
case FlutterStandardFieldInt64Data:
case FlutterStandardFieldFloat32Data:
case FlutterStandardFieldFloat64Data:
return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
case FlutterStandardFieldList: {
UInt32 length = [self readSize];
NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
for (UInt32 i = 0; i < length; i++) {
id value = [self readValue];
[array addObject:(value == nil ? [NSNull null] : value)];
}
return array;
}
case FlutterStandardFieldMap: {
UInt32 size = [self readSize];
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
for (UInt32 i = 0; i < size; i++) {
id key = [self readValue];
id val = [self readValue];
[dict setObject:(val == nil ? [NSNull null] : val)
forKey:(key == nil ? [NSNull null] : key)];
}
return dict;
}
default:
NSAssert(NO, @"Corrupted standard message");
}
return (__bridge id)FlutterStandardCodecHelperReadValueOfType(
&_range.location, (__bridge CFDataRef)_data, type, ReadValue, ReadTypedDataOfType,
(__bridge CFTypeRef)self);
}
@end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h"
#include <stdint.h>

void FlutterStandardCodecHelperReadAlignment(unsigned long* location,
uint8_t alignment) {
uint8_t mod = *location % alignment;
if (mod) {
*location += (alignment - mod);
}
}

static uint8_t PeekByte(unsigned long location, CFDataRef data) {
uint8_t result;
CFRange range = CFRangeMake(location, 1);
CFDataGetBytes(data, range, &result);
return result;
}

void FlutterStandardCodecHelperReadBytes(unsigned long* location,
unsigned long length,
void* destination,
CFDataRef data) {
CFRange range = CFRangeMake(*location, length);
CFDataGetBytes(data, range, destination);
*location += length;
}

uint8_t FlutterStandardCodecHelperReadByte(unsigned long* location,
CFDataRef data) {
uint8_t value;
FlutterStandardCodecHelperReadBytes(location, 1, &value, data);
return value;
}

uint32_t FlutterStandardCodecHelperReadSize(unsigned long* location,
CFDataRef data) {
uint8_t byte = FlutterStandardCodecHelperReadByte(location, data);
if (byte < 254) {
return (uint32_t)byte;
} else if (byte == 254) {
UInt16 value;
FlutterStandardCodecHelperReadBytes(location, 2, &value, data);
return value;
} else {
UInt32 value;
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
return value;
}
}

static CFDataRef ReadDataNoCopy(unsigned long* location,
unsigned long length,
CFDataRef data) {
CFDataRef result = CFDataCreateWithBytesNoCopy(
kCFAllocatorDefault, CFDataGetBytePtr(data) + *location, length,
kCFAllocatorNull);
*location += length;
return CFAutorelease(result);
}

CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long* location,
CFDataRef data) {
uint32_t size = FlutterStandardCodecHelperReadSize(location, data);
CFDataRef bytes = ReadDataNoCopy(location, size, data);
CFStringRef result = CFStringCreateFromExternalRepresentation(
kCFAllocatorDefault, bytes, kCFStringEncodingUTF8);
return CFAutorelease(result);
}

// Peeks ahead to see if we are reading a standard type. If so, recurse
// directly to FlutterStandardCodecHelperReadValueOfType, otherwise recurse to
// objc.
static inline CFTypeRef FastReadValue(
unsigned long* location,
CFDataRef data,
CFTypeRef (*ReadValue)(CFTypeRef),
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
CFTypeRef user_data) {
uint8_t type = PeekByte(*location, data);
if (FlutterStandardFieldIsStandardType(type)) {
*location += 1;
return FlutterStandardCodecHelperReadValueOfType(
location, data, type, ReadValue, ReadTypedDataOfType, user_data);
} else {
return ReadValue(user_data);
}
}

CFTypeRef FlutterStandardCodecHelperReadValueOfType(
unsigned long* location,
CFDataRef data,
uint8_t type,
CFTypeRef (*ReadValue)(CFTypeRef),
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
CFTypeRef user_data) {
FlutterStandardField field = (FlutterStandardField)type;
switch (field) {
case FlutterStandardFieldNil:
return nil;
case FlutterStandardFieldTrue:
return kCFBooleanTrue;
case FlutterStandardFieldFalse:
return kCFBooleanFalse;
case FlutterStandardFieldInt32: {
int32_t value;
FlutterStandardCodecHelperReadBytes(location, 4, &value, data);
return CFAutorelease(
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value));
}
case FlutterStandardFieldInt64: {
int64_t value;
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
return CFAutorelease(
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value));
}
case FlutterStandardFieldFloat64: {
Float64 value;
FlutterStandardCodecHelperReadAlignment(location, 8);
FlutterStandardCodecHelperReadBytes(location, 8, &value, data);
return CFAutorelease(
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
}
case FlutterStandardFieldIntHex:
case FlutterStandardFieldString:
return FlutterStandardCodecHelperReadUTF8(location, data);
case FlutterStandardFieldUInt8Data:
case FlutterStandardFieldInt32Data:
case FlutterStandardFieldInt64Data:
case FlutterStandardFieldFloat32Data:
case FlutterStandardFieldFloat64Data:
return ReadTypedDataOfType(field, user_data);
case FlutterStandardFieldList: {
UInt32 length = FlutterStandardCodecHelperReadSize(location, data);
CFMutableArrayRef array = CFArrayCreateMutable(
kCFAllocatorDefault, length, &kCFTypeArrayCallBacks);
for (UInt32 i = 0; i < length; i++) {
CFTypeRef value = FastReadValue(location, data, ReadValue,
ReadTypedDataOfType, user_data);
CFArrayAppendValue(array, (value == nil ? kCFNull : value));
}
return CFAutorelease(array);
}
case FlutterStandardFieldMap: {
UInt32 size = FlutterStandardCodecHelperReadSize(location, data);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, size, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
for (UInt32 i = 0; i < size; i++) {
CFTypeRef key = FastReadValue(location, data, ReadValue,
ReadTypedDataOfType, user_data);
CFTypeRef val = FastReadValue(location, data, ReadValue,
ReadTypedDataOfType, user_data);
CFDictionaryAddValue(dict, (key == nil ? kCFNull : key),
(val == nil ? kCFNull : val));
}
return CFAutorelease(dict);
}
default:
// Malformed message.
assert(false);
}
}
Loading