Skip to content

Commit 6d7bb7e

Browse files
authored
Implement lazy loading of php class for proto messages (#6911)
* Implement lazy loading of php class for proto messages * Fix php 7.1 * Fix encode * Fix memory leak * Fix enum descriptor
1 parent de75651 commit 6d7bb7e

File tree

6 files changed

+181
-79
lines changed

6 files changed

+181
-79
lines changed

php/ext/google/protobuf/def.c

Lines changed: 95 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -828,9 +828,11 @@ static void fill_segment(const char *segment, int length,
828828
static void fill_namespace(const char *package, const char *php_namespace,
829829
stringsink *classname) {
830830
if (php_namespace != NULL) {
831-
stringsink_string(classname, NULL, php_namespace, strlen(php_namespace),
832-
NULL);
833-
stringsink_string(classname, NULL, "\\", 1, NULL);
831+
if (strlen(php_namespace) != 0) {
832+
stringsink_string(classname, NULL, php_namespace, strlen(php_namespace),
833+
NULL);
834+
stringsink_string(classname, NULL, "\\", 1, NULL);
835+
}
834836
} else if (package != NULL) {
835837
int i = 0, j, offset = 0;
836838
size_t package_len = strlen(package);
@@ -882,11 +884,23 @@ static void fill_classname(const char *fullname,
882884
}
883885
}
884886

885-
static zend_class_entry *register_class(const upb_filedef *file,
886-
const char *fullname,
887-
PHP_PROTO_HASHTABLE_VALUE desc_php,
888-
bool use_nested_submsg,
889-
bool is_enum TSRMLS_DC) {
887+
static void fill_classname_for_desc(void *desc, bool is_enum) {
888+
const upb_filedef *file;
889+
const char *fullname;
890+
bool use_nested_submsg;
891+
892+
if (is_enum) {
893+
EnumDescriptorInternal* enumdesc = desc;
894+
file = upb_enumdef_file(enumdesc->enumdef);
895+
fullname = upb_enumdef_fullname(enumdesc->enumdef);
896+
use_nested_submsg = enumdesc->use_nested_submsg;
897+
} else {
898+
DescriptorInternal* msgdesc = desc;
899+
file = upb_msgdef_file(msgdesc->msgdef);
900+
fullname = upb_msgdef_fullname(msgdesc->msgdef);
901+
use_nested_submsg = msgdesc->use_nested_submsg;
902+
}
903+
890904
// Prepend '.' to package name to make it absolute. In the 5 additional
891905
// bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if
892906
// given message is google.protobuf.Empty.
@@ -896,36 +910,75 @@ static zend_class_entry *register_class(const upb_filedef *file,
896910
size_t classname_len =
897911
classname_len_max(fullname, package, php_namespace, prefix);
898912
char* after_package;
899-
zend_class_entry* ret;
900913
stringsink namesink;
901914
stringsink_init(&namesink);
902915

903916
fill_namespace(package, php_namespace, &namesink);
904917
fill_classname(fullname, package, prefix, &namesink, use_nested_submsg);
905918
stringsink_string(&namesink, NULL, "\0", 1, NULL);
906919

920+
if (is_enum) {
921+
EnumDescriptorInternal* enumdesc = desc;
922+
enumdesc->classname = strdup(namesink.ptr);
923+
} else {
924+
DescriptorInternal* msgdesc = desc;
925+
msgdesc->classname = strdup(namesink.ptr);
926+
}
927+
928+
stringsink_uninit(&namesink);
929+
}
930+
931+
void register_class(void *desc, bool is_enum TSRMLS_DC) {
932+
const char *classname;
933+
const char *fullname;
934+
zend_class_entry* ret;
935+
936+
if (is_enum) {
937+
EnumDescriptorInternal* enumdesc = desc;
938+
if (enumdesc->klass) {
939+
return;
940+
}
941+
classname = enumdesc->classname;
942+
fullname = upb_enumdef_fullname(enumdesc->enumdef);
943+
} else {
944+
DescriptorInternal* msgdesc = desc;
945+
if (msgdesc->klass) {
946+
return;
947+
}
948+
if (!msgdesc->classname) {
949+
return;
950+
}
951+
classname = msgdesc->classname;
952+
fullname = upb_msgdef_fullname(msgdesc->msgdef);
953+
}
954+
907955
PHP_PROTO_CE_DECLARE pce;
908-
if (php_proto_zend_lookup_class(namesink.ptr, namesink.len - 1, &pce) ==
956+
if (php_proto_zend_lookup_class(classname, strlen(classname), &pce) ==
909957
FAILURE) {
910958
zend_error(
911959
E_ERROR,
912-
"Generated message class %s hasn't been defined (%s, %s, %s, %s)",
913-
namesink.ptr, fullname, package, php_namespace, prefix);
914-
return NULL;
960+
"Generated message class %s hasn't been defined (%s)",
961+
classname);
962+
return;
915963
}
916964
ret = PHP_PROTO_CE_UNREF(pce);
917-
add_ce_obj(ret, desc_php);
918965
if (is_enum) {
919-
EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php);
920-
add_ce_enumdesc(ret, desc->intern);
921-
add_proto_enumdesc(fullname, desc->intern);
966+
EnumDescriptorInternal* enumdesc = desc;
967+
add_ce_enumdesc(ret, desc);
968+
add_proto_enumdesc(fullname, desc);
969+
enumdesc->klass = ret;
922970
} else {
923-
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php);
924-
add_ce_desc(ret, desc->intern);
925-
add_proto_desc(fullname, desc->intern);
971+
DescriptorInternal* msgdesc = desc;
972+
add_ce_desc(ret, desc);
973+
msgdesc->klass = ret;
974+
// Map entries don't have existing php class.
975+
if (!upb_msgdef_mapentry(msgdesc->msgdef)) {
976+
if (msgdesc->layout == NULL) {
977+
MessageLayout* layout = create_layout(msgdesc->msgdef);
978+
msgdesc->layout = layout;
979+
}
980+
}
926981
}
927-
stringsink_uninit(&namesink);
928-
return ret;
929982
}
930983

931984
bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) {
@@ -1019,6 +1072,8 @@ void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len,
10191072
desc->intern->pool = pool;
10201073
desc->intern->layout = NULL;
10211074
desc->intern->klass = NULL;
1075+
desc->intern->use_nested_submsg = use_nested_submsg;
1076+
desc->intern->classname = NULL;
10221077

10231078
add_def_obj(desc->intern->msgdef, desc_php);
10241079
add_msgdef_desc(desc->intern->msgdef, desc->intern);
@@ -1029,15 +1084,9 @@ void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len,
10291084
continue;
10301085
}
10311086

1032-
desc->intern->klass =
1033-
register_class(file, upb_msgdef_fullname(msgdef), desc_php,
1034-
use_nested_submsg, false TSRMLS_CC);
1035-
1036-
if (desc->intern->klass == NULL) {
1037-
return;
1038-
}
1039-
1040-
build_class_from_descriptor(desc_php TSRMLS_CC);
1087+
fill_classname_for_desc(desc->intern, false);
1088+
add_class_desc(desc->intern->classname, desc->intern);
1089+
add_proto_desc(upb_msgdef_fullname(desc->intern->msgdef), desc->intern);
10411090
}
10421091

10431092
for (i = 0; i < upb_filedef_enumcount(file); i++) {
@@ -1046,16 +1095,13 @@ void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len,
10461095
desc->intern = SYS_MALLOC(EnumDescriptorInternal);
10471096
desc->intern->enumdef = enumdef;
10481097
desc->intern->klass = NULL;
1098+
desc->intern->use_nested_submsg = use_nested_submsg;
1099+
desc->intern->classname = NULL;
10491100

10501101
add_def_obj(desc->intern->enumdef, desc_php);
10511102
add_enumdef_enumdesc(desc->intern->enumdef, desc->intern);
1052-
desc->intern->klass =
1053-
register_class(file, upb_enumdef_fullname(enumdef), desc_php,
1054-
use_nested_submsg, true TSRMLS_CC);
1055-
1056-
if (desc->intern->klass == NULL) {
1057-
return;
1058-
}
1103+
fill_classname_for_desc(desc->intern, true);
1104+
add_class_enumdesc(desc->intern->classname, desc->intern);
10591105
}
10601106
}
10611107

@@ -1144,9 +1190,17 @@ PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) {
11441190
RETURN_NULL();
11451191
}
11461192

1147-
PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(PHP_PROTO_CE_UNREF(pce));
1193+
zend_class_entry* ce = PHP_PROTO_CE_UNREF(pce);
1194+
1195+
PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(ce);
11481196
if (desc_php == NULL) {
1149-
EnumDescriptorInternal* intern = get_ce_enumdesc(PHP_PROTO_CE_UNREF(pce));
1197+
#if PHP_MAJOR_VERSION < 7
1198+
EnumDescriptorInternal* intern = get_class_enumdesc(ce->name);
1199+
#else
1200+
EnumDescriptorInternal* intern = get_class_enumdesc(ZSTR_VAL(ce->name));
1201+
#endif
1202+
register_class(intern, true TSRMLS_CC);
1203+
11501204
if (intern == NULL) {
11511205
RETURN_NULL();
11521206
}
@@ -1164,7 +1218,7 @@ PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) {
11641218
EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php);
11651219
desc->intern = intern;
11661220
add_def_obj(intern->enumdef, desc_php);
1167-
add_ce_obj(PHP_PROTO_CE_UNREF(pce), desc_php);
1221+
add_ce_obj(ce, desc_php);
11681222
}
11691223

11701224
zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc_php);

php/ext/google/protobuf/encode_decode.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ static void *appendsubmsg_handler(void *closure, const void *hd) {
429429

430430
const submsg_handlerdata_t *submsgdata = hd;
431431
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
432+
register_class(subdesc, false TSRMLS_CC);
432433
zend_class_entry* subklass = subdesc->klass;
433434
MessageHeader* submsg;
434435

@@ -456,6 +457,7 @@ static void *appendwrappersubmsg_handler(void *closure, const void *hd) {
456457

457458
const submsg_handlerdata_t *submsgdata = hd;
458459
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
460+
register_class(subdesc, false TSRMLS_CC);
459461
zend_class_entry* subklass = subdesc->klass;
460462
MessageHeader* submsg;
461463
wrapperfields_parseframe_t* frame =
@@ -487,6 +489,7 @@ static void *submsg_handler(void *closure, const void *hd) {
487489
const submsg_handlerdata_t* submsgdata = hd;
488490
TSRMLS_FETCH();
489491
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
492+
register_class(subdesc, false TSRMLS_CC);
490493
zend_class_entry* subklass = subdesc->klass;
491494
zval* submsg_php;
492495
MessageHeader* submsg;
@@ -520,6 +523,7 @@ static void *map_submsg_handler(void *closure, const void *hd) {
520523
const submsg_handlerdata_t* submsgdata = hd;
521524
TSRMLS_FETCH();
522525
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
526+
register_class(subdesc, false TSRMLS_CC);
523527
zend_class_entry* subklass = subdesc->klass;
524528
zval* submsg_php;
525529
MessageHeader* submsg;
@@ -554,6 +558,7 @@ static void *map_wrapper_submsg_handler(void *closure, const void *hd) {
554558
const submsg_handlerdata_t* submsgdata = hd;
555559
TSRMLS_FETCH();
556560
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
561+
register_class(subdesc, false TSRMLS_CC);
557562
zend_class_entry* subklass = subdesc->klass;
558563
zval* submsg_php;
559564
MessageHeader* submsg;
@@ -641,6 +646,7 @@ static void map_slot_init(
641646
}
642647
case UPB_TYPE_MESSAGE: {
643648
DescriptorInternal* subdesc = get_msgdef_desc(value_msg);
649+
register_class(subdesc, false TSRMLS_CC);
644650
zend_class_entry* subklass = subdesc->klass;
645651
MessageHeader* submsg;
646652
#if PHP_MAJOR_VERSION < 7
@@ -938,6 +944,7 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) {
938944
uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
939945
TSRMLS_FETCH();
940946
DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md);
947+
register_class(subdesc, false TSRMLS_CC);
941948
zend_class_entry* subklass = subdesc->klass;
942949
zval* submsg_php;
943950
MessageHeader* submsg;
@@ -976,6 +983,7 @@ static void* wrapper_submsg_handler(void* closure, const void* hd) {
976983
const submsg_handlerdata_t* submsgdata = hd;
977984
TSRMLS_FETCH();
978985
DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md);
986+
register_class(subdesc, false TSRMLS_CC);
979987
zend_class_entry* subklass = subdesc->klass;
980988
zval* submsg_php;
981989
MessageHeader* submsg;
@@ -1007,6 +1015,7 @@ static void* wrapper_oneofsubmsg_handler(void* closure, const void* hd) {
10071015
uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
10081016
TSRMLS_FETCH();
10091017
DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md);
1018+
register_class(subdesc, false TSRMLS_CC);
10101019
zend_class_entry* subklass = subdesc->klass;
10111020
wrapperfields_parseframe_t* frame =
10121021
(wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t));
@@ -1347,6 +1356,7 @@ void add_handlers_for_message(const void* closure, upb_handlers* h) {
13471356
const upb_msgdef* msgdef = upb_handlers_msgdef(h);
13481357
TSRMLS_FETCH();
13491358
DescriptorInternal* desc = get_msgdef_desc(msgdef);
1359+
register_class(desc, false TSRMLS_CC);
13501360
upb_msg_field_iter i;
13511361

13521362
// If this is a mapentry message type, set up a special set of handlers and
@@ -1356,15 +1366,6 @@ void add_handlers_for_message(const void* closure, upb_handlers* h) {
13561366
return;
13571367
}
13581368

1359-
// Ensure layout exists. We may be invoked to create handlers for a given
1360-
// message if we are included as a submsg of another message type before our
1361-
// class is actually built, so to work around this, we just create the layout
1362-
// (and handlers, in the class-building function) on-demand.
1363-
if (desc->layout == NULL) {
1364-
desc->layout = create_layout(desc->msgdef);
1365-
}
1366-
1367-
13681369
// If this is a wrapper message type, set up a special set of handlers and
13691370
// bail out of the normal (user-defined) message type handling.
13701371
if (is_wrapper_msg(msgdef)) {
@@ -1635,6 +1636,7 @@ static void putjsonany(MessageHeader* msg, const DescriptorInternal* desc,
16351636

16361637
if (value_len > 0) {
16371638
DescriptorInternal* payload_desc = get_msgdef_desc(payload_type);
1639+
register_class(payload_desc, false TSRMLS_CC);
16381640
zend_class_entry* payload_klass = payload_desc->klass;
16391641
zval val;
16401642
upb_sink subsink;

0 commit comments

Comments
 (0)