Merge pull request #6824 from jskeet/fix-extensions
Fix reflection access when using old generated code
diff --git a/.gitignore b/.gitignore
index dbbec53..4e909ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,6 +139,8 @@
php/tests/generated/
php/tests/old_protoc
php/tests/protobuf/
+php/tests/core
+php/tests/vgcore*
php/ext/google/protobuf/.libs/
php/ext/google/protobuf/Makefile.fragments
php/ext/google/protobuf/Makefile.global
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 8e5e680..0ae5435 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -40,8 +40,6 @@
endif (BUILD_SHARED_LIBS)
option(protobuf_BUILD_SHARED_LIBS "Build Shared Libraries" ${protobuf_BUILD_SHARED_LIBS_DEFAULT})
include(CMakeDependentOption)
-cmake_dependent_option(protobuf_MSVC_STATIC_RUNTIME "Link static runtime libraries" ON
- "NOT protobuf_BUILD_SHARED_LIBS" OFF)
set(protobuf_WITH_ZLIB_DEFAULT ON)
option(protobuf_WITH_ZLIB "Build with zlib support" ${protobuf_WITH_ZLIB_DEFAULT})
set(protobuf_DEBUG_POSTFIX "d"
@@ -155,22 +153,22 @@
set(protobuf_SHARED_OR_STATIC "SHARED")
else (protobuf_BUILD_SHARED_LIBS)
set(protobuf_SHARED_OR_STATIC "STATIC")
- # In case we are building static libraries, link also the runtime library statically
- # so that MSVCR*.DLL is not required at runtime.
- # https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
- # This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
- # http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
- if (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
- endif (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
endif (protobuf_BUILD_SHARED_LIBS)
+# In case we are linking the runtime library statically so that MSVCR*.DLL is not required at runtime.
+# https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
+# This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
+# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
+if (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+ foreach(flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ if(${flag_var} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif(${flag_var} MATCHES "/MD")
+ endforeach(flag_var)
+endif (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+
if (MSVC)
# Build with multiple processes
add_definitions(/MP)
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs
index 02fe778..d65a6f2 100644
--- a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs
@@ -41,6 +41,7 @@
using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types;
using static UnitTest.Issues.TestProtos.UnittestCustomOptionsProto3Extensions;
using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types;
+using Google.Protobuf.TestProtos;
#pragma warning disable CS0618
@@ -177,6 +178,21 @@
AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, Fieldopt, AggregateMessage.Descriptor.Fields["fieldname"].GetOption);
}
+ [Test]
+ public void NoOptions()
+ {
+ var fileDescriptor = UnittestProto3Reflection.Descriptor;
+ var messageDescriptor = TestAllTypes.Descriptor;
+ Assert.NotNull(fileDescriptor.CustomOptions);
+ Assert.NotNull(messageDescriptor.CustomOptions);
+ Assert.NotNull(messageDescriptor.Fields[1].CustomOptions);
+ Assert.NotNull(fileDescriptor.Services[0].CustomOptions);
+ Assert.NotNull(fileDescriptor.Services[0].Methods[0].CustomOptions);
+ Assert.NotNull(fileDescriptor.EnumTypes[0].CustomOptions);
+ Assert.NotNull(fileDescriptor.EnumTypes[0].Values[0].CustomOptions);
+ Assert.NotNull(TestAllTypes.Descriptor.Oneofs[0].CustomOptions);
+ }
+
private void AssertOption<T, D>(T expected, OptionFetcher<T> fetcher, Extension<D, T> extension, Func<Extension<D, T>, T> descriptorOptionFetcher) where D : IExtendableMessage<D>
{
T customOptionsValue;
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
index 33be961..264a88a 100644
--- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
@@ -129,7 +129,7 @@
/// The (possibly empty) set of custom options for this enum.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value enum option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
index a476ef1..3933820 100644
--- a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
@@ -74,7 +74,7 @@
/// The (possibly empty) set of custom options for this enum value.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value enum value option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
index a81bc9c..ddd671a 100644
--- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -299,7 +299,7 @@
/// The (possibly empty) set of custom options for this field.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value field option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index 79ba13b..388a40b 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -547,7 +547,7 @@
/// The (possibly empty) set of custom options for this file.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value file option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
index 510c079..eda1965 100644
--- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -264,7 +264,7 @@
/// The (possibly empty) set of custom options for this message.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value message option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
index 13d2396..92250ba 100644
--- a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
@@ -74,7 +74,7 @@
/// The (possibly empty) set of custom options for this method.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value method option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
index 655c07e..1e30b92 100644
--- a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
@@ -106,7 +106,7 @@
/// The (possibly empty) set of custom options for this oneof.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value oneof option for this descriptor
diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
index 120c6c6..ba310ad 100644
--- a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
@@ -95,7 +95,7 @@
/// The (possibly empty) set of custom options for this service.
/// </summary>
[Obsolete("CustomOptions are obsolete. Use GetOption")]
- public CustomOptions CustomOptions => new CustomOptions(Proto.Options._extensions?.ValuesByNumber);
+ public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
/// <summary>
/// Gets a single value service option for this descriptor
diff --git a/docs/options.md b/docs/options.md
index 7149b21..22a8bc9 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -212,3 +212,7 @@
1. Dart port of protocol buffers
* Website https://github.com/dart-lang/protobuf
* Extensions: 1073
+
+1. Ocaml-protoc-plugin
+ * Website: https://github.com/issuu/ocaml-protoc-plugin
+ * Extensions: 1074
diff --git a/java/README.md b/java/README.md
index ccd2c97..a109494 100644
--- a/java/README.md
+++ b/java/README.md
@@ -23,7 +23,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
- <version>3.9.2</version>
+ <version>3.10.0</version>
</dependency>
```
@@ -37,7 +37,7 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
- <version>3.9.2</version>
+ <version>3.10.0</version>
</dependency>
```
@@ -45,7 +45,7 @@
If you are using Gradle, add the following to your `build.gradle` file's dependencies:
```
- compile 'com.google.protobuf:protobuf-java:3.9.2'
+ compile 'com.google.protobuf:protobuf-java:3.10.0'
```
Again, be sure to check that the version number maches (or is newer than) the version number of protoc that you are using.
diff --git a/java/util/pom.xml b/java/util/pom.xml
index f0777b9..54a3581 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -25,7 +25,7 @@
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
- <version>2.3.2</version>
+ <version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -35,7 +35,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>2.8.5</version>
+ <version>2.8.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index e69bef4..b52bdf6 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -259,6 +259,19 @@
}
}
+void repeated_field_ensure_created(
+ const upb_fielddef *field,
+ CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
+ if (ZVAL_IS_NULL(CACHED_PTR_TO_ZVAL_PTR(repeated_field))) {
+ zval_ptr_dtor(repeated_field);
+#if PHP_MAJOR_VERSION < 7
+ MAKE_STD_ZVAL(CACHED_PTR_TO_ZVAL_PTR(repeated_field));
+#endif
+ repeated_field_create_with_field(repeated_field_type, field,
+ repeated_field PHP_PROTO_TSRMLS_CC);
+ }
+}
+
void repeated_field_create_with_field(
zend_class_entry *ce, const upb_fielddef *field,
CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c
index 166fb91..39304a5 100644
--- a/php/ext/google/protobuf/encode_decode.c
+++ b/php/ext/google/protobuf/encode_decode.c
@@ -139,6 +139,15 @@
return hd_ofs;
}
+static const void* newhandlerfielddata(
+ upb_handlers* h, const upb_fielddef* field) {
+ const void** hd_field = malloc(sizeof(void*));
+ PHP_PROTO_ASSERT(hd_field != NULL);
+ *hd_field = field;
+ upb_handlers_addcleanup(h, hd_field, free);
+ return hd_field;
+}
+
typedef struct {
void* closure;
stringsink sink;
@@ -163,16 +172,18 @@
}
typedef struct {
+ const upb_fielddef *fd;
size_t ofs;
const upb_msgdef *md;
} submsg_handlerdata_t;
-// Creates a handlerdata that contains offset and submessage type information.
+// Creates a handlerdata that contains field and submessage type information.
static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
const upb_fielddef* f) {
submsg_handlerdata_t* hd =
(submsg_handlerdata_t*)malloc(sizeof(submsg_handlerdata_t));
PHP_PROTO_ASSERT(hd != NULL);
+ hd->fd = f;
hd->ofs = ofs;
hd->md = upb_fielddef_msgsubdef(f);
upb_handlers_addcleanup(h, hd, free);
@@ -221,8 +232,11 @@
// this field (such an instance always exists even in an empty message).
static void *startseq_handler(void* closure, const void* hd) {
MessageHeader* msg = closure;
- const size_t *ofs = hd;
- return CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
+ const upb_fielddef** field = (const upb_fielddef**) hd;
+ CACHED_VALUE* cache = find_zval_property(msg, *field);
+ TSRMLS_FETCH();
+ repeated_field_ensure_created(*field, cache PHP_PROTO_TSRMLS_CC);
+ return CACHED_PTR_TO_ZVAL_PTR(cache);
}
// Handlers that append primitive values to a repeated field.
@@ -322,15 +336,6 @@
}
#endif
#if PHP_MAJOR_VERSION < 7
-static void *empty_php_string2(zval** value_ptr) {
- SEPARATE_ZVAL_IF_NOT_REF(value_ptr);
- if (Z_TYPE_PP(value_ptr) == IS_STRING &&
- !IS_INTERNED(Z_STRVAL_PP(value_ptr))) {
- FREE(Z_STRVAL_PP(value_ptr));
- }
- ZVAL_EMPTY_STRING(*value_ptr);
- return (void*)(*value_ptr);
-}
static void new_php_string(zval** value_ptr, const char* str, size_t len) {
SEPARATE_ZVAL_IF_NOT_REF(value_ptr);
if (Z_TYPE_PP(value_ptr) == IS_STRING &&
@@ -340,13 +345,6 @@
ZVAL_STRINGL(*value_ptr, str, len, 1);
}
#else
-static void *empty_php_string2(zval* value_ptr) {
- if (Z_TYPE_P(value_ptr) == IS_STRING) {
- zend_string_release(Z_STR_P(value_ptr));
- }
- ZVAL_EMPTY_STRING(value_ptr);
- return value_ptr;
-}
static void new_php_string(zval* value_ptr, const char* str, size_t len) {
if (Z_TYPE_P(value_ptr) == IS_STRING) {
zend_string_release(Z_STR_P(value_ptr));
@@ -372,6 +370,21 @@
static bool str_end_handler(void *closure, const void *hd) {
stringfields_parseframe_t* frame = closure;
+ const upb_fielddef **field = (const upb_fielddef **) hd;
+ MessageHeader* msg = (MessageHeader*)frame->closure;
+
+ CACHED_VALUE* cached = find_zval_property(msg, *field);
+
+ new_php_string(cached, frame->sink.ptr, frame->sink.len);
+
+ stringsink_uninit(&frame->sink);
+ free(frame);
+
+ return true;
+}
+
+static bool map_str_end_handler(void *closure, const void *hd) {
+ stringfields_parseframe_t* frame = closure;
const size_t *ofs = hd;
MessageHeader* msg = (MessageHeader*)frame->closure;
@@ -430,26 +443,60 @@
zval* submsg_php;
MessageHeader* submsg;
- if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs,
- CACHED_VALUE*))) == IS_NULL) {
+ CACHED_VALUE* cached = find_zval_property(msg, submsgdata->fd);
+
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) {
#if PHP_MAJOR_VERSION < 7
zval val;
ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
MessageHeader* intern = UNBOX(MessageHeader, &val);
custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
- REPLACE_ZVAL_VALUE(DEREF(message_data(msg), submsgdata->ofs, zval**),
- &val, 1);
+ REPLACE_ZVAL_VALUE(cached, &val, 1);
zval_dtor(&val);
#else
zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
- ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj);
+ ZVAL_OBJ(cached, obj);
MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj);
custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
#endif
}
- submsg_php = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*));
+ submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached);
+
+ submsg = UNBOX(MessageHeader, submsg_php);
+ return submsg;
+}
+
+static void *map_submsg_handler(void *closure, const void *hd) {
+ MessageHeader* msg = closure;
+ const submsg_handlerdata_t* submsgdata = hd;
+ TSRMLS_FETCH();
+ Descriptor* subdesc =
+ UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
+ zend_class_entry* subklass = subdesc->klass;
+ zval* submsg_php;
+ MessageHeader* submsg;
+
+ CACHED_VALUE* cached =
+ DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*);
+
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) {
+#if PHP_MAJOR_VERSION < 7
+ zval val;
+ ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
+ MessageHeader* intern = UNBOX(MessageHeader, &val);
+ custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
+ REPLACE_ZVAL_VALUE(cached, &val, 1);
+ zval_dtor(&val);
+#else
+ zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
+ ZVAL_OBJ(cached, obj);
+ MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj);
+ custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
+#endif
+ }
+
+ submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached);
submsg = UNBOX(MessageHeader, submsg_php);
return submsg;
@@ -457,7 +504,7 @@
// Handler data for startmap/endmap handlers.
typedef struct {
- size_t ofs;
+ const upb_fielddef* fd;
const upb_msgdef* value_md;
upb_fieldtype_t key_field_type;
upb_fieldtype_t value_field_type;
@@ -612,9 +659,10 @@
static void *startmapentry_handler(void *closure, const void *hd) {
MessageHeader* msg = closure;
const map_handlerdata_t* mapdata = hd;
+ CACHED_VALUE* cache = find_zval_property(msg, mapdata->fd);
TSRMLS_FETCH();
- zval* map = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), mapdata->ofs, CACHED_VALUE*));
+ map_field_ensure_created(mapdata->fd, cache PHP_PROTO_TSRMLS_CC);
+ zval* map = CACHED_PTR_TO_ZVAL_PTR(cache);
map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
frame->data = ALLOC(map_parse_frame_data_t);
@@ -662,7 +710,7 @@
// key/value and endmsg handlers. The reason is that there is no easy way to
// pass the handlerdata down to the sub-message handler setup.
static map_handlerdata_t* new_map_handlerdata(
- size_t ofs,
+ const upb_fielddef* field,
const upb_msgdef* mapentry_def,
Descriptor* desc) {
const upb_fielddef* key_field;
@@ -671,7 +719,7 @@
map_handlerdata_t* hd =
(map_handlerdata_t*)malloc(sizeof(map_handlerdata_t));
PHP_PROTO_ASSERT(hd != NULL);
- hd->ofs = ofs;
+ hd->fd = field;
key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
PHP_PROTO_ASSERT(key_field != NULL);
hd->key_field_type = upb_fielddef_type(key_field);
@@ -844,7 +892,7 @@
const upb_fielddef *f,
size_t offset) {
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newhandlerdata(h, offset);
+ attr.handler_data = newhandlerfielddata(h, f);
upb_handlers_setstartseq(h, f, startseq_handler, &attr);
switch (upb_fielddef_type(f)) {
@@ -884,7 +932,7 @@
// Set up handlers for a singular field.
static void add_handlers_for_singular_field(upb_handlers *h,
const upb_fielddef *f,
- size_t offset) {
+ size_t offset, bool is_map) {
switch (upb_fielddef_type(f)) {
#define SET_HANDLER(utype, ltype) \
case utype: { \
@@ -908,16 +956,29 @@
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES: {
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newhandlerdata(h, offset);
+ if (is_map) {
+ attr.handler_data = newhandlerdata(h, offset);
+ } else {
+ attr.handler_data = newhandlerfielddata(h, f);
+ }
upb_handlers_setstartstr(h, f, str_handler, &attr);
upb_handlers_setstring(h, f, stringdata_handler, &attr);
- upb_handlers_setendstr(h, f, str_end_handler, &attr);
+ if (is_map) {
+ upb_handlers_setendstr(h, f, map_str_end_handler, &attr);
+ } else {
+ upb_handlers_setendstr(h, f, str_end_handler, &attr);
+ }
break;
}
case UPB_TYPE_MESSAGE: {
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
- attr.handler_data = newsubmsghandlerdata(h, offset, f);
- upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+ if (is_map) {
+ attr.handler_data = newsubmsghandlerdata(h, offset, f);
+ upb_handlers_setstartsubmsg(h, f, map_submsg_handler, &attr);
+ } else {
+ attr.handler_data = newsubmsghandlerdata(h, 0, f);
+ upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+ }
break;
}
}
@@ -929,7 +990,7 @@
size_t offset,
Descriptor* desc) {
const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
- map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
+ map_handlerdata_t* hd = new_map_handlerdata(fielddef, map_msgdef, desc);
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
upb_handlers_addcleanup(h, hd, free);
@@ -951,10 +1012,10 @@
add_handlers_for_singular_field(h, key_field,
offsetof(map_parse_frame_data_t,
- key_storage));
+ key_storage), true);
add_handlers_for_singular_field(h, value_field,
offsetof(map_parse_frame_data_t,
- value_storage));
+ value_storage), true);
}
// Set up handlers for a oneof field.
@@ -1063,7 +1124,7 @@
} else if (upb_fielddef_isseq(f)) {
add_handlers_for_repeated_field(h, f, offset);
} else {
- add_handlers_for_singular_field(h, f, offset);
+ add_handlers_for_singular_field(h, f, offset, false);
}
}
}
@@ -1259,16 +1320,13 @@
const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE);
const upb_fielddef* value_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_VALUE);
- uint32_t type_url_offset;
zval* type_url_php_str;
const upb_msgdef *payload_type = NULL;
upb_sink_startmsg(sink);
/* Handle type url */
- type_url_offset = desc->layout->fields[upb_fielddef_index(type_field)].offset;
- type_url_php_str = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), type_url_offset, CACHED_VALUE*));
+ type_url_php_str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, type_field));
if (Z_STRLEN_P(type_url_php_str) > 0) {
putstr(type_url_php_str, type_field, sink, false);
}
@@ -1294,14 +1352,11 @@
}
{
- uint32_t value_offset;
zval* value_php_str;
const char* value_str;
size_t value_len;
- value_offset = desc->layout->fields[upb_fielddef_index(value_field)].offset;
- value_php_str = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), value_offset, CACHED_VALUE*));
+ value_php_str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, value_field));
value_str = Z_STRVAL_P(value_php_str);
value_len = Z_STRLEN_P(value_php_str);
@@ -1355,17 +1410,21 @@
upb_sink_startmsg(sink);
- array = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- intern = UNBOX(RepeatedField, array);
- ht = PHP_PROTO_HASH_OF(intern->array);
- size = zend_hash_num_elements(ht);
-
- if (size == 0) {
+ array = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (ZVAL_IS_NULL(array)) {
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
} else {
- putarray(array, f, sink, depth, true TSRMLS_CC);
+ intern = UNBOX(RepeatedField, array);
+ ht = PHP_PROTO_HASH_OF(intern->array);
+ size = zend_hash_num_elements(ht);
+
+ if (size == 0) {
+ upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+ upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+ } else {
+ putarray(array, f, sink, depth, true TSRMLS_CC);
+ }
}
upb_sink_endmsg(sink, &status);
@@ -1384,16 +1443,20 @@
upb_sink_startmsg(sink);
- map = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- intern = UNBOX(Map, map);
- size = upb_strtable_count(&intern->table);
-
- if (size == 0) {
+ map = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (ZVAL_IS_NULL(map)) {
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
} else {
- putmap(map, f, sink, depth, true TSRMLS_CC);
+ intern = UNBOX(Map, map);
+ size = upb_strtable_count(&intern->table);
+
+ if (size == 0) {
+ upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+ upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+ } else {
+ putmap(map, f, sink, depth, true TSRMLS_CC);
+ }
}
upb_sink_endmsg(sink, &status);
@@ -1455,28 +1518,24 @@
}
if (is_map_field(f)) {
- zval* map = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- if (map != NULL) {
+ zval* map = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (!ZVAL_IS_NULL(map)) {
putmap(map, f, sink, depth, is_json TSRMLS_CC);
}
} else if (upb_fielddef_isseq(f)) {
- zval* array = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- if (array != NULL) {
+ zval* array = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (!ZVAL_IS_NULL(array)) {
putarray(array, f, sink, depth, is_json TSRMLS_CC);
}
} else if (upb_fielddef_isstring(f)) {
- zval* str = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
+ zval* str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
if (containing_oneof || (is_json && is_wrapper_msg(desc->msgdef)) ||
Z_STRLEN_P(str) > 0) {
putstr(str, f, sink, is_json && is_wrapper_msg(desc->msgdef));
}
} else if (upb_fielddef_issubmsg(f)) {
- putsubmsg(CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*)),
- f, sink, depth, is_json TSRMLS_CC);
+ zval* submsg = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ putsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
} else {
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
@@ -1847,9 +1906,8 @@
value_field = map_field_value(f);
if (!upb_fielddef_issubmsg(value_field)) continue;
- zval* map_php = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- if (map_php == NULL) continue;
+ zval* map_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (ZVAL_IS_NULL(map_php)) continue;
Map* intern = UNBOX(Map, map_php);
for (map_begin(map_php, &map_it TSRMLS_CC);
@@ -1868,9 +1926,8 @@
} else if (upb_fielddef_isseq(f)) {
if (!upb_fielddef_issubmsg(f)) continue;
- zval* array_php = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
- if (array_php == NULL) continue;
+ zval* array_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
+ if (ZVAL_IS_NULL(array_php)) continue;
int size, i;
RepeatedField* intern = UNBOX(RepeatedField, array_php);
@@ -1890,8 +1947,7 @@
discard_unknown_fields(submsg);
}
} else if (upb_fielddef_issubmsg(f)) {
- zval* submsg_php = CACHED_PTR_TO_ZVAL_PTR(
- DEREF(message_data(msg), offset, CACHED_VALUE*));
+ zval* submsg_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
if (Z_TYPE_P(submsg_php) == IS_NULL) continue;
MessageHeader* submsg = UNBOX(MessageHeader, submsg_php);
discard_unknown_fields(submsg);
diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c
index 0ce1019..2764788 100644
--- a/php/ext/google/protobuf/map.c
+++ b/php/ext/google/protobuf/map.c
@@ -243,6 +243,18 @@
map_field_handlers->get_gc = map_field_get_gc;
PHP_PROTO_INIT_CLASS_END
+void map_field_ensure_created(const upb_fielddef *field,
+ CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) {
+ if (ZVAL_IS_NULL(CACHED_PTR_TO_ZVAL_PTR(map_field))) {
+ zval_ptr_dtor(map_field);
+#if PHP_MAJOR_VERSION < 7
+ MAKE_STD_ZVAL(CACHED_PTR_TO_ZVAL_PTR(map_field));
+#endif
+ map_field_create_with_field(map_field_type, field,
+ map_field PHP_PROTO_TSRMLS_CC);
+ }
+}
+
void map_field_create_with_field(const zend_class_entry *ce,
const upb_fielddef *field,
CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) {
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
index 303f5d4..03dec75 100644
--- a/php/ext/google/protobuf/message.c
+++ b/php/ext/google/protobuf/message.c
@@ -178,7 +178,7 @@
zend_get_property_info(Z_OBJCE_P(object), Z_STR_P(member), true);
#endif
return layout_get(
- self->descriptor->layout, message_data(self), field,
+ self->descriptor->layout, self, field,
OBJ_PROP(Z_OBJ_P(object), property_info->offset) TSRMLS_CC);
}
@@ -191,7 +191,7 @@
return;
}
- layout_get(self->descriptor->layout, message_data(self), field,
+ layout_get(self->descriptor->layout, self, field,
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
}
@@ -255,7 +255,6 @@
MessageHeader* intern PHP_PROTO_TSRMLS_DC) {
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(ce));
intern->data = ALLOC_N(uint8_t, desc->layout->size);
- memset(message_data(intern), 0, desc->layout->size);
// We wrap first so that everything in the message object is GC-rooted in
// case a collection happens during object creation in layout_init().
intern->descriptor = desc;
@@ -575,9 +574,9 @@
const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index);
// Unlike singular fields, oneof fields share cached property. So we cannot
- // let lay_get modify the cached property. Instead, we pass in the return
+ // let layout_get modify the cached property. Instead, we pass in the return
// value directly.
- layout_get(msg->descriptor->layout, message_data(msg), field,
+ layout_get(msg->descriptor->layout, msg, field,
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
}
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index 4abfecb..86bc5b3 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -200,7 +200,7 @@
#define CACHED_VALUE zval*
#define CACHED_TO_ZVAL_PTR(VALUE) (VALUE)
-#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (*VALUE)
+#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (*(CACHED_VALUE*)(VALUE))
#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (&VALUE)
#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (VALUE)
#define ZVAL_TO_CACHED_VALUE(VALUE) (&VALUE)
@@ -475,7 +475,7 @@
#define CACHED_VALUE zval
#define CACHED_TO_ZVAL_PTR(VALUE) (&VALUE)
-#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (VALUE)
+#define CACHED_PTR_TO_ZVAL_PTR(VALUE) ((CACHED_VALUE*)(VALUE))
#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (VALUE)
#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (*VALUE)
#define ZVAL_TO_CACHED_VALUE(VALUE) (VALUE)
@@ -935,6 +935,7 @@
struct MessageLayout {
const upb_msgdef* msgdef;
+ void* empty_template; // Can memcpy() onto a layout to clear it.
MessageField* fields;
size_t size;
};
@@ -948,7 +949,7 @@
MessageLayout* create_layout(const upb_msgdef* msgdef);
void layout_init(MessageLayout* layout, void* storage,
zend_object* object PHP_PROTO_TSRMLS_DC);
-zval* layout_get(MessageLayout* layout, const void* storage,
+zval* layout_get(MessageLayout* layout, MessageHeader* header,
const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC);
void layout_set(MessageLayout* layout, MessageHeader* header,
const upb_fielddef* field, zval* val TSRMLS_DC);
@@ -1089,6 +1090,8 @@
const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
+void map_field_ensure_created(const upb_fielddef *field,
+ CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC);
void map_field_create_with_field(const zend_class_entry* ce,
const upb_fielddef* field,
CACHED_VALUE* map_field PHP_PROTO_TSRMLS_DC);
@@ -1147,6 +1150,9 @@
long position;
PHP_PROTO_WRAP_OBJECT_END
+void repeated_field_ensure_created(
+ const upb_fielddef *field,
+ CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC);
void repeated_field_create_with_field(
zend_class_entry* ce, const upb_fielddef* field,
CACHED_VALUE* repeated_field PHP_PROTO_TSRMLS_DC);
@@ -1489,6 +1495,9 @@
#define FREE(object) efree(object)
#define PEFREE(object) pefree(object, 1)
+// Find corresponding zval property for the field.
+CACHED_VALUE* find_zval_property(MessageHeader* msg, const upb_fielddef* field);
+
// String argument.
#define STR(str) (str), strlen(str)
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c
index 1c28b1c..e6050d0 100644
--- a/php/ext/google/protobuf/storage.c
+++ b/php/ext/google/protobuf/storage.c
@@ -75,11 +75,9 @@
#undef CASE_TYPE
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
- return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
- 0;
+ return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(memory)) == 0;
case UPB_TYPE_MESSAGE:
- return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
- IS_NULL;
+ return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(memory)) == IS_NULL;
default: return false;
}
}
@@ -599,6 +597,8 @@
// Reserve space for unknown fields.
off += sizeof(void*);
+ layout->empty_template = NULL;
+
TSRMLS_FETCH();
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msgdef));
layout->fields = ALLOC_N(MessageField, nfields);
@@ -744,64 +744,35 @@
layout->size = off;
layout->msgdef = msgdef;
+ // Create the empty message template.
+ layout->empty_template = ALLOC_N(char, layout->size);
+ memset(layout->empty_template, 0, layout->size);
+
return layout;
}
void free_layout(MessageLayout* layout) {
+ FREE(layout->empty_template);
FREE(layout->fields);
FREE(layout);
}
void layout_init(MessageLayout* layout, void* storage,
zend_object* object PHP_PROTO_TSRMLS_DC) {
- int i;
- upb_msg_field_iter it;
-
- // Init unknown fields
- memset(storage, 0, sizeof(void*));
-
- for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it);
- upb_msg_field_next(&it), i++) {
- const upb_fielddef* field = upb_msg_iter_field(&it);
- 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);
- CACHED_VALUE* property_ptr = OBJ_PROP(object, 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);
-#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 PHP_PROTO_TSRMLS_CC);
- DEREF(memory, CACHED_VALUE*) = property_ptr;
- } else {
- native_slot_init(upb_fielddef_type(field), memory, property_ptr);
- }
- }
+ memcpy(storage, layout->empty_template, layout->size);
}
-// For non-singular fields, the related memory needs to point to the actual
-// zval in properties table first.
-static void* value_memory(const upb_fielddef* field, void* memory) {
- switch (upb_fielddef_type(field)) {
+// Switch memory for processing for singular fields based on field type.
+// * primitive fields: memory
+// * others (string, bytes and message): cache (the correspond zval
+// property)
+static void* value_memory(
+ upb_fieldtype_t type, void* memory, CACHED_VALUE* cache) {
+ switch (type) {
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
case UPB_TYPE_MESSAGE:
- memory = DEREF(memory, CACHED_VALUE*);
- break;
+ return cache;
default:
// No operation
break;
@@ -809,8 +780,17 @@
return memory;
}
-zval* layout_get(MessageLayout* layout, const void* storage,
+CACHED_VALUE* find_zval_property(
+ MessageHeader* header, const upb_fielddef* field) {
+ int property_cache_index =
+ header->descriptor->layout->fields[upb_fielddef_index(field)]
+ .cache_index;
+ return OBJ_PROP(&header->std, property_cache_index);
+}
+
+zval* layout_get(MessageLayout* layout, MessageHeader* header,
const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC) {
+ const void* storage = message_data(header);
void* memory = slot_memory(layout, storage, field);
uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
@@ -818,14 +798,21 @@
if (*oneof_case != upb_fielddef_number(field)) {
native_slot_get_default(upb_fielddef_type(field), cache TSRMLS_CC);
} else {
- native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
- cache TSRMLS_CC);
+ upb_fieldtype_t type = upb_fielddef_type(field);
+ CACHED_VALUE* stored_cache = find_zval_property(header, field);
+ native_slot_get(
+ type, value_memory(type, memory, stored_cache), cache TSRMLS_CC);
}
return CACHED_PTR_TO_ZVAL_PTR(cache);
+ } else if (is_map_field(field)) {
+ map_field_ensure_created(field, cache PHP_PROTO_TSRMLS_CC);
+ return CACHED_PTR_TO_ZVAL_PTR(cache);
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+ repeated_field_ensure_created(field, cache PHP_PROTO_TSRMLS_CC);
return CACHED_PTR_TO_ZVAL_PTR(cache);
} else {
- native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
+ upb_fieldtype_t type = upb_fielddef_type(field);
+ native_slot_get(type, value_memory(type, memory, cache),
cache TSRMLS_CC);
return CACHED_PTR_TO_ZVAL_PTR(cache);
}
@@ -868,8 +855,8 @@
*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, void**);
- zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+ CACHED_VALUE* cached = find_zval_property(header, field);
+ zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR(cached);
if (EXPECTED(property_ptr != val)) {
zend_class_entry *subce = NULL;
@@ -901,7 +888,7 @@
&converted_value);
}
#if PHP_MAJOR_VERSION < 7
- REPLACE_ZVAL_VALUE((zval**)memory, &converted_value, 1);
+ REPLACE_ZVAL_VALUE((zval**)cached, &converted_value, 1);
#else
php_proto_zval_ptr_dtor(property_ptr);
ZVAL_ZVAL(property_ptr, &converted_value, 1, 0);
@@ -916,12 +903,16 @@
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);
+ CACHED_VALUE* cache = find_zval_property(header, field);
+ native_slot_set(
+ type, ce, value_memory(upb_fielddef_type(field), memory, cache),
+ val TSRMLS_CC);
}
}
-static void native_slot_merge(const upb_fielddef* field, const void* from_memory,
- void* to_memory PHP_PROTO_TSRMLS_DC) {
+static void 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)) {
@@ -943,9 +934,8 @@
#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);
+ native_slot_set(type, NULL, to_memory,
+ CACHED_PTR_TO_ZVAL_PTR(from_memory) PHP_PROTO_TSRMLS_CC);
break;
case UPB_TYPE_MESSAGE: {
const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
@@ -953,22 +943,21 @@
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));
+ SEPARATE_ZVAL_IF_NOT_REF((zval**)to_memory);
#endif
CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(
- CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)), ce);
+ CACHED_PTR_TO_ZVAL_PTR(to_memory), ce);
MessageHeader* submsg =
- UNBOX(MessageHeader,
- CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
+ UNBOX(MessageHeader, CACHED_PTR_TO_ZVAL_PTR(to_memory));
custom_data_init(ce, submsg PHP_PROTO_TSRMLS_CC);
}
MessageHeader* sub_from =
UNBOX(MessageHeader,
- CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*)));
+ CACHED_PTR_TO_ZVAL_PTR(from_memory));
MessageHeader* sub_to =
UNBOX(MessageHeader,
- CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
+ CACHED_PTR_TO_ZVAL_PTR(to_memory));
layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC);
break;
@@ -1069,10 +1058,17 @@
int size, key_length, value_length;
MapIter map_it;
- 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*));
+ CACHED_VALUE* from_cache = find_zval_property(from, field);
+ CACHED_VALUE* to_cache = find_zval_property(to, field);
+
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(from_cache)) == IS_NULL) {
+ continue;
+ }
+ map_field_ensure_created(field, to_cache PHP_PROTO_TSRMLS_CC);
+
+ zval* to_map_php = CACHED_PTR_TO_ZVAL_PTR(to_cache);
+ zval* from_map_php = CACHED_PTR_TO_ZVAL_PTR(from_cache);
+
Map* to_map = UNBOX(Map, to_map_php);
Map* from_map = UNBOX(Map, from_map_php);
@@ -1098,8 +1094,16 @@
}
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
- 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*));
+ CACHED_VALUE* from_cache = find_zval_property(from, field);
+ CACHED_VALUE* to_cache = find_zval_property(to, field);
+
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(from_cache)) == IS_NULL) {
+ continue;
+ }
+ repeated_field_ensure_created(field, to_cache PHP_PROTO_TSRMLS_CC);
+
+ zval* to_array_php = CACHED_PTR_TO_ZVAL_PTR(to_cache);
+ zval* from_array_php = CACHED_PTR_TO_ZVAL_PTR(from_cache);
RepeatedField* to_array = UNBOX(RepeatedField, to_array_php);
RepeatedField* from_array = UNBOX(RepeatedField, from_array_php);
@@ -1129,7 +1133,19 @@
}
}
} else {
- native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC);
+ switch (upb_fielddef_type(field)) {
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ case UPB_TYPE_MESSAGE: {
+ CACHED_VALUE* from_cache = find_zval_property(from, field);
+ CACHED_VALUE* to_cache = find_zval_property(to, field);
+ native_slot_merge(field, from_cache, to_cache PHP_PROTO_TSRMLS_CC);
+ break;
+ }
+ default:
+ native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC);
+ break;
+ }
}
}
}
diff --git a/src/google/protobuf/stubs/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc
index 0598427..788b224 100644
--- a/src/google/protobuf/stubs/structurally_valid.cc
+++ b/src/google/protobuf/stubs/structurally_valid.cc
@@ -395,7 +395,7 @@
const uint8* isrc = reinterpret_cast<const uint8*>(str);
const uint8* src = isrc;
const uint8* srclimit = isrc + str_length;
- const uint8* srclimit8 = srclimit - 7;
+ const uint8* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
const uint8* Tbl_0 = &st->state_table[st->state0];
DoAgain:
@@ -504,7 +504,7 @@
const uint8* isrc = reinterpret_cast<const uint8*>(str);
const uint8* src = isrc;
const uint8* srclimit = isrc + str_length;
- const uint8* srclimit8 = srclimit - 7;
+ const uint8* srclimit8 = str_length < 7 ? isrc : srclimit - 7;
int n;
int rest_consumed;
int exit_reason;