diff options
Diffstat (limited to 'php/ext/google/protobuf/storage.c')
-rw-r--r-- | php/ext/google/protobuf/storage.c | 578 |
1 files changed, 349 insertions, 229 deletions
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c index af7c292f..6318f88c 100644 --- a/php/ext/google/protobuf/storage.c +++ b/php/ext/google/protobuf/storage.c @@ -57,7 +57,7 @@ size_t native_slot_size(upb_fieldtype_t type) { } } -static bool native_slot_is_default(upb_fieldtype_t type, void* memory) { +static bool native_slot_is_default(upb_fieldtype_t type, const void* memory) { switch (type) { #define CASE_TYPE(upb_type, c_type) \ case UPB_TYPE_##upb_type: { \ @@ -75,15 +75,17 @@ static bool native_slot_is_default(upb_fieldtype_t type, void* memory) { #undef CASE_TYPE case UPB_TYPE_STRING: case UPB_TYPE_BYTES: - return Z_STRLEN_PP(DEREF(memory, zval**)) == 0; + return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) == + 0; case UPB_TYPE_MESSAGE: - return Z_TYPE_PP(DEREF(memory, zval**)) == IS_NULL; + return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) == + IS_NULL; default: return false; } } bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, - void* memory, zval* value TSRMLS_DC) { + void* memory, zval* value PHP_PROTO_TSRMLS_DC) { switch (type) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { @@ -95,14 +97,14 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); return false; } - if (*(zval**)memory != NULL) { + + zval* cached_zval = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (EXPECTED(cached_zval != NULL)) { +#if PHP_MAJOR_VERSION < 7 REPLACE_ZVAL_VALUE((zval**)memory, value, 1); - } else { - // Handles repeated/map string field. Memory provided by - // RepeatedField/Map is not initialized. - MAKE_STD_ZVAL(DEREF(memory, zval*)); - ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value), Z_STRLEN_P(value), - 1); +#else + zend_assign_to_variable(cached_zval, value, IS_CV); +#endif } break; } @@ -115,13 +117,18 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, zend_error(E_USER_ERROR, "Given message does not have correct class."); return false; } - if (EXPECTED(DEREF(memory, zval*) != value)) { - if (DEREF(memory, zval*) != NULL) { - zval_ptr_dtor((zval**)memory); - } - DEREF(memory, zval*) = value; - Z_ADDREF_P(value); + + zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (EXPECTED(property_ptr != value)) { + php_proto_zval_ptr_dtor(property_ptr); } + +#if PHP_MAJOR_VERSION < 7 + DEREF(memory, zval*) = value; + Z_ADDREF_P(value); +#else + ZVAL_ZVAL(property_ptr, value, 1, 0); +#endif break; } @@ -151,7 +158,59 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, return true; } -void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) { +bool native_slot_set_by_array(upb_fieldtype_t type, + const zend_class_entry* klass, void* memory, + zval* value TSRMLS_DC) { + switch (type) { + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + if (!protobuf_convert_to_string(value)) { + return false; + } + if (type == UPB_TYPE_STRING && + !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) { + zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); + return false; + } + + // Handles repeated/map string field. Memory provided by + // RepeatedField/Map is not initialized. +#if PHP_MAJOR_VERSION < 7 + MAKE_STD_ZVAL(DEREF(memory, zval*)); + PHP_PROTO_ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value), + Z_STRLEN_P(value), 1); +#else + *(zend_string**)memory = zend_string_dup(Z_STR_P(value), 0); +#endif + break; + } + case UPB_TYPE_MESSAGE: { + if (Z_TYPE_P(value) != IS_OBJECT) { + zend_error(E_USER_ERROR, "Given value is not message."); + return false; + } + if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) { + zend_error(E_USER_ERROR, "Given message does not have correct class."); + return false; + } +#if PHP_MAJOR_VERSION < 7 + if (EXPECTED(DEREF(memory, zval*) != value)) { + DEREF(memory, zval*) = value; + Z_ADDREF_P(value); + } +#else + DEREF(memory, zend_object*) = Z_OBJ_P(value); + ++GC_REFCOUNT(Z_OBJ_P(value)); +#endif + break; + } + default: + return native_slot_set(type, klass, memory, value TSRMLS_CC); + } + return true; +} + +void native_slot_init(upb_fieldtype_t type, void* memory, void* cache) { zval* tmp = NULL; switch (type) { case UPB_TYPE_FLOAT: @@ -166,7 +225,7 @@ void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: - DEREF(memory, zval**) = cache; + DEREF(memory, CACHED_VALUE*) = cache; break; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: @@ -187,38 +246,38 @@ void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) { } void native_slot_get(upb_fieldtype_t type, const void* memory, - zval** cache TSRMLS_DC) { + CACHED_VALUE* cache TSRMLS_DC) { switch (type) { -#define CASE(upb_type, php_type, c_type) \ - case UPB_TYPE_##upb_type: \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_##php_type(*cache, DEREF(memory, c_type)); \ - return; +#define CASE(upb_type, php_type, c_type) \ + case UPB_TYPE_##upb_type: \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \ + return; -CASE(FLOAT, DOUBLE, float) -CASE(DOUBLE, DOUBLE, double) -CASE(BOOL, BOOL, int8_t) -CASE(INT32, LONG, int32_t) -CASE(ENUM, LONG, uint32_t) + CASE(FLOAT, DOUBLE, float) + CASE(DOUBLE, DOUBLE, double) + CASE(BOOL, BOOL, int8_t) + CASE(INT32, LONG, int32_t) + CASE(ENUM, LONG, uint32_t) #undef CASE #if SIZEOF_LONG == 4 -#define CASE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - char buffer[MAX_LENGTH_OF_INT64]; \ - sprintf(buffer, "%lld", DEREF(memory, c_type)); \ - ZVAL_STRING(*cache, buffer, 1); \ - return; \ - } +#define CASE(upb_type, c_type) \ + case UPB_TYPE_##upb_type: { \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + char buffer[MAX_LENGTH_OF_INT64]; \ + sprintf(buffer, "%lld", DEREF(memory, c_type)); \ + PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), buffer, 1); \ + return; \ + } #else -#define CASE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_LONG(*cache, DEREF(memory, c_type)); \ - return; \ - } +#define CASE(upb_type, c_type) \ + case UPB_TYPE_##upb_type: { \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \ + return; \ + } #endif CASE(UINT64, uint64_t) CASE(INT64, int64_t) @@ -227,32 +286,34 @@ CASE(INT64, int64_t) case UPB_TYPE_UINT32: { // Prepend bit-1 for negative numbers, so that uint32 value will be // consistent on both 32-bit and 64-bit architectures. - SEPARATE_ZVAL_IF_NOT_REF(cache); + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); int value = DEREF(memory, int32_t); if (sizeof(int) == 8) { value |= (-((value >> 31) & 0x1) & 0xFFFFFFFF00000000); } - ZVAL_LONG(*cache, value); + ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), value); return; } case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { - // For optional string/bytes fields, the cache is owned by the containing - // message and should have been updated during setting/decoding. However, - // for repeated string/bytes fields, the cache is provided by zend engine - // and has not been updated. - zval* value = DEREF(memory, zval*); - if (*cache != value) { - ZVAL_STRINGL(*cache, Z_STRVAL_P(value), Z_STRLEN_P(value), 1); + // For optional string/bytes/message fields, the cache is owned by the + // containing message and should have been updated during + // setting/decoding. However, oneof accessor call this function by + // providing the return value directly, which is not the same as the cache + // value. + zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) { + PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), Z_STRVAL_P(value), + Z_STRLEN_P(value), 1); } break; } case UPB_TYPE_MESSAGE: { // Same as above for string/bytes fields. - zval* value = DEREF(memory, zval*); - if (*cache != value) { - ZVAL_ZVAL(*cache, value, 1, 0); + zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) { + ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0); } return; } @@ -261,12 +322,46 @@ CASE(INT64, int64_t) } } -void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) { +void native_slot_get_by_array(upb_fieldtype_t type, const void* memory, + CACHED_VALUE* cache TSRMLS_DC) { switch (type) { -#define CASE(upb_type, php_type) \ - case UPB_TYPE_##upb_type: \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_##php_type(*cache, 0); \ + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { +#if PHP_MAJOR_VERSION < 7 + zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) { + PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), + Z_STRVAL_P(value), Z_STRLEN_P(value), 1); + } +#else + ZVAL_NEW_STR(cache, zend_string_dup(*(zend_string**)memory, 0)); +#endif + return; + } + case UPB_TYPE_MESSAGE: { +#if PHP_MAJOR_VERSION < 7 + zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) { + ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0); + } +#else + ++GC_REFCOUNT(*(zend_object**)memory); + ZVAL_OBJ(cache, *(zend_object**)memory); +#endif + return; + } + default: + native_slot_get(type, memory, cache TSRMLS_CC); + } +} + +void native_slot_get_default(upb_fieldtype_t type, + CACHED_VALUE* cache TSRMLS_DC) { + switch (type) { +#define CASE(upb_type, php_type) \ + case UPB_TYPE_##upb_type: \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \ return; CASE(FLOAT, DOUBLE) @@ -279,19 +374,19 @@ void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) { #undef CASE #if SIZEOF_LONG == 4 -#define CASE(upb_type) \ - case UPB_TYPE_##upb_type: { \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_STRING(*cache, "0", 1); \ - return; \ - } +#define CASE(upb_type) \ + case UPB_TYPE_##upb_type: { \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), "0", 1); \ + return; \ + } #else -#define CASE(upb_type) \ - case UPB_TYPE_##upb_type: { \ - SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_LONG(*cache, 0); \ - return; \ - } +#define CASE(upb_type) \ + case UPB_TYPE_##upb_type: { \ + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ + ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \ + return; \ + } #endif CASE(UINT64) CASE(INT64) @@ -299,13 +394,13 @@ CASE(INT64) case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { - SEPARATE_ZVAL_IF_NOT_REF(cache); - ZVAL_STRINGL(*cache, "", 0, 1); + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); + PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), "", 0, 1); break; } case UPB_TYPE_MESSAGE: { - SEPARATE_ZVAL_IF_NOT_REF(cache); - ZVAL_NULL(*cache); + PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); + ZVAL_NULL(CACHED_PTR_TO_ZVAL_PTR(cache)); return; } default: @@ -359,14 +454,15 @@ const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) { return value_field; } -const zend_class_entry* field_type_class(const upb_fielddef* field TSRMLS_DC) { +const zend_class_entry* field_type_class( + const upb_fielddef* field PHP_PROTO_TSRMLS_DC) { if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { - zval* desc_php = get_def_obj(upb_fielddef_subdef(field)); - Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC); + Descriptor* desc = UNBOX_HASHTABLE_VALUE( + Descriptor, get_def_obj(upb_fielddef_subdef(field))); return desc->klass; } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { - zval* desc_php = get_def_obj(upb_fielddef_subdef(field)); - EnumDescriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC); + EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE( + EnumDescriptor, get_def_obj(upb_fielddef_subdef(field))); return desc->klass; } return NULL; @@ -501,7 +597,7 @@ void free_layout(MessageLayout* layout) { } void layout_init(MessageLayout* layout, void* storage, - zval** properties_table TSRMLS_DC) { + CACHED_VALUE* properties_table PHP_PROTO_TSRMLS_DC) { int i; upb_msg_field_iter it; for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it); @@ -510,20 +606,27 @@ void layout_init(MessageLayout* layout, void* storage, void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); int cache_index = slot_property_cache(layout, storage, field); - zval** property_ptr = &properties_table[cache_index]; + CACHED_VALUE* property_ptr = &properties_table[cache_index]; if (upb_fielddef_containingoneof(field)) { memset(memory, 0, NATIVE_SLOT_MAX_SIZE); *oneof_case = ONEOF_CASE_NONE; } else if (is_map_field(field)) { zval_ptr_dtor(property_ptr); - map_field_create_with_field(map_field_type, field, property_ptr TSRMLS_CC); - DEREF(memory, zval**) = property_ptr; +#if PHP_MAJOR_VERSION < 7 + MAKE_STD_ZVAL(*property_ptr); +#endif + map_field_create_with_field(map_field_type, field, + property_ptr PHP_PROTO_TSRMLS_CC); + DEREF(memory, CACHED_VALUE*) = property_ptr; } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { zval_ptr_dtor(property_ptr); +#if PHP_MAJOR_VERSION < 7 + MAKE_STD_ZVAL(*property_ptr); +#endif repeated_field_create_with_field(repeated_field_type, field, - property_ptr TSRMLS_CC); - DEREF(memory, zval**) = property_ptr; + property_ptr PHP_PROTO_TSRMLS_CC); + DEREF(memory, CACHED_VALUE*) = property_ptr; } else { native_slot_init(upb_fielddef_type(field), memory, property_ptr); } @@ -537,7 +640,7 @@ static void* value_memory(const upb_fielddef* field, void* memory) { case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: - memory = DEREF(memory, zval**); + memory = DEREF(memory, CACHED_VALUE*); break; default: // No operation @@ -547,7 +650,7 @@ static void* value_memory(const upb_fielddef* field, void* memory) { } zval* layout_get(MessageLayout* layout, const void* storage, - const upb_fielddef* field, zval** cache TSRMLS_DC) { + const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC) { void* memory = slot_memory(layout, storage, field); uint32_t* oneof_case = slot_oneof_case(layout, storage, field); @@ -558,13 +661,13 @@ zval* layout_get(MessageLayout* layout, const void* storage, native_slot_get(upb_fielddef_type(field), value_memory(field, memory), cache TSRMLS_CC); } - return *cache; + return CACHED_PTR_TO_ZVAL_PTR(cache); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - return *cache; + return CACHED_PTR_TO_ZVAL_PTR(cache); } else { native_slot_get(upb_fielddef_type(field), value_memory(field, memory), cache TSRMLS_CC); - return *cache; + return CACHED_PTR_TO_ZVAL_PTR(cache); } } @@ -583,8 +686,7 @@ void layout_set(MessageLayout* layout, MessageHeader* header, switch (type) { case UPB_TYPE_MESSAGE: { const upb_msgdef* msg = upb_fielddef_msgsubdef(field); - zval* desc_php = get_def_obj(msg); - Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC); + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg)); ce = desc->klass; // Intentionally fall through. } @@ -593,9 +695,9 @@ void layout_set(MessageLayout* layout, MessageHeader* header, int property_cache_index = header->descriptor->layout->fields[upb_fielddef_index(field)] .cache_index; - DEREF(memory, zval**) = + DEREF(memory, CACHED_VALUE*) = &(header->std.properties_table)[property_cache_index]; - memory = DEREF(memory, zval**); + memory = DEREF(memory, CACHED_VALUE*); break; } default: @@ -606,27 +708,130 @@ void layout_set(MessageLayout* layout, MessageHeader* header, *oneof_case = upb_fielddef_number(field); } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { // Works for both repeated and map fields - memory = DEREF(memory, zval**); - if (EXPECTED(DEREF(memory, zval*) != val)) { - zval_ptr_dtor(memory); - DEREF(memory, zval*) = val; - Z_ADDREF_P(val); + memory = DEREF(memory, void**); + zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); + + if (EXPECTED(property_ptr != val)) { +#if PHP_MAJOR_VERSION < 7 + REPLACE_ZVAL_VALUE((zval**)memory, val, 1); +#else + php_proto_zval_ptr_dtor(property_ptr); + ZVAL_ZVAL(property_ptr, val, 1, 0); +#endif } } else { upb_fieldtype_t type = upb_fielddef_type(field); zend_class_entry *ce = NULL; if (type == UPB_TYPE_MESSAGE) { const upb_msgdef* msg = upb_fielddef_msgsubdef(field); - zval* desc_php = get_def_obj(msg); - Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC); + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg)); ce = desc->klass; } native_slot_set(type, ce, value_memory(field, memory), val TSRMLS_CC); } } +static native_slot_merge(const upb_fielddef* field, const void* from_memory, + void* to_memory PHP_PROTO_TSRMLS_DC) { + upb_fieldtype_t type = upb_fielddef_type(field); + zend_class_entry* ce = NULL; + if (!native_slot_is_default(type, from_memory)) { + switch (type) { +#define CASE_TYPE(upb_type, c_type) \ + case UPB_TYPE_##upb_type: { \ + DEREF(to_memory, c_type) = DEREF(from_memory, c_type); \ + break; \ + } + CASE_TYPE(INT32, int32_t) + CASE_TYPE(UINT32, uint32_t) + CASE_TYPE(ENUM, int32_t) + CASE_TYPE(INT64, int64_t) + CASE_TYPE(UINT64, uint64_t) + CASE_TYPE(FLOAT, float) + CASE_TYPE(DOUBLE, double) + CASE_TYPE(BOOL, int8_t) + +#undef CASE_TYPE + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + native_slot_set(type, NULL, value_memory(field, to_memory), + CACHED_PTR_TO_ZVAL_PTR(DEREF( + from_memory, CACHED_VALUE*)) PHP_PROTO_TSRMLS_CC); + break; + case UPB_TYPE_MESSAGE: { + const upb_msgdef* msg = upb_fielddef_msgsubdef(field); + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg)); + ce = desc->klass; + if (native_slot_is_default(type, to_memory)) { +#if PHP_MAJOR_VERSION < 7 + SEPARATE_ZVAL_IF_NOT_REF((zval**)value_memory(field, to_memory)); +#endif + CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR( + CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)), ce); + MessageHeader* submsg = + UNBOX(MessageHeader, + CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*))); + custom_data_init(ce, submsg PHP_PROTO_TSRMLS_CC); + } + + MessageHeader* sub_from = + UNBOX(MessageHeader, + CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*))); + MessageHeader* sub_to = + UNBOX(MessageHeader, + CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*))); + + layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC); + break; + } + } + } +} + +static native_slot_merge_by_array(const upb_fielddef* field, const void* from_memory, + void* to_memory PHP_PROTO_TSRMLS_DC) { + upb_fieldtype_t type = upb_fielddef_type(field); + switch (type) { + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { +#if PHP_MAJOR_VERSION < 7 + MAKE_STD_ZVAL(DEREF(to_memory, zval*)); + PHP_PROTO_ZVAL_STRINGL(DEREF(to_memory, zval*), + Z_STRVAL_P(*(zval**)from_memory), + Z_STRLEN_P(*(zval**)from_memory), 1); +#else + DEREF(to_memory, zend_string*) = + zend_string_dup(*(zend_string**)from_memory, 0); +#endif + break; + } + case UPB_TYPE_MESSAGE: { + const upb_msgdef* msg = upb_fielddef_msgsubdef(field); + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg)); + zend_class_entry* ce = desc->klass; +#if PHP_MAJOR_VERSION < 7 + MAKE_STD_ZVAL(DEREF(to_memory, zval*)); + CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(DEREF(to_memory, zval*), ce); +#else + DEREF(to_memory, zend_object*) = ce->create_object(ce TSRMLS_CC); +#endif + MessageHeader* sub_from = UNBOX_HASHTABLE_VALUE( + MessageHeader, DEREF(from_memory, PHP_PROTO_HASHTABLE_VALUE)); + MessageHeader* sub_to = UNBOX_HASHTABLE_VALUE( + MessageHeader, DEREF(to_memory, PHP_PROTO_HASHTABLE_VALUE)); + custom_data_init(ce, sub_to PHP_PROTO_TSRMLS_CC); + + layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC); + break; + } + default: + native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC); + break; + } +} + void layout_merge(MessageLayout* layout, MessageHeader* from, - MessageHeader* to TSRMLS_DC) { + MessageHeader* to PHP_PROTO_TSRMLS_DC) { int i, j; upb_msg_field_iter it; @@ -639,11 +844,10 @@ void layout_merge(MessageLayout* layout, MessageHeader* from, if (upb_fielddef_containingoneof(field)) { uint32_t oneof_case_offset = - layout->fields[upb_fielddef_index(field)].case_offset + - sizeof(MessageHeader); + layout->fields[upb_fielddef_index(field)].case_offset; // For a oneof, check that this field is actually present -- skip all the // below if not. - if (DEREF(((uint8_t*)from + oneof_case_offset), uint32_t) != + if (DEREF((message_data(from) + oneof_case_offset), uint32_t) != upb_fielddef_number(field)) { continue; } @@ -658,7 +862,7 @@ void layout_merge(MessageLayout* layout, MessageHeader* from, case UPB_TYPE_BYTES: { int property_cache_index = layout->fields[upb_fielddef_index(field)].cache_index; - DEREF(to_memory, zval**) = + DEREF(to_memory, CACHED_VALUE*) = &(to->std.properties_table)[property_cache_index]; break; } @@ -676,141 +880,57 @@ void layout_merge(MessageLayout* layout, MessageHeader* from, int size, key_length, value_length; MapIter map_it; - zval* to_map_php = *DEREF(to_memory, zval**); - zval* from_map_php = *DEREF(from_memory, zval**); - Map* to_map = zend_object_store_get_object(to_map_php TSRMLS_CC); - Map* from_map = zend_object_store_get_object(from_map_php TSRMLS_CC); + zval* to_map_php = + CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)); + zval* from_map_php = + CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*)); + Map* to_map = UNBOX(Map, to_map_php); + Map* from_map = UNBOX(Map, from_map_php); size = upb_strtable_count(&from_map->table); if (size == 0) continue; + const upb_msgdef *mapentry_def = upb_fielddef_msgsubdef(field); + const upb_fielddef *value_field = upb_msgdef_itof(mapentry_def, 2); + for (map_begin(from_map_php, &map_it TSRMLS_CC); !map_done(&map_it); map_next(&map_it)) { const char* key = map_iter_key(&map_it, &key_length); - upb_value value = map_iter_value(&map_it, &value_length); - void* mem = upb_value_memory(&value); - switch (to_map->value_type) { - case UPB_TYPE_MESSAGE: { - zval* new_message; - message_create_with_type(to_map->msg_ce, &new_message TSRMLS_CC); - Z_ADDREF_P(new_message); - - zval* subdesc_php = get_ce_obj(to_map->msg_ce); - Descriptor* subdesc = - zend_object_store_get_object(subdesc_php TSRMLS_CC); - MessageHeader* sub_from = - (MessageHeader*)zend_object_store_get_object(DEREF(mem, zval*) - TSRMLS_CC); - MessageHeader* sub_to = - (MessageHeader*)zend_object_store_get_object( - new_message TSRMLS_CC); - layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC); - DEREF(mem, zval*) = new_message; - break; - } - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: - Z_ADDREF_PP((zval**)mem); - break; - default: - break; - } - map_index_set(to_map, key, key_length, value); + upb_value from_value = map_iter_value(&map_it, &value_length); + upb_value to_value; + void* from_mem = upb_value_memory(&from_value); + void* to_mem = upb_value_memory(&to_value); + memset(to_mem, 0, native_slot_size(to_map->value_type)); + + native_slot_merge_by_array(value_field, from_mem, + to_mem PHP_PROTO_TSRMLS_CC); + + map_index_set(to_map, key, key_length, to_value); } } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - zval* to_array_php = *DEREF(to_memory, zval**); - zval* from_array_php = *DEREF(from_memory, zval**); - RepeatedField* to_array = - zend_object_store_get_object(to_array_php TSRMLS_CC); - RepeatedField* from_array = - zend_object_store_get_object(from_array_php TSRMLS_CC); - - int size = zend_hash_num_elements(HASH_OF(from_array->array)); + zval* to_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)); + zval* from_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*)); + RepeatedField* to_array = UNBOX(RepeatedField, to_array_php); + RepeatedField* from_array = UNBOX(RepeatedField, from_array_php); + + int size = zend_hash_num_elements(PHP_PROTO_HASH_OF(from_array->array)); if (size > 0) { for (j = 0; j < size; j++) { - void* memory = NULL; - zend_hash_index_find(HASH_OF(from_array->array), j, (void**)&memory); - switch (to_array->type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - zval* str; - MAKE_STD_ZVAL(str); - ZVAL_STRINGL(str, Z_STRVAL_PP((zval**)memory), - Z_STRLEN_PP((zval**)memory), 1); - memory = &str; - break; - } - case UPB_TYPE_MESSAGE: { - zval* new_message; - message_create_with_type(from_array->msg_ce, &new_message TSRMLS_CC); - Z_ADDREF_P(new_message); - - zval* subdesc_php = get_ce_obj(from_array->msg_ce); - Descriptor* subdesc = - zend_object_store_get_object(subdesc_php TSRMLS_CC); - MessageHeader* sub_from = - (MessageHeader*)zend_object_store_get_object( - DEREF(memory, zval*) TSRMLS_CC); - MessageHeader* sub_to = - (MessageHeader*)zend_object_store_get_object( - new_message TSRMLS_CC); - layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC); - - memory = &new_message; - } - default: - break; - } - repeated_field_push_native(to_array, memory TSRMLS_CC); + void* from_memory = NULL; + void* to_memory = + ALLOC_N(char, native_slot_size(upb_fielddef_type(field))); + memset(to_memory, 0, native_slot_size(upb_fielddef_type(field))); + php_proto_zend_hash_index_find(PHP_PROTO_HASH_OF(from_array->array), + j, (void**)&from_memory); + native_slot_merge_by_array(field, from_memory, + to_memory PHP_PROTO_TSRMLS_CC); + repeated_field_push_native(to_array, to_memory); + FREE(to_memory); } } } else { - upb_fieldtype_t type = upb_fielddef_type(field); - zend_class_entry *ce = NULL; - if (!native_slot_is_default(type, from_memory)) { - switch (type) { -#define CASE_TYPE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - DEREF(to_memory, c_type) = DEREF(from_memory, c_type); \ - break; \ - } - CASE_TYPE(INT32, int32_t) - CASE_TYPE(UINT32, uint32_t) - CASE_TYPE(ENUM, int32_t) - CASE_TYPE(INT64, int64_t) - CASE_TYPE(UINT64, uint64_t) - CASE_TYPE(FLOAT, float) - CASE_TYPE(DOUBLE, double) - CASE_TYPE(BOOL, int8_t) - -#undef CASE_TYPE - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - native_slot_set(type, NULL, value_memory(field, to_memory), - *DEREF(from_memory, zval**) TSRMLS_CC); - break; - case UPB_TYPE_MESSAGE: { - const upb_msgdef* msg = upb_fielddef_msgsubdef(field); - zval* desc_php = get_def_obj(msg); - Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC); - ce = desc->klass; - if (native_slot_is_default(type, to_memory)) { - zval* new_message = NULL; - message_create_with_type(ce, &new_message TSRMLS_CC); - native_slot_set(type, ce, value_memory(field, to_memory), - new_message TSRMLS_CC); - } - MessageHeader* sub_from = - (MessageHeader*)zend_object_store_get_object( - *DEREF(from_memory, zval**) TSRMLS_CC); - MessageHeader* sub_to = - (MessageHeader*)zend_object_store_get_object( - *DEREF(to_memory, zval**) TSRMLS_CC); - layout_merge(desc->layout, sub_from, sub_to TSRMLS_CC); - } - } - } + native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC); } } } |