From 9b1bed610fc0da29d28cdf31b81c13b6a999602b Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Wed, 20 Nov 2019 20:33:27 -0800 Subject: [PATCH] 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 --- php/ext/google/protobuf/def.c | 136 +++++++++++++++++------- php/ext/google/protobuf/encode_decode.c | 20 ++-- php/ext/google/protobuf/message.c | 38 +++---- php/ext/google/protobuf/protobuf.c | 42 +++++++- php/ext/google/protobuf/protobuf.h | 15 +-- php/ext/google/protobuf/storage.c | 9 ++ 6 files changed, 181 insertions(+), 79 deletions(-) diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c index 7c575c35cfe..f134f4b82cc 100644 --- a/php/ext/google/protobuf/def.c +++ b/php/ext/google/protobuf/def.c @@ -828,9 +828,11 @@ static void fill_segment(const char *segment, int length, static void fill_namespace(const char *package, const char *php_namespace, stringsink *classname) { if (php_namespace != NULL) { - stringsink_string(classname, NULL, php_namespace, strlen(php_namespace), - NULL); - stringsink_string(classname, NULL, "\\", 1, NULL); + if (strlen(php_namespace) != 0) { + stringsink_string(classname, NULL, php_namespace, strlen(php_namespace), + NULL); + stringsink_string(classname, NULL, "\\", 1, NULL); + } } else if (package != NULL) { int i = 0, j, offset = 0; size_t package_len = strlen(package); @@ -882,11 +884,23 @@ static void fill_classname(const char *fullname, } } -static zend_class_entry *register_class(const upb_filedef *file, - const char *fullname, - PHP_PROTO_HASHTABLE_VALUE desc_php, - bool use_nested_submsg, - bool is_enum TSRMLS_DC) { +static void fill_classname_for_desc(void *desc, bool is_enum) { + const upb_filedef *file; + const char *fullname; + bool use_nested_submsg; + + if (is_enum) { + EnumDescriptorInternal* enumdesc = desc; + file = upb_enumdef_file(enumdesc->enumdef); + fullname = upb_enumdef_fullname(enumdesc->enumdef); + use_nested_submsg = enumdesc->use_nested_submsg; + } else { + DescriptorInternal* msgdesc = desc; + file = upb_msgdef_file(msgdesc->msgdef); + fullname = upb_msgdef_fullname(msgdesc->msgdef); + use_nested_submsg = msgdesc->use_nested_submsg; + } + // Prepend '.' to package name to make it absolute. In the 5 additional // bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if // given message is google.protobuf.Empty. @@ -896,7 +910,6 @@ static zend_class_entry *register_class(const upb_filedef *file, size_t classname_len = classname_len_max(fullname, package, php_namespace, prefix); char* after_package; - zend_class_entry* ret; stringsink namesink; stringsink_init(&namesink); @@ -904,28 +917,68 @@ static zend_class_entry *register_class(const upb_filedef *file, fill_classname(fullname, package, prefix, &namesink, use_nested_submsg); stringsink_string(&namesink, NULL, "\0", 1, NULL); + if (is_enum) { + EnumDescriptorInternal* enumdesc = desc; + enumdesc->classname = strdup(namesink.ptr); + } else { + DescriptorInternal* msgdesc = desc; + msgdesc->classname = strdup(namesink.ptr); + } + + stringsink_uninit(&namesink); +} + +void register_class(void *desc, bool is_enum TSRMLS_DC) { + const char *classname; + const char *fullname; + zend_class_entry* ret; + + if (is_enum) { + EnumDescriptorInternal* enumdesc = desc; + if (enumdesc->klass) { + return; + } + classname = enumdesc->classname; + fullname = upb_enumdef_fullname(enumdesc->enumdef); + } else { + DescriptorInternal* msgdesc = desc; + if (msgdesc->klass) { + return; + } + if (!msgdesc->classname) { + return; + } + classname = msgdesc->classname; + fullname = upb_msgdef_fullname(msgdesc->msgdef); + } + PHP_PROTO_CE_DECLARE pce; - if (php_proto_zend_lookup_class(namesink.ptr, namesink.len - 1, &pce) == + if (php_proto_zend_lookup_class(classname, strlen(classname), &pce) == FAILURE) { zend_error( E_ERROR, - "Generated message class %s hasn't been defined (%s, %s, %s, %s)", - namesink.ptr, fullname, package, php_namespace, prefix); - return NULL; + "Generated message class %s hasn't been defined (%s)", + classname); + return; } ret = PHP_PROTO_CE_UNREF(pce); - add_ce_obj(ret, desc_php); if (is_enum) { - EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php); - add_ce_enumdesc(ret, desc->intern); - add_proto_enumdesc(fullname, desc->intern); + EnumDescriptorInternal* enumdesc = desc; + add_ce_enumdesc(ret, desc); + add_proto_enumdesc(fullname, desc); + enumdesc->klass = ret; } else { - Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php); - add_ce_desc(ret, desc->intern); - add_proto_desc(fullname, desc->intern); + DescriptorInternal* msgdesc = desc; + add_ce_desc(ret, desc); + msgdesc->klass = ret; + // Map entries don't have existing php class. + if (!upb_msgdef_mapentry(msgdesc->msgdef)) { + if (msgdesc->layout == NULL) { + MessageLayout* layout = create_layout(msgdesc->msgdef); + msgdesc->layout = layout; + } + } } - stringsink_uninit(&namesink); - return ret; } 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, desc->intern->pool = pool; desc->intern->layout = NULL; desc->intern->klass = NULL; + desc->intern->use_nested_submsg = use_nested_submsg; + desc->intern->classname = NULL; add_def_obj(desc->intern->msgdef, desc_php); 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, continue; } - desc->intern->klass = - register_class(file, upb_msgdef_fullname(msgdef), desc_php, - use_nested_submsg, false TSRMLS_CC); - - if (desc->intern->klass == NULL) { - return; - } - - build_class_from_descriptor(desc_php TSRMLS_CC); + fill_classname_for_desc(desc->intern, false); + add_class_desc(desc->intern->classname, desc->intern); + add_proto_desc(upb_msgdef_fullname(desc->intern->msgdef), desc->intern); } 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, desc->intern = SYS_MALLOC(EnumDescriptorInternal); desc->intern->enumdef = enumdef; desc->intern->klass = NULL; + desc->intern->use_nested_submsg = use_nested_submsg; + desc->intern->classname = NULL; add_def_obj(desc->intern->enumdef, desc_php); add_enumdef_enumdesc(desc->intern->enumdef, desc->intern); - desc->intern->klass = - register_class(file, upb_enumdef_fullname(enumdef), desc_php, - use_nested_submsg, true TSRMLS_CC); - - if (desc->intern->klass == NULL) { - return; - } + fill_classname_for_desc(desc->intern, true); + add_class_enumdesc(desc->intern->classname, desc->intern); } } @@ -1144,9 +1190,17 @@ PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { RETURN_NULL(); } - PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(PHP_PROTO_CE_UNREF(pce)); + zend_class_entry* ce = PHP_PROTO_CE_UNREF(pce); + + PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(ce); if (desc_php == NULL) { - EnumDescriptorInternal* intern = get_ce_enumdesc(PHP_PROTO_CE_UNREF(pce)); +#if PHP_MAJOR_VERSION < 7 + EnumDescriptorInternal* intern = get_class_enumdesc(ce->name); +#else + EnumDescriptorInternal* intern = get_class_enumdesc(ZSTR_VAL(ce->name)); +#endif + register_class(intern, true TSRMLS_CC); + if (intern == NULL) { RETURN_NULL(); } @@ -1164,7 +1218,7 @@ PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php); desc->intern = intern; add_def_obj(intern->enumdef, desc_php); - add_ce_obj(PHP_PROTO_CE_UNREF(pce), desc_php); + add_ce_obj(ce, desc_php); } zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc_php); diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c index 14808eb1ae1..e4b3566b525 100644 --- a/php/ext/google/protobuf/encode_decode.c +++ b/php/ext/google/protobuf/encode_decode.c @@ -429,6 +429,7 @@ static void *appendsubmsg_handler(void *closure, const void *hd) { const submsg_handlerdata_t *submsgdata = hd; DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; MessageHeader* submsg; @@ -456,6 +457,7 @@ static void *appendwrappersubmsg_handler(void *closure, const void *hd) { const submsg_handlerdata_t *submsgdata = hd; DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; MessageHeader* submsg; wrapperfields_parseframe_t* frame = @@ -487,6 +489,7 @@ static void *submsg_handler(void *closure, const void *hd) { const submsg_handlerdata_t* submsgdata = hd; TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; zval* submsg_php; MessageHeader* submsg; @@ -520,6 +523,7 @@ static void *map_submsg_handler(void *closure, const void *hd) { const submsg_handlerdata_t* submsgdata = hd; TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; zval* submsg_php; MessageHeader* submsg; @@ -554,6 +558,7 @@ static void *map_wrapper_submsg_handler(void *closure, const void *hd) { const submsg_handlerdata_t* submsgdata = hd; TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; zval* submsg_php; MessageHeader* submsg; @@ -641,6 +646,7 @@ static void map_slot_init( } case UPB_TYPE_MESSAGE: { DescriptorInternal* subdesc = get_msgdef_desc(value_msg); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; MessageHeader* submsg; #if PHP_MAJOR_VERSION < 7 @@ -938,6 +944,7 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) { uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t); TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; zval* submsg_php; MessageHeader* submsg; @@ -976,6 +983,7 @@ static void* wrapper_submsg_handler(void* closure, const void* hd) { const submsg_handlerdata_t* submsgdata = hd; TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; zval* submsg_php; MessageHeader* submsg; @@ -1007,6 +1015,7 @@ static void* wrapper_oneofsubmsg_handler(void* closure, const void* hd) { uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t); TSRMLS_FETCH(); DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; wrapperfields_parseframe_t* frame = (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t)); @@ -1347,6 +1356,7 @@ void add_handlers_for_message(const void* closure, upb_handlers* h) { const upb_msgdef* msgdef = upb_handlers_msgdef(h); TSRMLS_FETCH(); DescriptorInternal* desc = get_msgdef_desc(msgdef); + register_class(desc, false TSRMLS_CC); upb_msg_field_iter i; // 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) { return; } - // Ensure layout exists. We may be invoked to create handlers for a given - // message if we are included as a submsg of another message type before our - // class is actually built, so to work around this, we just create the layout - // (and handlers, in the class-building function) on-demand. - if (desc->layout == NULL) { - desc->layout = create_layout(desc->msgdef); - } - - // If this is a wrapper message type, set up a special set of handlers and // bail out of the normal (user-defined) message type handling. if (is_wrapper_msg(msgdef)) { @@ -1635,6 +1636,7 @@ static void putjsonany(MessageHeader* msg, const DescriptorInternal* desc, if (value_len > 0) { DescriptorInternal* payload_desc = get_msgdef_desc(payload_type); + register_class(payload_desc, false TSRMLS_CC); zend_class_entry* payload_klass = payload_desc->klass; zval val; upb_sink subsink; diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index e80ec4ec37b..9adf3b0179b 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -274,25 +274,6 @@ void custom_data_init(const zend_class_entry* ce, Message_construct(getThis(), array_wrapper); \ } -void build_class_from_descriptor( - PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC) { - Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, php_descriptor); - - // Map entries don't have existing php class. - if (upb_msgdef_mapentry(desc->intern->msgdef)) { - return; - } - - zend_class_entry* registered_ce = desc->intern->klass; - - if (desc->intern->layout == NULL) { - MessageLayout* layout = create_layout(desc->intern->msgdef); - desc->intern->layout = layout; - } - - registered_ce->create_object = message_create; -} - // ----------------------------------------------------------------------------- // PHP Methods // ----------------------------------------------------------------------------- @@ -346,11 +327,19 @@ void Message_construct(zval* msg, zval* array_wrapper) { TSRMLS_FETCH(); zend_class_entry* ce = Z_OBJCE_P(msg); MessageHeader* intern = NULL; - if (EXPECTED(class_added(ce))) { - intern = UNBOX(MessageHeader, msg); - custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC); + + if (!class_added(ce)) { +#if PHP_MAJOR_VERSION < 7 + DescriptorInternal* desc = get_class_desc(ce->name); +#else + DescriptorInternal* desc = get_class_desc(ZSTR_VAL(ce->name)); +#endif + register_class(desc, false TSRMLS_CC); } + intern = UNBOX(MessageHeader, msg); + custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC); + if (array_wrapper == NULL) { return; } @@ -396,6 +385,7 @@ void Message_construct(zval* msg, zval* array_wrapper) { if (is_wrapper) { DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); + register_class(subdesc, false TSRMLS_CC); subklass = subdesc->klass; } } @@ -435,6 +425,7 @@ void Message_construct(zval* msg, zval* array_wrapper) { if (is_wrapper) { DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); + register_class(subdesc, false TSRMLS_CC); subklass = subdesc->klass; } } @@ -458,6 +449,7 @@ void Message_construct(zval* msg, zval* array_wrapper) { } else if (upb_fielddef_issubmsg(field)) { const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); DescriptorInternal* desc = get_msgdef_desc(submsgdef); + register_class(desc, false TSRMLS_CC); CACHED_VALUE* cached = NULL; if (upb_fielddef_containingoneof(field)) { @@ -528,6 +520,7 @@ PHP_METHOD(Message, __construct) { PHP_METHOD(Message, clear) { MessageHeader* msg = UNBOX(MessageHeader, getThis()); DescriptorInternal* desc = msg->descriptor; + register_class(desc, false TSRMLS_CC); zend_class_entry* ce = desc->klass; zend_object_std_dtor(&msg->std TSRMLS_CC); @@ -1540,6 +1533,7 @@ PHP_METHOD(Any, unpack) { 0 TSRMLS_CC); return; } + register_class(desc, false TSRMLS_CC); zend_class_entry* klass = desc->klass; ZVAL_OBJ(return_value, klass->create_object(klass TSRMLS_CC)); MessageHeader* msg = UNBOX(MessageHeader, return_value); diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c index fd97c89bd73..3ceba7b8568 100644 --- a/php/ext/google/protobuf/protobuf.c +++ b/php/ext/google/protobuf/protobuf.c @@ -53,6 +53,7 @@ static upb_inttable ce_to_enumdesc_map_persistent; // wrapper Descriptor/EnumDescriptor instances. static upb_strtable proto_to_desc_map_persistent; static upb_strtable proto_to_enumdesc_map_persistent; +static upb_strtable class_to_desc_map_persistent; upb_strtable reserved_names; @@ -194,7 +195,7 @@ EnumDescriptorInternal* get_ce_enumdesc(const zend_class_entry* ce) { } bool class_added(const void* ce) { - return exist_in_table(ce_to_php_obj_map, ce); + return get_ce_desc(ce) != NULL; } void add_proto_desc(const char* proto, DescriptorInternal* desc) { @@ -232,6 +233,40 @@ EnumDescriptorInternal* get_proto_enumdesc(const char* proto) { } } +void add_class_desc(const char* klass, DescriptorInternal* desc) { + upb_strtable_insert(&class_to_desc_map_persistent, klass, + upb_value_ptr(desc)); +} + +DescriptorInternal* get_class_desc(const char* klass) { + upb_value v; +#ifndef NDEBUG + v.ctype = UPB_CTYPE_PTR; +#endif + if (!upb_strtable_lookup(&class_to_desc_map_persistent, klass, &v)) { + return NULL; + } else { + return upb_value_getptr(v); + } +} + +void add_class_enumdesc(const char* klass, EnumDescriptorInternal* desc) { + upb_strtable_insert(&class_to_desc_map_persistent, klass, + upb_value_ptr(desc)); +} + +EnumDescriptorInternal* get_class_enumdesc(const char* klass) { + upb_value v; +#ifndef NDEBUG + v.ctype = UPB_CTYPE_PTR; +#endif + if (!upb_strtable_lookup(&class_to_desc_map_persistent, klass, &v)) { + return NULL; + } else { + return upb_value_getptr(v); + } +} + // ----------------------------------------------------------------------------- // Well Known Types. // ----------------------------------------------------------------------------- @@ -344,6 +379,7 @@ static initialize_persistent_descriptor_pool(TSRMLS_D) { upb_inttable_init(&ce_to_enumdesc_map_persistent, UPB_CTYPE_PTR); upb_strtable_init(&proto_to_desc_map_persistent, UPB_CTYPE_PTR); upb_strtable_init(&proto_to_enumdesc_map_persistent, UPB_CTYPE_PTR); + upb_strtable_init(&class_to_desc_map_persistent, UPB_CTYPE_PTR); internal_descriptor_pool_impl_init(&generated_pool_impl TSRMLS_CC); @@ -388,7 +424,9 @@ static void cleanup_desc_table(upb_inttable* t) { desc = upb_value_getptr(v); if (desc->layout) { free_layout(desc->layout); + desc->layout = NULL; } + free(desc->classname); SYS_FREE(desc); } } @@ -402,6 +440,7 @@ static void cleanup_enumdesc_table(upb_inttable* t) { upb_inttable_next(&i)) { v = upb_inttable_iter_value(&i); desc = upb_value_getptr(v); + free(desc->classname); SYS_FREE(desc); } } @@ -421,6 +460,7 @@ static cleanup_persistent_descriptor_pool(TSRMLS_D) { upb_inttable_uninit(&ce_to_enumdesc_map_persistent); upb_strtable_uninit(&proto_to_desc_map_persistent); upb_strtable_uninit(&proto_to_enumdesc_map_persistent); + upb_strtable_uninit(&class_to_desc_map_persistent); } static PHP_RSHUTDOWN_FUNCTION(protobuf) { diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 1fd90f21af4..1d070a48083 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -779,6 +779,10 @@ void add_proto_desc(const char* proto, DescriptorInternal* desc); DescriptorInternal* get_proto_desc(const char* proto); void add_proto_enumdesc(const char* proto, EnumDescriptorInternal* desc); EnumDescriptorInternal* get_proto_enumdesc(const char* proto); +void add_class_desc(const char* klass, DescriptorInternal* desc); +DescriptorInternal* get_class_desc(const char* klass); +void add_class_enumdesc(const char* klass, EnumDescriptorInternal* desc); +EnumDescriptorInternal* get_class_enumdesc(const char* klass); extern zend_class_entry* map_field_type; extern zend_class_entry* repeated_field_type; @@ -817,6 +821,7 @@ void internal_add_generated_file(const char* data, PHP_PROTO_SIZE data_len, bool use_nested_submsg TSRMLS_DC); void init_generated_pool_once(TSRMLS_D); void add_handlers_for_message(const void* closure, upb_handlers* h); +void register_class(void *desc, bool is_enum TSRMLS_DC); // wrapper of generated pool #if PHP_MAJOR_VERSION < 7 @@ -844,6 +849,8 @@ struct DescriptorInternal { const upb_msgdef* msgdef; MessageLayout* layout; zend_class_entry* klass; // begins as NULL + bool use_nested_submsg; + char* classname; }; PHP_PROTO_WRAP_OBJECT_START(Descriptor) @@ -878,6 +885,8 @@ extern zend_class_entry* field_descriptor_type; struct EnumDescriptorInternal { const upb_enumdef* enumdef; zend_class_entry* klass; // begins as NULL + bool use_nested_submsg; + char* classname; }; PHP_PROTO_WRAP_OBJECT_START(EnumDescriptor) @@ -907,12 +916,6 @@ void* message_data(MessageHeader* msg); void custom_data_init(const zend_class_entry* ce, MessageHeader* msg PHP_PROTO_TSRMLS_DC); -// Build PHP class for given descriptor. Instead of building from scratch, this -// function modifies existing class which has been partially defined in PHP -// code. -void build_class_from_descriptor( - PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC); - extern zend_class_entry* message_type; extern zend_object_handlers* message_handlers; diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c index 2521af5b2e1..235c5df8a8e 100644 --- a/php/ext/google/protobuf/storage.c +++ b/php/ext/google/protobuf/storage.c @@ -551,10 +551,12 @@ const zend_class_entry* field_type_class( const upb_fielddef* field PHP_PROTO_TSRMLS_DC) { if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { DescriptorInternal* desc = get_msgdef_desc(upb_fielddef_msgsubdef(field)); + register_class(desc, false TSRMLS_CC); return desc->klass; } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { EnumDescriptorInternal* desc = get_enumdef_enumdesc(upb_fielddef_enumsubdef(field)); + register_class(desc, false TSRMLS_CC); return desc->klass; } return NULL; @@ -600,6 +602,7 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) { TSRMLS_FETCH(); DescriptorInternal* desc = get_msgdef_desc(msgdef); + register_class(desc, false TSRMLS_CC); layout->fields = SYS_MALLOC_N(MessageField, nfields); for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); @@ -822,6 +825,7 @@ zval* layout_get(MessageLayout* layout, MessageHeader* header, const upb_fielddef* value_field = upb_msgdef_itof(submsgdef, 1); MessageHeader* submsg; DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); + register_class(subdesc, false TSRMLS_CC); zend_class_entry* subklass = subdesc->klass; #if PHP_MAJOR_VERSION < 7 zval* val = NULL; @@ -877,6 +881,7 @@ void layout_set(MessageLayout* layout, MessageHeader* header, UPB_DESCRIPTOR_TYPE_MESSAGE) { const upb_msgdef* submsg = upb_fielddef_msgsubdef(valuefield); DescriptorInternal* subdesc = get_msgdef_desc(submsg); + register_class(subdesc, false TSRMLS_CC); subce = subdesc->klass; } check_map_field(subce, upb_fielddef_descriptortype(keyfield), @@ -886,6 +891,7 @@ void layout_set(MessageLayout* layout, MessageHeader* header, if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { const upb_msgdef* submsg = upb_fielddef_msgsubdef(field); DescriptorInternal* subdesc = get_msgdef_desc(submsg); + register_class(subdesc, false TSRMLS_CC); subce = subdesc->klass; } @@ -908,6 +914,7 @@ void layout_set(MessageLayout* layout, MessageHeader* header, if (type == UPB_TYPE_MESSAGE) { const upb_msgdef* msg = upb_fielddef_msgsubdef(field); DescriptorInternal* desc = get_msgdef_desc(msg); + register_class(desc, false TSRMLS_CC); ce = desc->klass; } CACHED_VALUE* cache = find_zval_property(header, field); @@ -946,6 +953,7 @@ static void native_slot_merge( case UPB_TYPE_MESSAGE: { const upb_msgdef* msg = upb_fielddef_msgsubdef(field); DescriptorInternal* desc = get_msgdef_desc(msg); + register_class(desc, false TSRMLS_CC); ce = desc->klass; if (native_slot_is_default(type, to_memory)) { #if PHP_MAJOR_VERSION < 7 @@ -992,6 +1000,7 @@ static void native_slot_merge_by_array(const upb_fielddef* field, const void* fr case UPB_TYPE_MESSAGE: { const upb_msgdef* msg = upb_fielddef_msgsubdef(field); DescriptorInternal* desc = get_msgdef_desc(upb_fielddef_msgsubdef(field)); + register_class(desc, false TSRMLS_CC); zend_class_entry* ce = desc->klass; #if PHP_MAJOR_VERSION < 7 MAKE_STD_ZVAL(DEREF(to_memory, zval*));