diff --git a/objectivec/GPBUnknownField.m b/objectivec/GPBUnknownField.m index f98de4ca5a..8ef9b10644 100644 --- a/objectivec/GPBUnknownField.m +++ b/objectivec/GPBUnknownField.m @@ -6,13 +6,13 @@ // https://developers.google.com/open-source/licenses/bsd #import "GPBUnknownField.h" -#import "GPBUnknownField_PackagePrivate.h" -#import "GPBWireFormat.h" #import "GPBArray.h" #import "GPBCodedOutputStream_PackagePrivate.h" #import "GPBUnknownFieldSet.h" +#import "GPBUnknownField_PackagePrivate.h" #import "GPBUnknownFields_PackagePrivate.h" +#import "GPBWireFormat.h" #define ASSERT_FIELD_TYPE(type) \ if (type_ != type) { \ @@ -20,24 +20,7 @@ format:@"GPBUnknownField is the wrong type"]; \ } -@implementation GPBUnknownField { - @protected - int32_t number_; - GPBUnknownFieldType type_; - - union { - uint64_t intValue; // type == Varint, Fixed32, Fixed64 - NSData *lengthDelimited; // type == LengthDelimited - GPBUnknownFields *group; // type == Group - struct { // type == Legacy - GPBUInt64Array *mutableVarintList; - GPBUInt32Array *mutableFixed32List; - GPBUInt64Array *mutableFixed64List; - NSMutableArray *mutableLengthDelimitedList; - NSMutableArray *mutableGroupList; - } legacy; - } storage_; -} +@implementation GPBUnknownField @synthesize number = number_; @synthesize type = type_; @@ -289,90 +272,57 @@ } - (void)writeToOutput:(GPBCodedOutputStream *)output { - switch (type_) { - case GPBUnknownFieldTypeVarint: - [output writeUInt64:number_ value:storage_.intValue]; - break; - case GPBUnknownFieldTypeFixed32: - [output writeFixed32:number_ value:(uint32_t)storage_.intValue]; - break; - case GPBUnknownFieldTypeFixed64: - [output writeFixed64:number_ value:storage_.intValue]; - break; - case GPBUnknownFieldTypeLengthDelimited: - [output writeBytes:number_ value:storage_.lengthDelimited]; - break; - case GPBUnknownFieldTypeGroup: - [output writeRawVarint32:GPBWireFormatMakeTag(number_, GPBWireFormatStartGroup)]; - [storage_.group writeToCodedOutputStream:output]; - [output writeRawVarint32:GPBWireFormatMakeTag(number_, GPBWireFormatEndGroup)]; - break; - case GPBUnknownFieldTypeLegacy: { - NSUInteger count = storage_.legacy.mutableVarintList.count; - if (count > 0) { - [output writeUInt64Array:number_ values:storage_.legacy.mutableVarintList tag:0]; - } - count = storage_.legacy.mutableFixed32List.count; - if (count > 0) { - [output writeFixed32Array:number_ values:storage_.legacy.mutableFixed32List tag:0]; - } - count = storage_.legacy.mutableFixed64List.count; - if (count > 0) { - [output writeFixed64Array:number_ values:storage_.legacy.mutableFixed64List tag:0]; - } - count = storage_.legacy.mutableLengthDelimitedList.count; - if (count > 0) { - [output writeBytesArray:number_ values:storage_.legacy.mutableLengthDelimitedList]; - } - count = storage_.legacy.mutableGroupList.count; - if (count > 0) { - [output writeUnknownGroupArray:number_ values:storage_.legacy.mutableGroupList]; - } - } + ASSERT_FIELD_TYPE(GPBUnknownFieldTypeLegacy); + NSUInteger count = storage_.legacy.mutableVarintList.count; + if (count > 0) { + [output writeUInt64Array:number_ values:storage_.legacy.mutableVarintList tag:0]; + } + count = storage_.legacy.mutableFixed32List.count; + if (count > 0) { + [output writeFixed32Array:number_ values:storage_.legacy.mutableFixed32List tag:0]; + } + count = storage_.legacy.mutableFixed64List.count; + if (count > 0) { + [output writeFixed64Array:number_ values:storage_.legacy.mutableFixed64List tag:0]; + } + count = storage_.legacy.mutableLengthDelimitedList.count; + if (count > 0) { + [output writeBytesArray:number_ values:storage_.legacy.mutableLengthDelimitedList]; + } + count = storage_.legacy.mutableGroupList.count; + if (count > 0) { + [output writeUnknownGroupArray:number_ values:storage_.legacy.mutableGroupList]; } } - (size_t)serializedSize { - switch (type_) { - case GPBUnknownFieldTypeVarint: - return GPBComputeUInt64Size(number_, storage_.intValue); - case GPBUnknownFieldTypeFixed32: - return GPBComputeFixed32Size(number_, (uint32_t)storage_.intValue); - case GPBUnknownFieldTypeFixed64: - return GPBComputeFixed64Size(number_, storage_.intValue); - case GPBUnknownFieldTypeLengthDelimited: - return GPBComputeBytesSize(number_, storage_.lengthDelimited); - case GPBUnknownFieldTypeGroup: - return (GPBComputeTagSize(number_) * 2) + [storage_.group serializedSize]; - case GPBUnknownFieldTypeLegacy: { - __block size_t result = 0; - int32_t number = number_; - [storage_.legacy.mutableVarintList - enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeUInt64Size(number, value); - }]; - - [storage_.legacy.mutableFixed32List - enumerateValuesWithBlock:^(uint32_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeFixed32Size(number, value); - }]; - - [storage_.legacy.mutableFixed64List - enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeFixed64Size(number, value); - }]; - - for (NSData *data in storage_.legacy.mutableLengthDelimitedList) { - result += GPBComputeBytesSize(number, data); - } + ASSERT_FIELD_TYPE(GPBUnknownFieldTypeLegacy); + __block size_t result = 0; + int32_t number = number_; + [storage_.legacy.mutableVarintList + enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeUInt64Size(number, value); + }]; + + [storage_.legacy.mutableFixed32List + enumerateValuesWithBlock:^(uint32_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeFixed32Size(number, value); + }]; + + [storage_.legacy.mutableFixed64List + enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeFixed64Size(number, value); + }]; - for (GPBUnknownFieldSet *set in storage_.legacy.mutableGroupList) { - result += GPBComputeUnknownGroupSize(number, set); - } + for (NSData *data in storage_.legacy.mutableLengthDelimitedList) { + result += GPBComputeBytesSize(number, data); + } - return result; - } + for (GPBUnknownFieldSet *set in storage_.legacy.mutableGroupList) { + result += GPBComputeUnknownGroupSize(number, set); } + + return result; } - (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output { diff --git a/objectivec/GPBUnknownField_PackagePrivate.h b/objectivec/GPBUnknownField_PackagePrivate.h index e95358f9d2..117dcb9018 100644 --- a/objectivec/GPBUnknownField_PackagePrivate.h +++ b/objectivec/GPBUnknownField_PackagePrivate.h @@ -11,7 +11,24 @@ @class GPBCodedOutputStream; -@interface GPBUnknownField () +@interface GPBUnknownField () { + @package + int32_t number_; + GPBUnknownFieldType type_; + + union { + uint64_t intValue; // type == Varint, Fixed32, Fixed64 + NSData *_Nonnull lengthDelimited; // type == LengthDelimited + GPBUnknownFields *_Nonnull group; // type == Group + struct { // type == Legacy + GPBUInt64Array *_Null_unspecified mutableVarintList; + GPBUInt32Array *_Null_unspecified mutableFixed32List; + GPBUInt64Array *_Null_unspecified mutableFixed64List; + NSMutableArray *_Null_unspecified mutableLengthDelimitedList; + NSMutableArray *_Null_unspecified mutableGroupList; + } legacy; + } storage_; +} - (nonnull instancetype)initWithNumber:(int32_t)number varint:(uint64_t)varint; - (nonnull instancetype)initWithNumber:(int32_t)number fixed32:(uint32_t)fixed32; diff --git a/objectivec/GPBUnknownFields.m b/objectivec/GPBUnknownFields.m index ee33de1884..e24e07b416 100644 --- a/objectivec/GPBUnknownFields.m +++ b/objectivec/GPBUnknownFields.m @@ -24,14 +24,15 @@ [NSException raise:NSInvalidArgumentException format:@"Not a valid field number."]; \ } -@interface GPBUnknownFields () -- (BOOL)mergeFromInputStream:(nonnull GPBCodedInputStream *)input endTag:(uint32_t)endTag; -@end +// TODO: Consider using on other functions to reduce bloat when +// some compiler optimizations are enabled. +#define GPB_NOINLINE __attribute__((noinline)) -@implementation GPBUnknownFields { +@interface GPBUnknownFields () { @package NSMutableArray *fields_; } +@end // Direct access is use for speed, to avoid even internally declaring things // read/write, etc. The warning is enabled in the project to ensure code calling @@ -39,6 +40,157 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdirect-ivar-access" +GPB_NOINLINE +static size_t ComputeSerializeSize(GPBUnknownFields *_Nonnull self) { + size_t result = 0; + for (GPBUnknownField *field in self->fields_) { + uint32_t fieldNumber = field->number_; + switch (field->type_) { + case GPBUnknownFieldTypeVarint: + result += GPBComputeUInt64Size(fieldNumber, field->storage_.intValue); + break; + case GPBUnknownFieldTypeFixed32: + result += GPBComputeFixed32Size(fieldNumber, (uint32_t)field->storage_.intValue); + break; + case GPBUnknownFieldTypeFixed64: + result += GPBComputeFixed64Size(fieldNumber, field->storage_.intValue); + break; + case GPBUnknownFieldTypeLengthDelimited: + result += GPBComputeBytesSize(fieldNumber, field->storage_.lengthDelimited); + break; + case GPBUnknownFieldTypeGroup: + result += + (GPBComputeTagSize(fieldNumber) * 2) + ComputeSerializeSize(field->storage_.group); + break; + case GPBUnknownFieldTypeLegacy: +#if defined(DEBUG) && DEBUG + NSCAssert(NO, @"Internal error within the library"); +#endif + break; + } + } + return result; +} + +GPB_NOINLINE +static void WriteToCoddedOutputStream(GPBUnknownFields *_Nonnull self, + GPBCodedOutputStream *_Nonnull output) { + for (GPBUnknownField *field in self->fields_) { + uint32_t fieldNumber = field->number_; + switch (field->type_) { + case GPBUnknownFieldTypeVarint: + [output writeUInt64:fieldNumber value:field->storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed32: + [output writeFixed32:fieldNumber value:(uint32_t)field->storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed64: + [output writeFixed64:fieldNumber value:field->storage_.intValue]; + break; + case GPBUnknownFieldTypeLengthDelimited: + [output writeBytes:fieldNumber value:field->storage_.lengthDelimited]; + break; + case GPBUnknownFieldTypeGroup: + [output writeRawVarint32:GPBWireFormatMakeTag(fieldNumber, GPBWireFormatStartGroup)]; + WriteToCoddedOutputStream(field->storage_.group, output); + [output writeRawVarint32:GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)]; + break; + case GPBUnknownFieldTypeLegacy: +#if defined(DEBUG) && DEBUG + NSCAssert(NO, @"Internal error within the library"); +#endif + break; + } + } +} + +GPB_NOINLINE +static BOOL MergeFromInputStream(GPBUnknownFields *self, GPBCodedInputStream *input, + uint32_t endTag) { +#if defined(DEBUG) && DEBUG + NSCAssert(endTag == 0 || GPBWireFormatGetTagWireType(endTag) == GPBWireFormatEndGroup, + @"Internal error:Invalid end tag: %u", endTag); +#endif + GPBCodedInputStreamState *state = &input->state_; + NSMutableArray *fields = self->fields_; + @try { + while (YES) { + uint32_t tag = GPBCodedInputStreamReadTag(state); + if (tag == endTag) { + return YES; + } + if (tag == 0) { + // Reached end of input without finding the end tag. + return NO; + } + GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag); + int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag); + switch (wireType) { + case GPBWireFormatVarint: { + uint64_t value = GPBCodedInputStreamReadInt64(state); + GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber + varint:value]; + [fields addObject:field]; + [field release]; + break; + } + case GPBWireFormatFixed32: { + uint32_t value = GPBCodedInputStreamReadFixed32(state); + GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber + fixed32:value]; + [fields addObject:field]; + [field release]; + break; + } + case GPBWireFormatFixed64: { + uint64_t value = GPBCodedInputStreamReadFixed64(state); + GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber + fixed64:value]; + [fields addObject:field]; + [field release]; + break; + } + case GPBWireFormatLengthDelimited: { + NSData *data = GPBCodedInputStreamReadRetainedBytes(state); + GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber + lengthDelimited:data]; + [fields addObject:field]; + [field release]; + [data release]; + break; + } + case GPBWireFormatStartGroup: { + GPBUnknownFields *group = [[GPBUnknownFields alloc] init]; + GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber group:group]; + [fields addObject:field]; + [field release]; + [group release]; // Still will be held in the field/fields. + uint32_t endGroupTag = GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup); + if (MergeFromInputStream(group, input, endGroupTag)) { + GPBCodedInputStreamCheckLastTagWas(state, endGroupTag); + } else { + [NSException + raise:NSInternalInconsistencyException + format:@"Internal error: Unknown field data for nested group was malformed."]; + } + break; + } + case GPBWireFormatEndGroup: + [NSException raise:NSInternalInconsistencyException + format:@"Unexpected end group tag: %u", tag]; + break; + } + } + } @catch (NSException *exception) { +#if defined(DEBUG) && DEBUG + NSLog(@"%@: Internal exception while parsing unknown data, this shouldn't happen!: %@", + [self class], exception); +#endif + } +} + +@implementation GPBUnknownFields + - (instancetype)initFromMessage:(nonnull GPBMessage *)message { self = [super init]; if (self) { @@ -50,7 +202,7 @@ GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:[legacyUnknownFields data]]; // Parse until the end of the data (tag will be zero). - if (![self mergeFromInputStream:input endTag:0]) { + if (!MergeFromInputStream(self, input, 0)) { [input release]; [self release]; [NSException raise:NSInternalInconsistencyException @@ -177,29 +329,15 @@ #pragma mark - Internal Methods -- (size_t)serializedSize { - size_t result = 0; - for (GPBUnknownField *field in self->fields_) { - result += [field serializedSize]; - } - return result; -} - -- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { - for (GPBUnknownField *field in fields_) { - [field writeToOutput:output]; - } -} - - (NSData *)serializeAsData { if (fields_.count == 0) { return [NSData data]; } - size_t expectedSize = [self serializedSize]; + size_t expectedSize = ComputeSerializeSize(self); NSMutableData *data = [NSMutableData dataWithLength:expectedSize]; GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data]; @try { - [self writeToCodedOutputStream:stream]; + WriteToCoddedOutputStream(self, stream); [stream flush]; } @catch (NSException *exception) { #if defined(DEBUG) && DEBUG @@ -213,88 +351,6 @@ return data; } -- (BOOL)mergeFromInputStream:(nonnull GPBCodedInputStream *)input endTag:(uint32_t)endTag { -#if defined(DEBUG) && DEBUG - NSAssert(endTag == 0 || GPBWireFormatGetTagWireType(endTag) == GPBWireFormatEndGroup, - @"Internal error:Invalid end tag: %u", endTag); -#endif - GPBCodedInputStreamState *state = &input->state_; - @try { - while (YES) { - uint32_t tag = GPBCodedInputStreamReadTag(state); - if (tag == endTag) { - return YES; - } - if (tag == 0) { - // Reached end of input without finding the end tag. - return NO; - } - GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag); - int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag); - switch (wireType) { - case GPBWireFormatVarint: { - uint64_t value = GPBCodedInputStreamReadInt64(state); - GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber - varint:value]; - [fields_ addObject:field]; - [field release]; - break; - } - case GPBWireFormatFixed32: { - uint32_t value = GPBCodedInputStreamReadFixed32(state); - GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber - fixed32:value]; - [fields_ addObject:field]; - [field release]; - break; - } - case GPBWireFormatFixed64: { - uint64_t value = GPBCodedInputStreamReadFixed64(state); - GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber - fixed64:value]; - [fields_ addObject:field]; - [field release]; - break; - } - case GPBWireFormatLengthDelimited: { - NSData *data = GPBCodedInputStreamReadRetainedBytes(state); - GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber - lengthDelimited:data]; - [fields_ addObject:field]; - [field release]; - [data release]; - break; - } - case GPBWireFormatStartGroup: { - GPBUnknownFields *group = [[GPBUnknownFields alloc] init]; - GPBUnknownField *field = [[GPBUnknownField alloc] initWithNumber:fieldNumber group:group]; - [fields_ addObject:field]; - [field release]; - [group release]; // Still will be held in the field/fields_. - uint32_t endGroupTag = GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup); - if ([group mergeFromInputStream:input endTag:endGroupTag]) { - GPBCodedInputStreamCheckLastTagWas(state, endGroupTag); - } else { - [NSException - raise:NSInternalInconsistencyException - format:@"Internal error: Unknown field data for nested group was malformed."]; - } - break; - } - case GPBWireFormatEndGroup: - [NSException raise:NSInternalInconsistencyException - format:@"Unexpected end group tag: %u", tag]; - break; - } - } - } @catch (NSException *exception) { -#if defined(DEBUG) && DEBUG - NSLog(@"%@: Internal exception while parsing unknown data, this shouldn't happen!: %@", - [self class], exception); -#endif - } -} - @end @implementation GPBUnknownFields (AccessHelpers) @@ -352,6 +408,6 @@ return nil; } -#pragma clang diagnostic pop - @end + +#pragma clang diagnostic pop diff --git a/objectivec/GPBUnknownFields_PackagePrivate.h b/objectivec/GPBUnknownFields_PackagePrivate.h index dc63d3a217..ba2f251252 100644 --- a/objectivec/GPBUnknownFields_PackagePrivate.h +++ b/objectivec/GPBUnknownFields_PackagePrivate.h @@ -13,8 +13,6 @@ @interface GPBUnknownFields () -- (size_t)serializedSize; - (nonnull NSData *)serializeAsData; -- (void)writeToCodedOutputStream:(nonnull GPBCodedOutputStream *)output; @end