[ObjC] Runtime support for fullName and FileDescriptor improvements

Add a new generator interface to:
- provide the message name directly instead of the overhead needed to try and compute it
- provide the data for the GPBFileDescriptor as a struct.

This allows -[GPBMessage fullName] to much more easily compute the fullname.

It also will allow the creation of all GPBFileDescriptors to be done on demand thus reducing the work in the startup codepaths as well as reducing memory requirements.

The generation changes are in a following commit.

PiperOrigin-RevId: 508063366
pull/11852/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 1d744d40c8
commit f4c7972ff4
  1. 123
      objectivec/GPBDescriptor.m
  2. 22
      objectivec/GPBDescriptor_PackagePrivate.h

@ -38,7 +38,8 @@
@interface GPBDescriptor ()
- (instancetype)initWithClass:(Class)messageClass
file:(GPBFileDescriptor *)file
messageName:(NSString *)messageName
fileDescription:(GPBFileDescription *)fileDescription
fields:(NSArray *)fields
storageSize:(uint32_t)storage
wireFormat:(BOOL)wireFormat;
@ -48,8 +49,8 @@
// Single initializer
// description has to be long lived, it is held as a raw pointer.
- (instancetype)initWithFieldDescription:(void *)description
file:(GPBFileDescriptor *)file
descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags;
descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags
fileSyntax:(GPBFileSyntax)fileSyntax;
@end
@ -72,6 +73,7 @@
static const char kTextFormatExtraValueKey = 0;
static const char kParentClassValueKey = 0;
static const char kClassNameSuffixKey = 0;
static const char kFileDescriptorCacheKey = 0;
// Utility function to generate selectors on the fly.
static SEL SelFromStrings(const char *prefix, const char *middle, const char *suffix,
@ -122,7 +124,8 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
@implementation GPBDescriptor {
Class messageClass_;
GPBFileDescriptor *file_;
NSString *messageName_;
const GPBFileDescription *fileDescription_;
BOOL wireFormat_;
}
@ -131,11 +134,11 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
@synthesize oneofs = oneofs_;
@synthesize extensionRanges = extensionRanges_;
@synthesize extensionRangesCount = extensionRangesCount_;
@synthesize file = file_;
@synthesize wireFormat = wireFormat_;
+ (instancetype)allocDescriptorForClass:(Class)messageClass
file:(GPBFileDescriptor *)file
messageName:(NSString *)messageName
fileDescription:(GPBFileDescription *)fileDescription
fields:(void *)fieldDescriptions
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
@ -168,7 +171,9 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
mergedFieldFlags |= (((GPBMessageFieldDescription *)fieldDescriptions)[i]).flags;
}
GPBFieldDescriptor *fieldDescriptor =
[[GPBFieldDescriptor alloc] initWithFieldDescription:desc file:file descriptorFlags:flags];
[[GPBFieldDescriptor alloc] initWithFieldDescription:desc
descriptorFlags:flags
fileSyntax:fileDescription->syntax];
[fields addObject:fieldDescriptor];
[fieldDescriptor release];
}
@ -184,7 +189,8 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
file:file
messageName:messageName
fileDescription:fileDescription
fields:fields
storageSize:storageSize
wireFormat:wireFormat];
@ -192,6 +198,35 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
return descriptor;
}
+ (instancetype)allocDescriptorForClass:(Class)messageClass
file:(GPBFileDescriptor *)file
fields:(void *)fieldDescriptions
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
flags:(GPBDescriptorInitializationFlags)flags {
GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30006,
time_to_remove_this_old_version_shim);
// Use a local GPBFileDescription with just the syntax to allow legacy generation initialization,
// then clear the ivar and wire in the GPBFileDescriptor.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
GPBFileDescription localDesc = {NULL, NULL, file.syntax};
#pragma clang diagnostic pop
GPBDescriptor *result = [self allocDescriptorForClass:messageClass
messageName:nil
fileDescription:&localDesc
fields:fieldDescriptions
fieldCount:fieldCount
storageSize:storageSize
flags:flags];
result->fileDescription_ = NULL;
objc_setAssociatedObject(result, &kFileDescriptorCacheKey, file,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return result;
}
+ (instancetype)allocDescriptorForClass:(Class)messageClass
rootClass:(__unused Class)rootClass
file:(GPBFileDescriptor *)file
@ -213,13 +248,21 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
}
- (instancetype)initWithClass:(Class)messageClass
file:(GPBFileDescriptor *)file
messageName:(NSString *)messageName
fileDescription:(GPBFileDescription *)fileDescription
fields:(NSArray *)fields
storageSize:(uint32_t)storageSize
wireFormat:(BOOL)wireFormat {
if ((self = [super init])) {
messageClass_ = messageClass;
file_ = file;
#if defined(DEBUG) && DEBUG
// If `messageName` is set, then `fileDescription` also must be set. `fileDescription` gets
// hotwired for legacy startup, so it can be non NULL without `messageName` having been set.
NSAssert((messageName == nil) || (fileDescription != NULL),
@"messageName and fileDescription should always be provided together");
#endif
messageName_ = [messageName copy];
fileDescription_ = fileDescription;
fields_ = [fields retain];
storageSize_ = storageSize;
wireFormat_ = wireFormat;
@ -228,6 +271,7 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
}
- (void)dealloc {
[messageName_ release];
[fields_ release];
[oneofs_ release];
[super dealloc];
@ -292,6 +336,8 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
}
- (void)setupMessageClassNameSuffix:(NSString *)suffix {
GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30007,
time_to_remove_this_old_version_shim);
if (suffix.length) {
objc_setAssociatedObject(self, &kClassNameSuffixKey, suffix, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@ -301,12 +347,54 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
return NSStringFromClass(messageClass_);
}
- (GPBFileDescriptor *)file {
@synchronized(self) {
GPBFileDescriptor *result = objc_getAssociatedObject(self, &kFileDescriptorCacheKey);
if (!result) {
#if defined(DEBUG) && DEBUG
NSAssert(fileDescription_ != NULL, @"Internal error in generation/startup");
#endif
// `package` and `prefix` can both be NULL if there wasn't one for the file.
NSString *package = fileDescription_->package ? @(fileDescription_->package) : @"";
if (fileDescription_->prefix) {
result = [[GPBFileDescriptor alloc] initWithPackage:package
objcPrefix:@(fileDescription_->prefix)
syntax:fileDescription_->syntax];
} else {
result = [[GPBFileDescriptor alloc] initWithPackage:package
syntax:fileDescription_->syntax];
}
objc_setAssociatedObject(result, &kFileDescriptorCacheKey, result,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return result;
}
}
- (GPBDescriptor *)containingType {
Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey);
return [parentClass descriptor];
}
- (NSString *)fullName {
GPBDescriptor *parent = self.containingType;
if (messageName_) {
if (parent) {
return [NSString stringWithFormat:@"%@.%@", parent.fullName, messageName_];
}
if (fileDescription_->package) {
return [NSString stringWithFormat:@"%s.%@", fileDescription_->package, messageName_];
}
return messageName_;
}
GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30007,
time_to_remove_this_old_approach);
// NOTE: When this code path is removed, this also means this api can't return nil any more but
// that would be a breaking code change (not longer a Swift optional), so changing that will be
// harder.
NSString *className = NSStringFromClass(self.messageClass);
GPBFileDescriptor *file = self.file;
NSString *objcPrefix = file.objcPrefix;
@ -314,7 +402,6 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageField
NSAssert(0, @"Class didn't have correct prefix? (%@ - %@)", className, objcPrefix);
return nil;
}
GPBDescriptor *parent = self.containingType;
NSString *name = nil;
if (parent) {
@ -542,8 +629,8 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
@synthesize containingOneof = containingOneof_;
- (instancetype)initWithFieldDescription:(void *)description
file:(GPBFileDescriptor *)file
descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags {
descriptorFlags:(GPBDescriptorInitializationFlags)descriptorFlags
fileSyntax:(GPBFileSyntax)fileSyntax {
if ((self = [super init])) {
BOOL includesDefault =
(descriptorFlags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
@ -571,11 +658,8 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
// - not repeated/map
// - not in a oneof (negative has index)
// - not a message (the flag doesn't make sense for messages)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
BOOL clearOnZero = ((file.syntax == GPBFileSyntaxProto3) && !isMapOrArray &&
BOOL clearOnZero = ((fileSyntax == GPBFileSyntaxProto3) && !isMapOrArray &&
(coreDesc->hasIndex >= 0) && !isMessage);
#pragma clang diagnostic pop
if (clearOnZero) {
coreDesc->flags |= GPBFieldClearHasIvarOnZero;
}
@ -592,10 +676,7 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
// to be what the runtime was doing (even though it was wrong). This is
// only wrong in the rare cases an enum is declared in a proto3 syntax
// file but used for a field in the proto2 syntax file.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
BOOL isClosedEnum = (dataType == GPBDataTypeEnum && file.syntax != GPBFileSyntaxProto3);
#pragma clang diagnostic pop
BOOL isClosedEnum = (dataType == GPBDataTypeEnum && fileSyntax != GPBFileSyntaxProto3);
if (isClosedEnum) {
coreDesc->flags |= GPBFieldClosedEnum;
}

@ -91,6 +91,15 @@ typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
// their size. This directly impacts the size of apps since these exist per
// field/extension.
typedef struct GPBFileDescription {
// The proto package for the file.
const char *package;
// The objc_class_prefix option if present.
const char *prefix;
// The file's proto syntax.
GPBFileSyntax syntax;
} GPBFileDescription;
// Describes a single field in a protobuf as it is represented as an ivar.
typedef struct GPBMessageFieldDescription {
// Name of ivar.
@ -200,9 +209,10 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
uint32_t storageSize_;
}
// fieldDescriptions have to be long lived, they are held as raw pointers.
// fieldDescriptions and fileDescription have to be long lived, they are held as raw pointers.
+ (instancetype)allocDescriptorForClass:(Class)messageClass
file:(GPBFileDescriptor *)file
messageName:(NSString *)messageName
fileDescription:(GPBFileDescription *)fileDescription
fields:(void *)fieldDescriptions
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
@ -217,9 +227,14 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
- (void)setupContainingMessageClass:(Class)msgClass;
- (void)setupMessageClassNameSuffix:(NSString *)suffix;
// Deprecated, these remain to support older versions of source generation.
+ (instancetype)allocDescriptorForClass:(Class)messageClass
file:(GPBFileDescriptor *)file
fields:(void *)fieldDescriptions
fieldCount:(uint32_t)fieldCount
storageSize:(uint32_t)storageSize
flags:(GPBDescriptorInitializationFlags)flags;
+ (instancetype)allocDescriptorForClass:(Class)messageClass
rootClass:(Class)rootClass
file:(GPBFileDescriptor *)file
@ -228,6 +243,7 @@ typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
storageSize:(uint32_t)storageSize
flags:(GPBDescriptorInitializationFlags)flags;
- (void)setupContainingMessageClassName:(const char *)msgClassName;
- (void)setupMessageClassNameSuffix:(NSString *)suffix;
@end

Loading…
Cancel
Save